Index: branches/OKBJavaConnector/ECJClient/nbproject/build-impl.xml
===================================================================
--- branches/OKBJavaConnector/ECJClient/nbproject/build-impl.xml	(revision 6151)
+++ branches/OKBJavaConnector/ECJClient/nbproject/build-impl.xml	(revision 6152)
@@ -56,5 +56,12 @@
     <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
         <available file="${manifest.file}" property="manifest.available"/>
-        <available file="${application.splash}" property="splashscreen.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
         <condition property="main.class.available">
             <and>
@@ -71,6 +78,12 @@
             </and>
         </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
         <condition property="do.mkdist">
             <and>
+                <isset property="do.archive"/>
                 <isset property="libs.CopyLibs.classpath"/>
                 <not>
@@ -85,15 +98,4 @@
             </and>
         </condition>
-        <condition property="manifest.available+main.class+mkdist.available+splashscreen.available">
-            <and>
-                <istrue value="${manifest.available+main.class+mkdist.available}"/>
-                <istrue value="${splashscreen.available}"/>
-            </and>
-        </condition>
-        <condition property="do.archive">
-            <not>
-                <istrue value="${jar.archive.disabled}"/>
-            </not>
-        </condition>
         <condition property="do.archive+manifest.available">
             <and>
@@ -102,4 +104,16 @@
             </and>
         </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
         <condition property="do.archive+manifest.available+main.class">
             <and>
@@ -108,15 +122,15 @@
             </and>
         </condition>
-        <condition property="do.archive+manifest.available+main.class+mkdist.available">
-            <and>
-                <istrue value="${manifest.available+main.class+mkdist.available}"/>
-                <istrue value="${do.archive}"/>
-            </and>
-        </condition>
-        <condition property="do.archive+manifest.available+main.class+mkdist.available+splashscreen.available">
-            <and>
-                <istrue value="${manifest.available+main.class+mkdist.available+splashscreen.available}"/>
-                <istrue value="${do.archive}"/>
-            </and>
+        <condition property="manifest.available-mkdist.available">
+            <or>
+                <istrue value="${manifest.available}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="manifest.available+main.class-mkdist.available">
+            <or>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </or>
         </condition>
         <condition property="have.tests">
@@ -174,6 +188,15 @@
             <length length="0" string="${endorsed.classpath}" when="greater"/>
         </condition>
-        <property name="javac.fork" value="false"/>
+        <condition else="false" property="jdkBug6558476">
+            <and>
+                <matches pattern="1\.[56]" string="${java.specification.version}"/>
+                <not>
+                    <os family="unix"/>
+                </not>
+            </and>
+        </condition>
+        <property name="javac.fork" value="${jdkBug6558476}"/>
         <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
         <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
     </target>
@@ -303,5 +326,7 @@
                     <files includesfile="${javac.includesfile.binary}"/>
                 </delete>
-                <delete file="${javac.includesfile.binary}"/>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
             </sequential>
         </macrodef>
@@ -313,5 +338,6 @@
             <attribute default="**" name="testincludes"/>
             <sequential>
-                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${build.dir}">
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
                     <batchtest todir="${build.test.results.dir}">
                         <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
@@ -329,8 +355,53 @@
                     <formatter type="xml"/>
                     <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-ea"/>
                     <jvmarg line="${run.jvmargs}"/>
                 </junit>
             </sequential>
         </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" name="profile-init"/>
+    <target name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
     </target>
     <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
@@ -428,4 +499,5 @@
     <target name="-init-macrodef-copylibs">
         <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
             <element name="customize" optional="true"/>
             <sequential>
@@ -443,5 +515,5 @@
                 </pathconvert>
                 <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
-                <copylibs compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
                     <fileset dir="${build.classes.dir}"/>
                     <manifest>
@@ -600,8 +672,8 @@
         <!-- You can override this target in the ../build.xml file. -->
     </target>
-    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available">
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
         <j2seproject1:jar/>
     </target>
-    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
         <j2seproject1:jar manifest="${manifest.file}"/>
     </target>
@@ -612,5 +684,5 @@
             </j2seproject1:manifest>
         </j2seproject1:jar>
-        <echo>To run this application from the command line without Ant, try:</echo>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
         <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
         <property location="${dist.jar}" name="dist.jar.resolved"/>
@@ -619,35 +691,44 @@
             <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
         </pathconvert>
-        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
-    </target>
-    <target depends="init,compile,-pre-pre-jar,-pre-jar,-init-macrodef-copylibs" if="do.archive+manifest.available+main.class+mkdist.available+splashscreen.available" name="-do-jar-with-libraries-and-splashscreen">
+        <echo level="info">java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
         <basename file="${application.splash}" property="splashscreen.basename"/>
         <mkdir dir="${build.classes.dir}/META-INF"/>
         <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
-        <j2seproject3:copylibs>
-            <customize>
-                <attribute name="Main-Class" value="${main.class}"/>
-                <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
-            </customize>
-        </j2seproject3:copylibs>
-        <echo>To run this application from the command line without Ant, try:</echo>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
         <property location="${dist.jar}" name="dist.jar.resolved"/>
-        <echo>java -jar "${dist.jar.resolved}"</echo>
-    </target>
-    <target depends="init,compile,-pre-pre-jar,-pre-jar,-init-macrodef-copylibs" if="do.archive+manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries" unless="splashscreen.available">
-        <j2seproject3:copylibs>
-            <customize>
-                <attribute name="Main-Class" value="${main.class}"/>
-            </customize>
-        </j2seproject3:copylibs>
-        <echo>To run this application from the command line without Ant, try:</echo>
-        <property location="${dist.jar}" name="dist.jar.resolved"/>
-        <echo>java -jar "${dist.jar.resolved}"</echo>
-    </target>
+        <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
     <target name="-post-jar">
         <!-- Empty placeholder for easier customization. -->
         <!-- You can override this target in the ../build.xml file. -->
     </target>
-    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries-and-splashscreen,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
     <!--
                 =================
@@ -714,4 +795,70 @@
     </target>
     <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="netbeans.home" name="profile">
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="netbeans.home" name="profile-single">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <!--
+                =========================
+                APPLET PROFILING  SECTION
+                =========================
+            -->
+    <target depends="profile-init,compile-single" if="netbeans.home" name="profile-applet">
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <!--
+                =========================
+                TESTS PROFILING  SECTION
+                =========================
+            -->
+    <target depends="profile-init,compile-test-single" if="netbeans.home" name="profile-test-single">
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
     <!--
                 ===============
@@ -760,5 +907,5 @@
         <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
     </target>
-    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
         <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
         <copy todir="${build.test.classes.dir}">
@@ -775,5 +922,5 @@
         <!-- You can override this target in the ../build.xml file. -->
     </target>
-    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
         <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
         <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
Index: branches/OKBJavaConnector/ECJClient/nbproject/genfiles.properties
===================================================================
--- branches/OKBJavaConnector/ECJClient/nbproject/genfiles.properties	(revision 6151)
+++ branches/OKBJavaConnector/ECJClient/nbproject/genfiles.properties	(revision 6152)
@@ -5,4 +5,4 @@
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
 nbproject/build-impl.xml.data.CRC32=66572d14
-nbproject/build-impl.xml.script.CRC32=e6589168
-nbproject/build-impl.xml.stylesheet.CRC32=229523de@1.38.3.45
+nbproject/build-impl.xml.script.CRC32=6072b748
+nbproject/build-impl.xml.stylesheet.CRC32=0c01fd8e@1.43.1.45
Index: branches/OKBJavaConnector/ECJClient/nbproject/project.properties
===================================================================
--- branches/OKBJavaConnector/ECJClient/nbproject/project.properties	(revision 6151)
+++ branches/OKBJavaConnector/ECJClient/nbproject/project.properties	(revision 6152)
@@ -27,4 +27,12 @@
 endorsed.classpath=
 excludes=
+file.reference.gnujaxp.jar=libs\\gnujaxp.jar
+file.reference.iText-2.1.5.jar=libs\\iText-2.1.5.jar
+file.reference.jcommon-1.0.16.jar=libs\\jcommon-1.0.16.jar
+file.reference.jfreechart-1.0.13-experimental.jar=libs\\jfreechart-1.0.13-experimental.jar
+file.reference.jfreechart-1.0.13-swt.jar=libs\\jfreechart-1.0.13-swt.jar
+file.reference.jfreechart-1.0.13.jar=libs\\jfreechart-1.0.13.jar
+file.reference.junit.jar=libs\\junit.jar
+file.reference.swtgraphics2d.jar=libs\\swtgraphics2d.jar
 includes=**
 jar.compress=false
@@ -34,5 +42,13 @@
     ${reference.QueryService.jar}:\
     ${reference.RunCreationService.jar}:\
-    ${libs.metro.classpath}
+    ${libs.metro.classpath}:\
+    ${file.reference.gnujaxp.jar}:\
+    ${file.reference.iText-2.1.5.jar}:\
+    ${file.reference.jcommon-1.0.16.jar}:\
+    ${file.reference.jfreechart-1.0.13-experimental.jar}:\
+    ${file.reference.jfreechart-1.0.13-swt.jar}:\
+    ${file.reference.jfreechart-1.0.13.jar}:\
+    ${file.reference.junit.jar}:\
+    ${file.reference.swtgraphics2d.jar}
 # Space-separated list of extra javac options
 javac.compilerargs=
@@ -60,5 +76,5 @@
 javadoc.version=false
 javadoc.windowtitle=
-main.class=
+main.class=ec.display.Console
 manifest.file=manifest.mf
 meta.inf.dir=${src.dir}/META-INF
Index: branches/OKBJavaConnector/ECJClient/src/com/heuristiclab/okb/ecj/OKBStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/com/heuristiclab/okb/ecj/OKBStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/com/heuristiclab/okb/ecj/OKBStatistics.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.heuristiclab.okb.ecj;
+
+import com.heuristiclab.okb.service.administration.AdministrationServiceUtil;
+import com.heurisitclab.okb.service.runcreation.Algorithm;
+import com.heurisitclab.okb.service.runcreation.RunCreationUtil;
+import com.heuristiclab.okb.service.administration.Platform;
+
+
+import ec.EvolutionState;
+import ec.Statistics;
+import ec.util.Parameter;
+import ec.util.ParameterDatabase;
+
+/**
+ *
+ * @author fab
+ */
+public class OKBStatistics extends Statistics{
+
+    public static final String ECJ_PLATFORM_NAME = "Unknown";
+    private Platform ecjPlatform;
+    private Algorithm algorithm;
+
+
+    @Override
+    public void setup(EvolutionState state, Parameter base) {
+        super.setup(state, base);
+    
+        
+
+    }
+
+
+
+    @Override
+    public void postInitializationStatistics(EvolutionState state) {
+        super.postInitializationStatistics(state);
+
+            ecjPlatform = AdministrationServiceUtil.getPlattform(ECJ_PLATFORM_NAME);
+        algorithm = RunCreationUtil.getAlgorithm(state.evaluator.getClass().getName(), ecjPlatform.getName());
+        Object o = state.parameters;
+        while(state.parameters.elements().hasMoreElements())
+            System.out.print(state.parameters.elements().nextElement());
+        
+        ;
+        state.parameters.getProperty("state.parameters.entrySet()");
+        state.parameters.getString(new Parameter("print-params"),new Parameter(""));
+        
+
+
+    }
+    
+    
+    
+    
+    
+}
Index: branches/OKBJavaConnector/ECJClient/src/ec/Breeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Breeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Breeder.java	(revision 6152)
@@ -0,0 +1,48 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * Breeder.java
+ * 
+ * Created: Tue Aug 10 21:00:11 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A Breeder is a singleton object which is responsible for the breeding
+ * process during the course of an evolutionary run.  Only one Breeder
+ * is created in a run, and is stored in the EvolutionState object.
+ *
+ * <p>Breeders typically do their work by applying a Species' BreedingPipelines
+ * on subpopulations of that species to produce new individuals for those
+ * subpopulations.
+ *
+ * <p>Breeders may be multithreaded.  The number of threads they may spawn
+ * (excepting a parent "gathering" thread) is governed by the EvolutionState's
+ * breedthreads value.
+ *
+ * <p>Be careful about spawning threads -- this system has no few synchronized 
+ * methods for efficiency's sake, so you must either divvy up breeding in a
+ * thread-safe fashion and assume that all individuals
+ * in the current population are read-only (which you may assume for a generational
+ * breeder which needs to return a whole new population each generation), or
+ * otherwise you must obtain the appropriate locks on individuals in the population
+ * and other objects as necessary.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class Breeder implements Singleton
+    {
+    /** Breeds state.population, returning a new population.  In general,
+        state.population should not be modified. */
+
+    public abstract Population breedPopulation(final EvolutionState state) ;
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/BreedingPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/BreedingPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/BreedingPipeline.java	(revision 6152)
@@ -0,0 +1,301 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.*;
+import ec.steadystate.*;
+
+/* 
+ * BreedingPipeline.java
+ * 
+ * Created: Tue Aug 17 21:37:10 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A BreedingPipeline is a BreedingSource which provides "fresh" individuals which
+ * can be used to fill a new population.  BreedingPipelines might include
+ * Crossover pipelines, various Mutation pipelines, etc.  This abstract class
+ * provides some default versions of various methods to simplify matters for you.
+ * It also contains an array of breeding sources for your convenience.  You don't
+ * have to use them of course, but this means you have to customize the
+ * default methods below to make sure they get distributed to your special
+ * sources.  Note that these sources may contain references to the same
+ * object -- they're not necessarily distinct.  This is to provide both
+ * some simple DAG features and also to conserve space.
+ *
+ *
+ * <p>A BreedingPipeline implements SteadyStateBSourceForm, meaning that
+ * it receives the individualReplaced(...) and sourcesAreProperForm(...) messages.
+ * however by default it doesn't do anything with these except distribute them
+ * to its sources.  You might override these to do something more interesting.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>num-sources</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(User-specified number of sources to the pipeline.  
+ Some pipelines have hard-coded numbers of sources; others indicate 
+ (with the java constant DYNAMIC_SOURCES) that the number of sources is determined by this
+ user parameter instead.)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>source.</tt><i>n</i><br>
+ <font size=-1>classname, inherits and != BreedingSource, or the value <tt>same</tt><br>
+ <td valign=top>(Source <i>n</i> for this BreedingPipeline.
+ If the value is set to <tt>same</tt>, then this source is the
+ exact same source object as <i>base</i>.<tt>source.</tt><i>n-1</i>, and
+ further parameters for this object will be ignored and treated as the same 
+ as those for <i>n-1</i>.  <tt>same<tt> is not valid for 
+ <i>base</i>.<tt>source.0</tt>)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+
+ <tr><td valign=top><i>base</i>.<tt>source.</tt><i>n</i><br>
+ <td>Source <i>n</i></td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class BreedingPipeline extends BreedingSource implements SteadyStateBSourceForm
+    {
+    /** Indicates that a source is the exact same source as the previous source. */
+    public static final String V_SAME = "same";
+
+    /** Indicates the probability that the Breeding Pipeline will perform its mutative action instead of just doing reproduction. */
+    public static final String P_LIKELIHOOD = "likelihood";
+
+    /** Indicates that the number of sources is variable and determined by the
+        user in the parameter file. */
+
+    public static final int DYNAMIC_SOURCES = 0;
+
+    /** Standard parameter for number of sources (only used if numSources
+        returns DYNAMIC_SOURCES */
+
+    public static final String P_NUMSOURCES = "num-sources";
+
+    /** Standard parameter for individual-selectors associated with a BreedingPipeline */
+    public static final String P_SOURCE = "source";
+
+    /** My parameter base -- I keep it around so I can print some messages that
+        are useful with it (not deep cloned) */
+        
+    public Parameter mybase;
+
+    public float likelihood;
+
+    /** Array of sources feeding the pipeline */
+    public BreedingSource[] sources;
+
+    /** Returns the number of sources to this pipeline.  Called during
+        BreedingPipeline's setup.  Be sure to return a value > 0, or
+        DYNAMIC_SOURCES which indicates that setup should check the parameter
+        file for the parameter "num-sources" to make its determination. */
+
+    public abstract int numSources();
+            
+    /** Returns the minimum among the typicalIndsProduced() for any children --
+        a function that's useful internally, not very useful for you to call externally. */
+    public int minChildProduction() 
+        {
+        if (sources.length==0) return 0;
+        int min = sources[0].typicalIndsProduced();
+        for(int x=1;x<sources.length;x++)
+            {
+            int cur = sources[x].typicalIndsProduced();
+            if (min > cur) min = cur;
+            }
+        return min;
+        }
+
+    /** Returns the maximum among the typicalIndsProduced() for any children --
+        a function that's useful internally, not very useful for you to call externally. */
+    public int maxChildProduction() 
+        {
+        if (sources.length==0) return 0;
+        int max = sources[0].typicalIndsProduced();
+        for(int x=1;x<sources.length;x++)
+            {
+            int cur = sources[x].typicalIndsProduced();
+            if (max < cur) max = cur;
+            }
+        return max;
+        }
+
+
+    /** Returns the "typical" number of individuals produced -- by default
+        this is the minimum typical number of individuals produced by any
+        children sources of the pipeline.  If you'd prefer something different,
+        override this method. */
+    public int typicalIndsProduced()
+        {
+        return minChildProduction();
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        mybase = base;
+        
+        Parameter def = defaultBase();
+
+        likelihood = state.parameters.getFloatWithDefault(base.push(P_LIKELIHOOD), def.push(P_LIKELIHOOD), 1.0f);
+        if (likelihood < 0.0f || likelihood > 1.0f)
+            state.output.fatal("Breeding Pipeline likelihood must be a value between 0.0 and 1.0 inclusive",
+                base.push(P_LIKELIHOOD),
+                def.push(P_LIKELIHOOD));
+
+
+        int numsources = numSources();
+        if (numsources <= DYNAMIC_SOURCES)
+            {
+            // figure it from the file
+            numsources = state.parameters.getInt(
+                base.push(P_NUMSOURCES), def.push(P_NUMSOURCES),1);
+            if (numsources==0)
+                state.output.fatal("Breeding pipeline num-sources value must be > 0",
+                    base.push(P_NUMSOURCES),
+                    def.push(P_NUMSOURCES)); 
+            }
+
+        sources = new BreedingSource[numsources];
+
+        for(int x=0;x<sources.length;x++)
+            {
+            Parameter p = base.push(P_SOURCE).push(""+x);
+            Parameter d = def.push(P_SOURCE).push(""+x);
+
+            String s = state.parameters.getString(p,d);
+            if (s!=null && s.equals(V_SAME))
+                {
+                if (x==0)  // oops
+                    state.output.fatal(
+                        "Source #0 cannot be declared with the value \"same\".",
+                        p,d);
+                
+                // else the source is the same source as before
+                sources[x] = sources[x-1];
+                }
+            else 
+                {
+                sources[x] = (BreedingSource)
+                    (state.parameters.getInstanceForParameter(
+                        p,d,BreedingSource.class));
+                sources[x].setup(state,p);
+                }
+            }
+        state.output.exitIfErrors();
+        }
+
+
+    public Object clone()
+        {
+        BreedingPipeline c = (BreedingPipeline)(super.clone());
+        
+        // make a new array
+        c.sources = new BreedingSource[sources.length];
+
+        // clone the sources -- we won't go through the hassle of
+        // determining if we have a DAG or not -- we'll just clone
+        // it out to a tree.  I doubt it's worth it.
+
+        for(int x=0;x<sources.length;x++)
+            {
+            if (x==0 || sources[x]!=sources[x-1])
+                c.sources[x] = (BreedingSource)(sources[x].clone());
+            else 
+                c.sources[x] = c.sources[x-1];
+            }
+
+        return c;
+        }
+
+    /** Performs direct cloning of n individuals.  if produceChildrenFromSource is true, then */
+    public int reproduce(final int n, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread,
+        boolean produceChildrenFromSource) 
+        {
+        if (produceChildrenFromSource)
+            sources[0].produce(n,n,start,subpopulation,inds,state,thread);
+        if (sources[0] instanceof SelectionMethod)
+            for(int q=start; q < n+start; q++)
+                inds[q] = (Individual)(inds[q].clone());
+        return n;
+        }
+
+
+    public boolean produces(final EvolutionState state,
+        final Population newpop,
+        final int subpopulation,
+        int thread)
+        {
+        for(int x=0;x<sources.length;x++)
+            if (x==0 || sources[x]!=sources[x-1])
+                if (!sources[x].produces(state,newpop,subpopulation,thread))
+                    return false;
+        return true;
+        }
+
+    public void prepareToProduce(final EvolutionState state,
+        final int subpopulation,
+        final int thread)
+        {
+        for(int x=0;x<sources.length;x++) 
+            if (x==0 || sources[x]!=sources[x-1])
+                sources[x].prepareToProduce(state,subpopulation,thread);
+        }
+
+    public void finishProducing(final EvolutionState state,
+        final int subpopulation,
+        final int thread)
+        {
+        for(int x=0;x<sources.length;x++) 
+            if (x==0 || sources[x]!=sources[x-1])
+                sources[x].finishProducing(state,subpopulation,thread);
+        }
+
+    public void preparePipeline(Object hook)
+        {
+        // the default form calls this on all the sources.
+        // note that it follows all the source paths even if they're
+        // duplicates
+        for(int x=0; x<sources.length;x++) 
+            sources[x].preparePipeline(hook);
+        }
+        
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        {
+        for(int x=0; x<sources.length;x++) 
+            ((SteadyStateBSourceForm)(sources[x])).individualReplaced(state,subpopulation,thread,individual);
+        }
+
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        {
+        for(int x=0; x<sources.length;x++) 
+            if (! (sources[x] instanceof SteadyStateBSourceForm))
+                {
+                state.output.error("The following breeding source is not of SteadyStateBSourceForm.", 
+                    mybase.push(P_SOURCE).push(""+x), defaultBase().push(P_SOURCE).push(""+x));
+                }
+            else 
+                ((SteadyStateBSourceForm)(sources[x])).sourcesAreProperForm(state);
+        }
+
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/BreedingSource.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/BreedingSource.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/BreedingSource.java	(revision 6152)
@@ -0,0 +1,216 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.*;
+
+/* 
+ * BreedingSource.java
+ * 
+ * Created: Thu Nov 18 17:40:26 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A BreedingSource is a Prototype which 
+ * provides Individuals to populate new populations based on
+ * old ones.  The BreedingSource/BreedingPipeline/SelectionMethod mechanism
+ * is inherently designed to work within single subpopulations, which is
+ * by far the most common case.  If for some
+ * reason you need to breed among different subpopulations to produce new ones
+ * in a manner that can't be handled with exchanges, you will probably have to
+ * write your own custom Breeder; you'd have to write your own custom breeding
+ * pipelines anyway of course, though you can probably get away with reusing
+ * the SelectionMethods.
+ *
+ * <p>A BreedingSource may have parent sources which feed it as well.
+ * Some BreedingSources, <i>SelectionMethods</i>,
+ * are meant solely to plug into other BreedingSources, <i>BreedingPipelines</i>.
+ * BreedingPipelines can plug into other BreedingPipelines, and can also be
+ * used to provide the final Individual meant to populate a new generation.
+ *
+ * <p>Think of BreedingSources as Streams of Individuals; at one end of the
+ * stream is the provider, a SelectionMethod, which picks individuals from
+ * the old population.  At the other end of the stream is a BreedingPipeline
+ * which hands you the finished product, a small set of new Individuals
+ * for you to use in populating your new population.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i><tt>.prob</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0, or undefined</font></td>
+ <td valign=top>(probability this BreedingSource gets chosen.  Undefined is only valid if the caller of this BreedingSource doesn't need a probability)</td></tr>
+ </table>
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class BreedingSource implements Prototype, RandomChoiceChooser
+    {
+    public static final String P_PROB = "prob";
+    public static final float NO_PROBABILITY = -1.0f;
+    
+    /** The probability that this BreedingSource will be chosen 
+        to breed over other BreedingSources.  This may or may
+        not be used, depending on what the caller to this BreedingSource is.
+        It also might be modified by external sources owning this object,
+        for their own purposes.  A BreedingSource should not use it for
+        any purpose of its own, nor modify it except when setting it up.
+
+        <p>The most common modification is to normalize it with some other
+        set of probabilities, then set all of them up in increasing summation;
+        this allows the use of the fast static BreedingSource-picking utility
+        method, BreedingSource.pickRandom(...).  In order to use this method,
+        for example, if four
+        breeding source probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.
+    */
+
+    public float probability;
+
+    /** Sets up the BreedingPipeline.  You can use state.output.error here
+        because the top-level caller promises to call exitIfErrors() after calling
+        setup.  Note that probability might get modified again by
+        an external source if it doesn't normalize right. 
+
+        <p>The most common modification is to normalize it with some other
+        set of probabilities, then set all of them up in increasing summation;
+        this allows the use of the fast static BreedingSource-picking utility
+        method, BreedingSource.pickRandom(...).  In order to use this method,
+        for example, if four
+        breeding source probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.
+
+
+        @see Prototype#setup(EvolutionState,Parameter)
+    */
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        if (!state.parameters.exists(base.push(P_PROB),def.push(P_PROB)))
+            probability = NO_PROBABILITY;
+        else
+            {
+            probability = state.parameters.getFloat(base.push(P_PROB),def.push(P_PROB),0.0);
+            if (probability<0.0) state.output.error("Breeding Source's probability must be a floating point value >= 0.0, or empty, which represents NO_PROBABILITY.",base.push(P_PROB),def.push(P_PROB));
+            }
+        }
+
+    public final float getProbability(final Object obj)
+        {
+        return ((BreedingSource)obj).probability;
+        }
+
+    public final void setProbability(final Object obj, final float prob)
+        {
+        ((BreedingSource)obj).probability = prob;
+        }
+
+
+    /** Picks a random source from an array of sources, with their
+        probabilities normalized and summed as follows:  For example,
+        if four
+        breeding source probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}. */
+
+    public static int pickRandom(final BreedingSource[] sources,final float prob)
+        {
+        return RandomChoice.pickFromDistribution(sources,sources[0], prob);
+        }
+
+    /** Normalizes and arranges the probabilities in sources so that they
+        are usable by pickRandom(...).  If the sources have all zero probabilities,
+        then a uniform selection is used.  Negative probabilities will
+        generate an ArithmeticException, as will an empty source array. */
+    public static void setupProbabilities(final BreedingSource[] sources)
+        {
+        RandomChoice.organizeDistribution(sources,sources[0],true);
+        }
+
+
+    /** Returns the "typical" number of individuals
+        generated with one call of produce(...). */
+    public abstract int typicalIndsProduced();
+
+    /** Returns true if this BreedingSource, when attached to the given
+        subpopulation, will produce individuals of the subpopulation's species.
+        SelectionMethods should additionally make sure that their Fitnesses are
+        of a valid type, if necessary. newpop *may* be the same as state.population
+    */
+
+    public abstract boolean produces(final EvolutionState state,
+        final Population newpop,
+        final int subpopulation,
+        int thread);
+
+    /** Called before produce(...), usually once a generation, or maybe only
+        once if you're doing steady-state evolution, to let the breeding source
+        "warm up" prior to producing.  Individuals should be produced from
+        old individuals in positions [start...start+length] in the subpopulation 
+        only.  May be called again to reset the BreedingSource for a whole
+        'nuther subpopulation. */
+
+    public abstract void prepareToProduce(final EvolutionState state,
+        final int subpopulation,
+        final int thread);
+
+    /** Called after produce(...), usually once a generation, or maybe only
+        once if you're doing steady-state evolution (at the end of the run). */
+        
+    public abstract void finishProducing(final EvolutionState s,
+        final int subpopulation,
+        final int thread);
+
+    /** Produces <i>n</i> individuals from the given subpopulation
+        and puts them into inds[start...start+n-1],
+        where n = Min(Max(q,min),max), where <i>q</i> is the "typical" number of 
+        individuals the BreedingSource produces in one shot, and returns
+        <i>n</i>.  max must be >= min, and min must be >= 1. For example, crossover
+        might typically produce two individuals, tournament selection might typically
+        produce a single individual, etc. */
+    public abstract int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) ;        
+
+    public Object clone()
+        {
+        try { return super.clone(); }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+
+
+    /** A hook which should be passed to all your subsidiary breeding
+        sources.  The default does this for you already, so ordinarily
+        you don't need to change anything.  If you are a BreedingPipeline and you
+        implement your sources in a way different
+        than using the sources[] array, be sure to override this method
+        so that it calls preparePipeline(hook) on all of your sources.
+        
+        <p>ECJ at present does not custom-implement or call this method: 
+        it's available for you. Becuase it has custom functionality, 
+        this method might get called more than once, and by various objects
+        as needed.  If you use it, you should determine somehow how to use
+        it to send information under the assumption that it might be sent
+        by nested items in the pipeline; you don't want to scribble over
+        each other's calls! Note that this method should travel *all*
+        breeding source paths regardless of whether or not it's redundant to
+        do so. */
+    public void preparePipeline(final Object hook)
+        {
+        // the default method does nothing, though BreedingPipelines override this
+        // to guarantee that it's called on all their sources as well.
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Clique.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Clique.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Clique.java	(revision 6152)
@@ -0,0 +1,45 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec;
+
+/* 
+ * Clique.java
+ * 
+ * Created: Wed Oct 13 15:12:23 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Clique is a class pattern marking classes which 
+ * create only a few instances, generally accessible through
+ * some global mechanism, and every single
+ * one of which gets its own distinct setup(...) call.  Cliques should
+ * <b>not</b> be Cloneable, but they are Serializable.
+ *
+ * <p>All Cliques presently in ECJ rely on a central repository which
+ * stores members of that Clique for easy access by various objects.
+ * This repository typically includes a hashtable of the Clique members,
+ * plus perhaps one or more arrays of the members stored in different
+ * fashions.  Originally these central repositories were stored as static
+ * members of the Clique class; but as of ECJ 13 they have been moved
+ * to be instance variables of certain Initializers.  For example,
+ * GPInitializer holds the repositories for the GPFunctionSet, GPType,
+ * GPNodeConstraints, and GPTreeConstraints cliques.  Likewise,
+ * RuleInitializer holds the repository for the RuleConstraints clique.
+ * 
+ * <p>This change was made to facilitate making ECJ modular; we had to remove
+ * all non-final static members.  If you make your own Clique, its repository
+ * (if you have one) doesn't have to be in an Initializer, but it's a 
+ * convenient location.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface Clique extends Setup
+    {
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/DefaultsForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/DefaultsForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/DefaultsForm.java	(revision 6152)
@@ -0,0 +1,42 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * DefaultsForm.java
+ * 
+ * Created: Fri Jan 21 15:14:01 2000
+ * By: Sean Luke
+ */
+
+/**
+ * DefaultsForm is the interface which describes how Defaults objects
+ * should work.  In general there is one Defaults class for each
+ * package (there doesn't have to be, but it would be nice).  This
+ * class should be relatively uniquely named (the defaults class in
+ * the GP package is called GPDefaults for example).
+ * DefaultsForm objects should implement a single static final method:
+
+ <p><tt>public final Parameter base();</tt>
+
+ <p>...which returns the default parameter base for the package.  This
+ method cannot be declared in this interface, however, because it is
+ static.  :-)  So this interface isn't much use, except to describe how
+ defaults objects should generally work.
+
+ <p> A parameter base is a secondary "default" place for the parameters database to look
+ for a parameter value if the primary value was not defined.
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface DefaultsForm 
+    {
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/ECDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/ECDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/ECDefaults.java	(revision 6152)
@@ -0,0 +1,32 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.*;
+
+/* 
+ * ECDefaults.java
+ * 
+ * Created: Thu Jan 20 16:49:57 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class ECDefaults implements DefaultsForm
+    {
+    public static final String P_EC = "ec";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_EC);
+        }    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Evaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Evaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Evaluator.java	(revision 6152)
@@ -0,0 +1,134 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.ParamClassLoadException;
+import ec.util.Parameter;
+import ec.eval.MasterProblem;
+
+/* 
+ * Evaluator.java
+ * 
+ * Created: Tue Aug 10 20:53:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * An Evaluator is a singleton object which is responsible for the
+ * evaluation process during the course of an evolutionary run.  Only
+ * one Evaluator is created in a run, and is stored in the EvolutionState
+ * object.
+ *
+ * <p>Evaluators typically do their work by applying an instance of some
+ * subclass of Problem to individuals in the population.  Evaluators come
+ * with a Problem prototype which they may clone as necessary to create
+ * new Problem spaces to evaluate individuals in (Problems may be reused
+ * to prevent constant cloning).
+ *
+ * <p>Evaluators may be multithreaded, with one Problem instance per thread
+ * usually.  The number of threads they may spawn (excepting a parent
+ * "gathering" thread) is governed by the EvolutionState's evalthreads value.
+ *
+ * <p>Be careful about spawning threads -- this system has no few synchronized 
+ * methods for efficiency's sake, so you must either divvy up evaluation in 
+ * a thread-safe fashion, or 
+ * otherwise you must obtain the appropriate locks on individuals in the population
+ * and other objects as necessary.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i><tt>.problem</tt><br>
+ <font size=-1>classname, inherits and != ec.Problem</font></td>
+ <td valign=top>(the class for the Problem prototype p_problem)</td></tr>
+ <tr><td valign=top><i>base</i><tt>.masterproblem</tt><br>
+ <font size=-1>classname, inherits</font></td>
+ <td valign=top>(the class for the MasterProblem prototype masterproblem)</td></tr>
+ </table>
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class Evaluator implements Singleton
+    {
+    public static final String P_PROBLEM = "problem";
+
+    public Problem p_problem;
+
+    public static final String P_MASTERPROBLEM = "masterproblem";
+    public static final String P_IAMSLAVE = "i-am-slave";
+    
+    /** Evaluates the fitness of an entire population.  You will
+        have to determine how to handle multiple threads on your own,
+        as this is a very domain-specific thing. */
+    public abstract void evaluatePopulation(final EvolutionState state);
+
+    /** Returns true if an ideal individual has been found or some
+        other run result has shortcircuited the run so that it should
+        end prematurely right now. */
+    public abstract boolean runComplete(final EvolutionState state);
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // Load my problem
+        p_problem = (Problem)(state.parameters.getInstanceForParameter(
+                base.push(P_PROBLEM),null,Problem.class));
+        p_problem.setup(state,base.push(P_PROBLEM));
+        
+        /*
+        // Check to see if this process is configured to be a master problem server
+        // If so, don't bother creating and setting up the master problem.
+        String masterServerName = state.parameters.getString(new Parameter(P_EVALSLAVENAME));
+
+        if (masterServerName == null)
+        {
+        */
+        // Am I a master problem and NOT a slave.  Note that the "eval.i-am-slave" parameter
+        // is not set by the user but rather programmatically by the Slave.java class
+        if( state.parameters.exists(base.push(P_MASTERPROBLEM),null) &&  // I am a master (or possibly a slave -- same params)
+            !state.parameters.getBoolean(base.push(P_IAMSLAVE),null,false))  // I am NOT a slave
+            {
+            try {
+                Problem masterproblem = (Problem)(state.parameters.getInstanceForParameter(
+                        base.push(P_MASTERPROBLEM),null,Problem.class));
+                masterproblem.setup(state,base.push(P_MASTERPROBLEM));
+                 
+                /*
+                 * If a MasterProblem was specified, interpose it between the
+                 * evaluator and the real problem.  This allows seamless use
+                 * of the master problem.
+                 */
+                ((MasterProblem)masterproblem).problem = p_problem;
+                p_problem = masterproblem;
+                }
+            catch(ParamClassLoadException e)
+                {
+                state.output.fatal("Parameter has an invalid value: "+base.push(P_MASTERPROBLEM));
+                }
+            }
+        /*
+          }
+        */        
+        }
+    
+    /** Called to set up remote evaluation network contacts when the run is started.  Mostly used for client/server evaluation (see MasterProblem).  By default calls p_problem.initializeContacts(state) */
+    public void initializeContacts(EvolutionState state)
+        {
+        p_problem.initializeContacts(state);
+        }
+    
+    /**  Called to reinitialize remote evaluation network contacts when the run is restarted from checkpoint.  Mostly used for client/server evaluation (see MasterProblem).  By default calls p_problem.reinitializeContacts(state) */
+    public void reinitializeContacts(EvolutionState state)
+        {
+        p_problem.reinitializeContacts(state);
+        }
+        
+    /**  Called to shut down remote evaluation network contacts when the run is completed.  Mostly used for client/server evaluation (see MasterProblem).  By default calls p_problem.closeContacts(state,result) */
+    public void closeContacts(EvolutionState state, int result)
+        {
+        p_problem.closeContacts(state,result);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/EvolutionState.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/EvolutionState.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/EvolutionState.java	(revision 6152)
@@ -0,0 +1,376 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.ParameterDatabase;
+import ec.util.Parameter;
+import ec.util.MersenneTwisterFast;
+import ec.util.Output;
+import java.io.IOException;
+import java.util.Vector;
+
+/* 
+ * EvolutionState.java
+ * 
+ * Created: Tue Aug 10 22:14:46 1999
+ * By: Sean Luke
+ */
+
+/**
+ * An EvolutionState object is a singleton object which holds the entire
+ * state of an evolutionary run.  By serializing EvolutionState, the entire
+ * run can be checkpointed out to a file.
+ *
+ * <p>The EvolutionState instance is passed around in a <i>lot</i> of methods,
+ * so objects can read from the parameter database, pick random numbers,
+ * and write to the output facility.
+ *
+ * <p>EvolutionState is a unique object in that it calls its own setup(...)
+ * method, from run(...).
+ *
+ * <p>An EvolutionState object contains quite a few objects, including:
+ <ul>
+ <li><i>Objects you may safely manipulate during the multithreaded sections of a run:</i>
+ <ul>
+ <li> MersenneTwisterFast random number generators (one for each evaluation or breeding thread -- use the thread number you were provided to determine which random number generator to use)
+ <li> The ParameterDatabase
+ <li> The Output facility for writing messages and logging
+ </ul>
+
+ <li><i>Singleton objects:</i>
+ <ul>
+ <li> The Initializer.
+ <li> The Finisher.
+ <li> The Breeder.
+ <li> The Evaluator.
+ <li> The Statistics facility.
+ <li> The Exchanger.
+ </ul>
+
+ <li><i>The current evolution state:</i>
+ <ul>
+ <li> The generation number.
+ <li> The population.
+ <li> The maximal number of generations.
+ </ul>
+
+ <li><i>Auxillary read-only information:</i>
+ <ul>
+ <li> The prefix to begin checkpoint file names with.
+ <li> Whether to quit upon finding a perfect individual.
+ <li> The number of breeding threads to spawn.
+ <li> The number of evaluation threads to spawn.
+ </ul>
+ 
+ <li><i>A place to stash pointers to static variables so they'll get serialized: </i>
+ <ul>
+ <li> Statics
+ </ul>
+ </ul>
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt>generations</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(maximal number of generations to run.)</td></tr>
+
+ <tr><td valign=top><tt>checkpoint-modulo</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(how many generations should pass before we do a checkpoint?  
+ The definition of "generations" depends on the particular EvolutionState 
+ implementation you're using)</td></tr>
+
+ <tr><td valign=top><tt>checkpoint</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(should we checkpoint?)</td></tr>
+ 
+ <tr><td valign=top><tt>prefix</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(the prefix to prepend to checkpoint files -- see ec.util.Checkpoint)</td></tr>
+
+ <tr><td valign=top><tt>quit-on-run-complete</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(do we prematurely quit the run when we find a perfect individual?)</td></tr>
+
+ <tr><td valign=top><tt>init</tt><br>
+ <font size=-1>classname, inherits and != ec.Initializer</font></td>
+ <td valign=top>(the class for initializer)</td></tr>
+
+ <tr><td valign=top><tt>finish</tt><br>
+ <font size=-1>classname, inherits and != ec.Finisher</font></td>
+ <td valign=top>(the class for finisher)</td></tr>
+
+ <tr><td valign=top><tt>breed</tt><br>
+ <font size=-1>classname, inherits and != ec.Breeder</font></td>
+ <td valign=top>(the class for breeder)</td></tr>
+
+ <tr><td valign=top><tt>eval</tt><br>
+ <font size=-1>classname, inherits and != ec.Evaluator</font></td>
+ <td valign=top>(the class for evaluator)</td></tr>
+
+ <tr><td valign=top><tt>stat</tt><br>
+ <font size=-1>classname, inherits or = ec.Statistics</font></td>
+ <td valign=top>(the class for statistics)</td></tr>
+
+ <tr><td valign=top><tt>exch</tt><br>
+ <font size=-1>classname, inherits and != ec.Exchanger</font></td>
+ <td valign=top>(the class for exchanger)</td></tr>
+
+ </table>
+
+
+ <p><b>Parameter bases</b><br>
+ <table>
+
+ <tr><td valign=top><tt>init</tt></td>
+ <td>initializer</td></tr>
+
+ <tr><td valign=top><tt>finish</tt></td>
+ <td>finisher</td></tr>
+
+ <tr><td valign=top><tt>breed</tt></td>
+ <td>breeder</td></tr>
+
+ <tr><td valign=top><tt>eval</tt></td>
+ <td>evaluator</td></tr>
+
+ <tr><td valign=top><tt>stat</tt></td>
+ <td>statistics</td></tr>
+
+ <tr><td valign=top><tt>exch</tt></td>
+ <td>exchanger</td></tr>
+ </table>
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class EvolutionState implements Singleton
+    {
+    /** The parameter database (threadsafe).  Parameter objects are also threadsafe.
+        Nonetheless, you should generally try to treat this database as read-only. */
+    public ParameterDatabase parameters;
+
+    /** An array of random number generators, indexed by the thread number you were given (or, if you're not in a multithreaded area, use 0).  These generators are not threadsafe in and of themselves, but if you only use the random number generator assigned to your thread, as was intended, then you get random numbers in a threadsafe way.  These generators must each have a different seed, of course.v*/
+    public MersenneTwisterFast[] random;
+
+    /** The output and logging facility (threadsafe).  Keep in mind that output in Java is expensive. */
+    public Output output;
+
+    /** The requested number of threads to be used in breeding, excepting perhaps a "parent" thread which gathers the other threads.  If breedthreads = 1, then the system should not be multithreaded during breeding.  Don't modify this during a run. */
+    public int breedthreads;  // how many threads to use in breeding
+
+    /** The requested number of threads to be used in evaluation, excepting perhaps a "parent" thread which gathers the other threads.  If evalthreads = 1, then the system should not be multithreaded during evaluation. Don't modify this during a run.*/
+    public int evalthreads;  // how many threads to use in evaluation
+
+    /** Should we checkpoint at all? */
+    public boolean checkpoint;
+
+    /** The requested prefix start checkpoint filenames, not including a following period.  You probably shouldn't modify this during a run.*/
+    public String checkpointPrefix;  // term to prefix checkpoint filenames
+
+    /** The requested number of generations that should pass before we write out a checkpoint file. */
+    public int checkpointModulo;
+
+    /** An amount to add to each random number generator seed to "offset" it -- often this is simply the job number.  
+        If you are using more random number generators
+        internally than the ones initially created for you in the EvolutionState, you might want to create them with the seed
+        value of <tt>seedParameter+randomSeedOffset</tt>.  At present the only such class creating additional generators
+        is ec.eval.MasterProblem. */
+    public int randomSeedOffset;
+
+    /** Whether or not the system should prematurely quit when Evaluator returns true for runComplete(...) (that is, when the system found an ideal individual. */
+    public boolean quitOnRunComplete;
+
+    /** Current job iteration variables, set by Evolve.  The default version simply sets this to a single Object[1] containing
+        the current job iteration number as an Integer (for a single job, it's 0).  You probably should not modify this inside
+        an evolutionary run.  */
+    public Object[] job;
+
+    /** The original runtime arguments passed to the Java process. You probably should not modify this inside
+        an evolutionary run.  */
+    public String[] runtimeArguments;
+        
+    // set during running
+    
+    /** The current generation of the population in the run.  For non-generational approaches, this probably should represent some kind of incrementing value, perhaps the number of individuals evaluated so far.  You probably shouldn't modify this. */
+    public int generation;
+    /** The number of generations the evolutionary computation system will run until it ends.  If after the population has been evaluated the Evaluator returns true for runComplete(...), and quitOnRunComplete is true, then the system will quit.  You probably shouldn't modify this.  */
+    public int numGenerations;
+
+    /** The current population.  This is <i>not</i> a singleton object, and may be replaced after every generation in a generational approach. You should only access this in a read-only fashion.  */
+    public Population population;
+
+    /** The population initializer, a singleton object.  You should only access this in a read-only fashion. */
+    public Initializer initializer;
+
+    /** The population finisher, a singleton object.  You should only access this in a read-only fashion. */
+    public Finisher finisher;
+
+    /** The population breeder, a singleton object.  You should only access this in a read-only fashion. */
+    public Breeder breeder;
+
+    /** The population evaluator, a singleton object.  You should only access this in a read-only fashion. */
+    public Evaluator evaluator;
+
+    /** The population statistics, a singleton object.  You should generally only access this in a read-only fashion. */
+    public Statistics statistics;
+
+    /** The population exchanger, a singleton object.  You should only access this in a read-only fashion. */
+    public Exchanger exchanger;
+
+    /** "The population has started fresh (not from a checkpoint)." */ 
+    public final static int C_STARTED_FRESH = 0;
+
+    /** "The population started from a checkpoint." */
+    public final static int C_STARTED_FROM_CHECKPOINT = 1;
+
+    /** "The evolution run has quit, finding a perfect individual." */
+    public final static int R_SUCCESS = 0;
+
+    /** "The evolution run has quit, failing to find a perfect individual." */
+    public final static int R_FAILURE = 1;
+    
+    /** "The evolution run has not quit */
+    public final static int R_NOTDONE = 2;
+
+    public final static String P_INITIALIZER = "init";
+    public final static String P_FINISHER = "finish";
+    public final static String P_BREEDER = "breed";
+    public final static String P_EVALUATOR = "eval";
+    public final static String P_STATISTICS = "stat";
+    public final static String P_EXCHANGER = "exch";
+    public final static String P_GENERATIONS = "generations";
+    public final static String P_QUITONRUNCOMPLETE = "quit-on-run-complete";
+    public final static String P_CHECKPOINTPREFIX = "prefix";
+    public final static String P_CHECKPOINTMODULO = "checkpoint-modulo";
+    public final static String P_CHECKPOINT = "checkpoint";
+
+    /** This will be called to create your evolution state; immediately
+        after the constructor is called,
+        the parameters, random, and output fields will be set
+        for you.  The constructor probably won't be called ever if
+        restoring (deserializing) from a checkpoint.
+    */
+    public EvolutionState() { }
+    
+    /** Unlike for other setup() methods, ignore the base; it will always be null. 
+        @see Prototype#setup(EvolutionState,Parameter)
+    */
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+
+        Parameter p;
+
+        // we ignore the base, it's worthless anyway for EvolutionState
+
+        p = new Parameter(P_CHECKPOINT);
+        checkpoint = parameters.getBoolean(p,null,false);
+
+        p = new Parameter(P_CHECKPOINTPREFIX);
+        checkpointPrefix = parameters.getString(p,null);
+        if (checkpointPrefix==null)
+            output.fatal("No checkpoint prefix specified.",p);
+
+        p = new Parameter(P_CHECKPOINTMODULO);
+        checkpointModulo = parameters.getInt(p,null,1);
+        if (checkpointModulo==0)
+            output.fatal("The checkpoint modulo must be an integer >0.",p);
+        
+        p = new Parameter(P_GENERATIONS);
+        numGenerations = parameters.getInt(p,null,1);
+        if (numGenerations==0)
+            output.fatal("The number of generations must be an integer >0.",p);
+        
+        p=new Parameter(P_QUITONRUNCOMPLETE);
+        quitOnRunComplete = parameters.getBoolean(p,null,false);
+
+
+        /* Set up the singletons */
+        p=new Parameter(P_INITIALIZER);
+        initializer = (Initializer)
+            (parameters.getInstanceForParameter(p,null,Initializer.class));
+        initializer.setup(this,p);
+
+        p=new Parameter(P_FINISHER);
+        finisher = (Finisher)
+            (parameters.getInstanceForParameter(p,null,Finisher.class));
+        finisher.setup(this,p);
+
+        p=new Parameter(P_BREEDER);
+        breeder = (Breeder)
+            (parameters.getInstanceForParameter(p,null,Breeder.class));
+        breeder.setup(this,p);
+
+        p=new Parameter(P_EVALUATOR);
+        evaluator = (Evaluator)
+            (parameters.getInstanceForParameter(p,null,Evaluator.class));
+        evaluator.setup(this,p);
+
+        p=new Parameter(P_STATISTICS);
+        statistics = (Statistics)
+            (parameters.getInstanceForParameterEq(p,null,Statistics.class));
+        statistics.setup(this,p);
+        
+        p=new Parameter(P_EXCHANGER);
+        exchanger = (Exchanger)
+            (parameters.getInstanceForParameter(p,null,Exchanger.class));
+        exchanger.setup(this,p);
+                
+        generation = 0;
+        }
+
+
+    /** This method is called after a checkpoint
+        is restored from but before the run starts up again.  You might use this
+        to set up file pointers that were lost, etc. */
+ 
+    public void resetFromCheckpoint() throws IOException
+        {
+        output.restart();   // may throw an exception if there's a bad file
+        exchanger.reinitializeContacts(this);
+        evaluator.reinitializeContacts(this);
+        }
+
+    public void finish(int result) {}
+
+    public void startFromCheckpoint() {}
+
+    public void startFresh() {}
+
+    public int evolve()
+        throws InternalError { return R_NOTDONE; }
+
+    /** Starts the run. <i>condition</i> indicates whether or not the
+        run was restarted from a checkpoint (C_STARTED_FRESH vs
+        C_STARTED_FROM_CHECKPOINT).  At the point that run(...) has been
+        called, the parameter database has already been set up, as have
+        the random number generators, the number of threads, and the
+        Output facility.  This method should call this.setup(...) to
+        set up the EvolutionState object if condition equals C_STARTED_FRESH. */
+    public void run(int condition)
+        {
+        if (condition == C_STARTED_FRESH)
+            {
+            startFresh();
+            }
+        else // condition == C_STARTED_FROM_CHECKPOINT
+            {
+            startFromCheckpoint();
+            }
+        
+        /* the big loop */
+        int result = R_NOTDONE;
+        while ( result == R_NOTDONE )
+            {
+            result = evolve();
+            }
+        
+        finish(result);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Evolve.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Evolve.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Evolve.java	(revision 6152)
@@ -0,0 +1,652 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.*;
+import java.io.File;
+import java.io.PrintWriter;
+
+/* 
+ * Evolve.java
+ * 
+ * Created: Wed Aug 11 17:49:01 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Evolve is the main entry class for an evolutionary computation run.
+ *
+ * <p> An EC run is done with one of two argument formats:
+ *
+ * <p><tt>java ec.Evolve -file </tt><i>parameter_file [</i><tt>-p </tt><i>parameter=value]*</i>
+ *
+ * <p>This starts a new evolutionary run, using the parameter file <i>parameter_file</i>.
+ * The user can provide optional overriding parameters on the command-line with the <tt>-p</tt> option.
+ *
+ * <p><tt>java ec.Evolve -checkpoint </tt><i>checkpoint_file</i>
+ * 
+ * <p>This starts up an evolutionary run from a previous checkpoint file.
+ *
+ * <p>The basic Evolve class has a main() loop with a simple job iteration facility.
+ * If you'd like to run the evolutionary system four times, each with a different random
+ * seed, you might do:
+ * 
+ * <p><tt>java ec.Evolve -file </tt><i>parameter_file</i> <tt>-p jobs=4</tt>
+ *
+ * <p>Here, Evolve will run the first time with the random seed equal to whatever's specified
+ * in your file, then job#2 will be run with the seed + 1, job#3 with the seed + 2, 
+ * and job#4 with the seed + 3.  If you have multiple seeds, ECJ will try to make sure they're
+ * all different even across jobs by adding the job number * numberOfSeeds to each of them.
+ * This means that if you're doing multiple jobs with multiple seeds, you should probably set
+ * seed.0 to x, seed.1 to x+1, seed.2 to x+2, etc. for best results.  It also works if seed.0
+ * is x, seed.1 is y (a number much bigger than x), seed.2 is z (a number much bigger than y) etc.
+ *
+ * If you set seed.0=time etc. for multiple jobs, the values of each seed will be set to the
+ * current time that the job starts plus the job number * numberOfSeeds.  As current time always
+ * goes up, this shouldn't be an issue.  However it's theoretically possible that if you checkpoint and restart
+ * on another system with a clock set back in time, you could get the same seed in a later job.
+ *
+ * <p><b>main() has been designed to be modified.</b>  The comments for the Evolve.java file contain
+ * a lot discussion of how ECJ's main() bootstraps the EvolutionState object and runs it, plus a much
+ * simpler example of main() and explanations for how main() works.
+ *
+
+ <p><b>Parameters</b><br>
+ <table>
+
+ <tr><td valign=top><tt>jobs</tt></br>
+ <font size=-1> int >= 1 (default)</font></td>
+ <td valign=top>(The number of jobs to iterate.  The current job number (0...jobs-1) will be added to each seed UNLESS the seed is loaded from the system time.  The job number also gets added as a prefix (if the number of jobs is more than 1)).</td></tr>
+
+ <tr><td valign=top><tt>nostore</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should the ec.util.Output facility <i>not</i> store announcements in memory?)</td></tr>
+
+ <tr><td valign=top><tt>flush</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should I flush all output as soon as it's printed (useful for debugging when an exception occurs))</td></tr>
+
+ <tr><td valign=top><tt>evalthreads</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the number of threads to spawn for evaluation)</td></tr>
+
+ <tr><td valign=top><tt>breedthreads</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the number of threads to spawn for breeding)</td></tr>
+
+ <tr><td valign=top><tt>seed.</tt><i>n</i><br>
+ <font size=-1>int != 0, or string  = <tt>time</tt></font></td>
+ <td valign=top>(the seed for random number generator #<i>n</i>.  <i>n</i> should range from 0 to Max(evalthreads,breedthreads)-1.  If value is <tt>time</tt>, then the seed is based on the system clock plus <i>n</i>.)</td></tr>
+
+ <tr><td valign=top><tt>state</tt><br>
+ <font size=-1>classname, inherits and != ec.EvolutionState</font></td>
+ <td valign=top>(the EvolutionState object class)</td></tr>
+
+ <tr><td valign=top><tt>print-accessed-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters requested during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-used-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters actually <i>used</i> during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-unaccessed-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters NOT requested during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-unused-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters NOT actually used during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-all-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters stored in the parameter database?)</td></tr>
+
+ </table>
+ * 
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Evolve 
+    {
+    public final static String P_PRINTACCESSEDPARAMETERS = "print-accessed-params";
+    public final static String P_PRINTUSEDPARAMETERS = "print-used-params";
+    public final static String P_PRINTALLPARAMETERS = "print-all-params";
+    public final static String P_PRINTUNUSEDPARAMETERS = "print-unused-params";
+    public final static String P_PRINTUNACCESSEDPARAMETERS = "print-unaccessed-params";
+
+    /** The argument indicating that we're starting up from a checkpoint file. */
+    public static final String A_CHECKPOINT = "-checkpoint";
+    
+    /** The argument indicating that we're starting fresh from a new parameter file. */
+    public static final String A_FILE = "-file";
+
+    /** evalthreads parameter */
+    public static final String P_EVALTHREADS = "evalthreads";
+
+    /** breedthreads parameter */
+    public static final String P_BREEDTHREADS = "breedthreads";
+
+    /** seed parameter */
+    public static final String P_SEED = "seed";
+
+    /** 'time' seed parameter value */
+    public static final String V_SEED_TIME = "time";
+
+    /** state parameter */
+    public static final String P_STATE = "state";
+    
+    /** 'auto' thread parameter value */
+    public static final String V_THREADS_AUTO = "auto";
+
+
+    /** Restores an EvolutionState from checkpoint if "-checkpoint FILENAME" is in the command-line arguments. */
+    public static EvolutionState possiblyRestoreFromCheckpoint(String[] args)
+        {
+        for(int x=0;x<args.length-1;x++)
+            if (args[x].equals(A_CHECKPOINT))
+                {
+                System.err.println("Restoring from Checkpoint " + args[x+1]);
+                try
+                    {
+                    return Checkpoint.restoreFromCheckpoint(args[x+1]);
+                    }
+                catch(Exception e)
+                    {
+                    Output.initialError("An exception was generated upon starting up from a checkpoint.\nHere it is:\n" + e);
+                    }
+                }
+        return null;  // should never happen
+        }
+                
+    /** Loads a ParameterDatabase from checkpoint if "-params" is in the command-line arguments. */
+    public static ParameterDatabase loadParameterDatabase(String[] args) 
+        {
+        ParameterDatabase parameters = null;
+        for(int x=0;x<args.length-1;x++)
+            if (args[x].equals(A_FILE))
+                try
+                    {
+                    parameters = new ParameterDatabase(
+                        new File(new File(args[x+1]).getAbsolutePath()),
+                        args);
+                    break;
+                    }
+                catch(Exception e)
+                    {
+                    Output.initialError(
+                        "An exception was generated upon reading the parameter file \"" +
+                        args[x+1] + "\".\nHere it is:\n" + e); 
+                    }
+        if (parameters==null)
+            Output.initialError("No parameter file was specified." );
+        return parameters;
+        }
+    
+    
+    /** Loads the number of threads. */
+    public static int determineThreads(Output output, ParameterDatabase parameters, Parameter threadParameter)
+        {
+        int thread = 1;
+        String tmp_s = parameters.getString(threadParameter,null);
+        if (tmp_s==null) // uh oh
+            {
+            output.fatal("Threads number must exist.",threadParameter,null);
+            }
+        else if (V_THREADS_AUTO.equalsIgnoreCase(tmp_s))
+            {
+            Runtime runtime = Runtime.getRuntime();
+            try { return ((Integer)runtime.getClass().getMethod("availableProcessors", (Class[])null).
+                    invoke(runtime,(Object[])null)).intValue(); }
+            catch (Exception e)
+                { 
+                output.fatal("Whoa! This Java version is too old to have the Runtime.availableProcessors() method available.\n" + 
+                    "This means you can't use 'auto' as a threads option.",threadParameter,null);
+                }
+            }
+        else
+            {
+            try
+                {
+                thread = parameters.getInt(threadParameter,null);
+                }
+            catch (NumberFormatException e)
+                {
+                output.fatal("Invalid, non-integer threads value ("+thread+")",threadParameter,null);
+                }
+            }
+        return thread;
+        }
+        
+    /** Primes the generator.  Mersenne Twister seeds its first 624 numbers using a basic
+        linear congruential generator; thereafter it uses the MersenneTwister algorithm to
+        build new seeds.  Those first 624 numbers are generally just fine, but to be extra
+        safe, you can prime the generator by calling nextInt() on it some (N>1) * 624 times.
+        This method does exactly that, presently with N=2. */
+    public static MersenneTwisterFast primeGenerator(MersenneTwisterFast generator)
+        {
+        for(int i = 0; i < 624 * 2; i++)
+            generator.nextInt();
+        return generator;
+        }
+
+    /** Loads a random generator seed.  First, the seed is loaded from the seedParameter.  If the parameter
+        is V_SEED_TIME, the seed is set to the currentTime value.  Then the seed is incremented by the offset. 
+        This method is broken out of initialize(...) primarily to share code with ec.eval.MasterProblem.*/
+    public static int determineSeed(Output output, ParameterDatabase parameters, Parameter seedParameter, long currentTime, int offset, boolean auto)
+        {
+        int seed = 1;  // have to initialize to make the compiler happy
+        String tmp_s = parameters.getString(seedParameter,null);
+        if (tmp_s==null && !auto) // uh oh
+            {
+            output.fatal("Seed must exist.",seedParameter,null);
+            }
+        else if (V_SEED_TIME.equalsIgnoreCase(tmp_s) || (tmp_s == null && auto))
+            {
+            if (tmp_s == null && auto)
+                output.warnOnce("Using automatic determination number of threads, but not all seeds are defined.\nThe rest will be defined using the wall clock time.");
+            seed = (int)currentTime;  // using low-order bits so it's probably okay
+            if (seed==0)
+                output.fatal("Whoa! This Java version is returning 0 for System.currentTimeMillis(), which ain't right.  This means you can't use '"+V_SEED_TIME+"' as a seed ",seedParameter,null);
+            }
+        else
+            {
+            try
+                {
+                seed = parameters.getInt(seedParameter,null);
+                }
+            catch (NumberFormatException e)
+                {
+                output.fatal("Invalid, non-integer seed value ("+seed+")",seedParameter,null);
+                }
+            }
+        return seed + offset;
+        }
+
+
+    /** Initializes an evolutionary run given the parameters and a random seed adjustment (added to each random seed).
+        The adjustment offers a convenient way to change the seeds of the random number generators each time you
+        do a new evolutionary run.  You are of course welcome to replace the random number generators after initialize(...)
+        but before startFresh(...) */
+                
+    public static EvolutionState initialize(ParameterDatabase parameters, int randomSeedOffset)
+        {
+        Output output;
+        // 1. create the output
+
+        output = new Output(true);
+
+        // stdout is always log #0.  stderr is always log #1.
+        // stderr accepts announcements, and both are fully verbose 
+        // by default.
+        output.addLog(ec.util.Log.D_STDOUT,false);
+        output.addLog(ec.util.Log.D_STDERR,true);
+                
+        // now continue intialization
+        return initialize(parameters, randomSeedOffset, output);
+        }
+
+
+    /** Initializes an evolutionary run given the parameters and a random seed adjustment (added to each random seed),
+        with the Output pre-constructed.
+        The adjustment offers a convenient way to change the seeds of the random number generators each time you
+        do a new evolutionary run.  You are of course welcome to replace the random number generators after initialize(...)
+        but before startFresh(...) */
+                
+    public static EvolutionState initialize(ParameterDatabase parameters, int randomSeedOffset, Output output)
+        {
+        EvolutionState state=null;
+        MersenneTwisterFast[] random;
+        int[] seeds;
+        int breedthreads = 1;
+        int evalthreads = 1;
+        boolean store;
+        int x;
+
+        // output was already created for us.  
+        output.systemMessage(Version.message());
+                
+        // 2. set up thread values
+        
+        breedthreads = Evolve.determineThreads(output, parameters, new Parameter(P_BREEDTHREADS));
+        evalthreads = Evolve.determineThreads(output, parameters, new Parameter(P_EVALTHREADS));
+        boolean auto = (V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(P_BREEDTHREADS),null)) ||
+            V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(P_EVALTHREADS),null)));  // at least one thread is automatic.  Seeds may need to be dynamic.
+
+        // 3. create the Mersenne Twister random number generators,
+        // one per thread
+
+        random = new MersenneTwisterFast[breedthreads > evalthreads ? 
+            breedthreads : evalthreads];
+        seeds = new int[random.length];
+                                                
+        String seedMessage = "Seed: ";
+        int time = (int)(System.currentTimeMillis());
+        for (x=0;x<random.length;x++)
+            {
+            seeds[x] = determineSeed(output,parameters,new Parameter(P_SEED).push(""+x),
+                time+x,random.length * randomSeedOffset, auto);
+            for (int y=0;y<x;y++)
+                if (seeds[x]==seeds[y])
+                    output.fatal(P_SEED+"."+x+" ("+seeds[x]+") and "+P_SEED+"."+y+" ("+seeds[y]+") ought not be the same seed.",null,null); 
+            random[x] = Evolve.primeGenerator(new MersenneTwisterFast(seeds[x]));    // we prime the generator to be more sure of randomness.
+            seedMessage = seedMessage + seeds[x] + " ";
+            }
+
+        // 4.  Start up the evolution
+                
+        // what evolution state to use?
+        state = (EvolutionState)
+            parameters.getInstanceForParameter(new Parameter(P_STATE),null,
+                EvolutionState.class);
+        state.parameters = parameters;
+        state.random = random;
+        state.output = output;
+        state.evalthreads = evalthreads;
+        state.breedthreads = breedthreads;
+        state.randomSeedOffset = randomSeedOffset;
+
+        output.systemMessage("Threads:  breed/" + breedthreads + " eval/" + evalthreads);
+        output.systemMessage(seedMessage);
+                
+        return state;
+        }
+                
+                
+    /** Begins a fresh evolutionary run with a given state.  The state should have been
+        provided by initialize(...).  The jobPrefix is added to the front of output and
+        checkpoint filenames.  If it's null, nothing is added to the front.  */
+        
+    public static void cleanup(EvolutionState state)
+        {
+        // flush the output
+        state.output.flush();
+
+        // Possibly print out the run parameters
+        PrintWriter pw = new PrintWriter(System.err);
+                
+        // before we print out access information, we need to still "get" these
+        // parameters, so that they show up as accessed and gotten.
+        state.parameters.getBoolean(new Parameter(P_PRINTUSEDPARAMETERS),null,false);
+        state.parameters.getBoolean(new Parameter(P_PRINTACCESSEDPARAMETERS),null,false);
+        state.parameters.getBoolean(new Parameter(P_PRINTUNUSEDPARAMETERS),null,false);
+        state.parameters.getBoolean(new Parameter(P_PRINTUNACCESSEDPARAMETERS),null,false);
+        state.parameters.getBoolean(new Parameter(P_PRINTALLPARAMETERS),null,false);
+                
+        //...okay, here we go...
+                
+        if (state.parameters.getBoolean(new Parameter(P_PRINTUSEDPARAMETERS),null,false))
+            {
+            pw.println("\n\nUsed Parameters\n===============\n");
+            state.parameters.listGotten(pw);
+            }
+
+        if (state.parameters.getBoolean(new Parameter(P_PRINTACCESSEDPARAMETERS),null,false))
+            {
+            pw.println("\n\nAccessed Parameters\n===================\n");
+            state.parameters.listAccessed(pw);
+            }
+
+        if (state.parameters.getBoolean(new Parameter(P_PRINTUNUSEDPARAMETERS),null,false))
+            {
+            pw.println("\n\nUnused Parameters\n"+
+                "================= (Ignore parent.x references) \n");
+            state.parameters.listNotGotten(pw);
+            }
+
+        if (state.parameters.getBoolean(new Parameter(P_PRINTUNACCESSEDPARAMETERS),null,false))
+            {
+            pw.println("\n\nUnaccessed Parameters\n"+
+                "===================== (Ignore parent.x references) \n");
+            state.parameters.listNotAccessed(pw);
+            }
+
+        if (state.parameters.getBoolean(new Parameter(P_PRINTALLPARAMETERS),null,false))
+            {
+            pw.println("\n\nAll Parameters\n==============\n");
+            // list only the parameters visible.  Shadowed parameters not shown
+            state.parameters.list(pw,false);
+            }
+
+        pw.flush();
+
+        System.err.flush();
+        System.out.flush();
+                
+        // finish by closing down Output.  This is because gzipped and other buffered
+        // streams just don't shut write themselves out, and finalize isn't called
+        // on them because Java's being obnoxious.  Pretty stupid.
+        state.output.close();
+        }
+
+
+
+
+/*
+
+ * MAIN
+ * 
+ * Evolve has... evolved from previous Evolves.  The goal behind these changes is:
+ *       1. To provide a simple jobs facility
+ *       2. To make it easy for you to make your own main(), including more
+ *          sophisticated jobs facilities.
+ * 
+ * Before we get into the specifics of this file, let's first look at the main
+ * evolution loop in EvolutionState.java.  The general code is:
+ *       1.  If I was loaded from a checkpoint, call the hook startFromCheckpoint()
+ *       2.  If I'm instead starting from scratch, call the hook startFresh() 
+ *       3.  Loop:
+ *               4. result = evolve() 
+ *               5. If result != EvolutionState.R_NOTDONE, break from loop
+ *       6.      Call the hook finish(result)
+ * 
+ * That's all there's to it.  Various EvolutionState classes need to implement
+ * the startFromCheckpoint, startFresh, evolve, and finish methods.  This basic
+ * evolution loop is encapsulated in a convenience method called EvolutionState.run(...).
+ * 
+ * Evolve.java is little more than code to fire up the right EvolutionState class,
+ * call run(...), and then shut down.  The complexity mostly comes from bringing
+ * up the class (loading it from checkpoint or from scratch) and in shutting down.
+ * Here's the general mechanism:
+ * 
+ * - To load from checkpoint, we must find the checkpoint filename and call
+ *       Checkpoint.restoreFromCheckpoint(filename) to generate the EvolutionState
+ *       instance.  Evolve.java provides a convenience function for this called
+ *       possiblyRestoreFromCheckpoint(...), which returns null if there *isn't*
+ *       a checkpoint file to load from.  Else it returns the unfrozen EvolutionState.
+ *       
+ * - To instead set up from scratch, you have to do a bunch of stuff to set up the state.
+ *       First, you need to load a parameter database.  Evolve.java has a convenience function
+ *       for that called loadParameterDatabase(...).  Second, you must do a series
+ *       of items: (1) generate an Output object (2) identify the number of threads
+ *       (3) create the MersenneTwisterFast random number generators (4) instantiate
+ *       the EvolutionState subclass instance (5) plug these items, plus the random 
+ *       seed offset and the parameter database, into the instance.  These five
+ *       steps are done for you in a convenience function called initialize(...).
+ * 
+ * -     Now the state is ready to go. Call run(...) on your EvolutionState
+ *       (or do the evolution loop described above manually if you wish)
+ * 
+ * - Finally, to shut down, you need to (1) flush the Output (2) print out
+ *       the used, accessed, unused, unaccessed, and all parameters if the user
+ *       requested a printout at the end [rarely] (3) flush System.err and System.out
+ *       for good measure, and (4) close Output -- which closes its streams except
+ *       for System.err and System.out.  There is a convenience function for this as
+ *       well.  It's called cleanup(...).
+ *       
+ * - Last, you shut down with System.exit(0) -- very important because it quits
+ *       any remaining threads the user might have had running and forgot about.
+ *       
+ * So there you have it.  Several convenience functions in Evolve...
+ *       Evolve.possiblyRestoreFromCheckpoint
+ *       Evolve.loadParameterDatabase
+ *       Evolve.initialize
+ *       EvolutionState.run
+ *       Evolve.cleanup
+ * ... result in a very simple basic main() function:
+ *       
+ *
+ *               public static void main(String[] args)
+ *                       {
+ *                       EvolutionState state = possiblyRestoreFromCheckpoint(args);
+ *                       if (state!=null)  // loaded from checkpoint
+ *                               state.run(EvolutionState.C_STARTED_FROM_CHECKPOINT);
+ *                       else
+ *                               {
+ *                               state = initialize(loadParameterDatabase(args), 0);
+ *                               state.run(EvolutionState.C_STARTED_FRESH);
+ *                               }
+ *                       cleanup(state);
+ *                       System.exit(0);
+ *                       }
+ *
+ *
+ * Piece of cake!
+ * 
+ * The more extravagant main(...) you see below just has a few extra gizmos for
+ * doing basic job iteration.  EvolutionState has two convenience slots for
+ * doing job iteration:
+ *
+ *       job                                     (an Object[]    use this as you like)
+ *       runtimeArguments        (a String[]             put args in here)
+ *
+ * The reason these are slots in EvolutionState is so you can store this information
+ * across checkpoints and continue where you had started job-number-wise when the
+ * user starts up from a checkpoint again.
+ * 
+ * You'll probably want the EvolutionState to output its stat files etc. using unique
+ * prefixes to differentiate between jobs (0.stat, 1.stat, or whatever you like -- it
+ * doesn't have to be numbers), and you'll also probably want checkpoint files to be
+ * similarly prefixed.  So you'll probably want to do:
+ *
+ *       state.output.setFilePrefix(jobPrefix);
+ *       state.checkpointPrefix = jobPrefix + state.checkpointPrefix;
+ *
+ * The extravagant main below is basically doing this.  We're using state.job to stash
+ * away a single iterated job number, stored as an Integer in state.job[0], and then
+ * iterating that way, making sure we stash the job number and runtime arguments each time 
+ * so we can recover them when loading from checkpoint.  We use the "jobs" parameter 
+ * to determine how many jobs to run.  If this number is 1, we don't even bother to set
+ * the file prefixes, so ECJ generates files just like it used to.
+ *
+ * It's important to note that this main was created with the assumption that you might
+ * modify it for your own purposes.  Do you want a nested loop, perhaps to do all combinations
+ * of two parameters or something?  Rewrite it to use two array slots in the job array.
+ * Want to store more information on a per-job basis?  Feel free to use the job array any
+ * way you like -- it's ONLY used by this main() loop.
+ *
+ */
+
+
+
+
+
+
+    /** Top-level evolutionary loop.  */
+
+    public static void main(String[] args)
+        {
+        EvolutionState state;
+        ParameterDatabase parameters;
+                
+        // if we're loading from checkpoint, let's finish out the most recent job
+        state = possiblyRestoreFromCheckpoint(args);
+        int currentJob = 0;                             // the next job number (0 by default)
+
+        // this simple job iterator just uses the 'jobs' parameter, iterating from 0 to 'jobs' - 1
+        // inclusive.  The current job number is stored in state.jobs[0], so we'll begin there if
+        // we had loaded from checkpoint.
+                
+        if (state != null)  // loaded from checkpoint
+            {
+            // extract the next job number from state.job[0] (where in this example we'll stash it)
+            try
+                {
+                if (state.runtimeArguments == null)
+                    Output.initialError("Checkpoint completed from job started by foreign program (probably GUI).  Exiting...");
+                args = state.runtimeArguments;                          // restore runtime arguments from checkpoint
+                currentJob = ((Integer)(state.job[0])).intValue() + 1;  // extract next job number
+                }
+            catch (Exception e)
+                {
+                Output.initialError("EvolutionState's jobs variable is not set up properly.  Exiting...");
+                }
+
+            state.run(EvolutionState.C_STARTED_FROM_CHECKPOINT);
+            cleanup(state);
+            }
+
+        // A this point we've finished out any previously-checkpointed job.  If there was
+        // one such job, we've updated the current job number (currentJob) to the next number.
+        // Otherwise currentJob is 0.
+
+        // Now we're going to load the parameter database to see if there are any more jobs.
+        // We could have done this using the previous parameter database, but it's no big deal.
+        parameters = loadParameterDatabase(args);
+        if (currentJob == 0)  // no current job number yet
+            currentJob = parameters.getIntWithDefault(new Parameter("current-job"), null, 0);
+        if (currentJob < 0)
+            Output.initialError("The 'current-job' parameter must be >= 0 (or not exist, which defaults to 0)");
+            
+        int numJobs = parameters.getIntWithDefault(new Parameter("jobs"), null, 1);
+        if (numJobs < 1)
+            Output.initialError("The 'jobs' parameter must be >= 1 (or not exist, which defaults to 1)");
+                
+                
+        // Now we know how many jobs remain.  Let's loop for that many jobs.  Each time we'll
+        // load the parameter database scratch (except the first time where we reuse the one we
+        // just loaded a second ago).  The reason we reload from scratch each time is that the
+        // experimenter is free to scribble all over the parameter database and it'd be nice to
+        // have everything fresh and clean.  It doesn't take long to load the database anyway,
+        // it's usually small.
+        for(int job = currentJob ; job < numJobs; job++)
+            {
+            try
+                {
+                // load the parameter database (reusing the very first if it exists)
+                if (parameters == null)
+                    parameters = loadParameterDatabase(args);
+                            
+                // Initialize the EvolutionState, then set its job variables
+                state = initialize(parameters, job);                // pass in job# as the seed increment
+                state.output.systemMessage("Job: " + job);
+                state.job = new Object[1];                                  // make the job argument storage
+                state.job[0] = new Integer(job);                    // stick the current job in our job storage
+                state.runtimeArguments = args;                              // stick the runtime arguments in our storage
+                if (numJobs > 1)                                                    // only if iterating (so we can be backwards-compatible),
+                    {
+                    String jobFilePrefix = "job." + job + ".";
+                    state.output.setFilePrefix(jobFilePrefix);     // add a prefix for checkpoint/output files 
+                    state.checkpointPrefix = jobFilePrefix + state.checkpointPrefix;  // also set up checkpoint prefix
+                    }
+                                    
+                // Here you can set up the EvolutionState's parameters further before it's setup(...).
+                // This includes replacing the random number generators, changing values in state.parameters,
+                // changing instance variables (except for job and runtimeArguments, please), etc.
+
+
+
+
+
+                // now we let it go
+                state.run(EvolutionState.C_STARTED_FRESH);
+                cleanup(state);  // flush and close various streams, print out parameters if necessary
+                parameters = null;  // so we load a fresh database next time around
+                }
+            catch (Throwable e)  // such as an out of memory error caused by this job
+                {
+                e.printStackTrace();
+                state = null;
+                System.gc();  // take a shot!
+                }
+            }
+
+        System.exit(0);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Exchanger.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Exchanger.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Exchanger.java	(revision 6152)
@@ -0,0 +1,59 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * Exchanger.java
+ * 
+ * Created: Tue Aug 10 21:59:17 1999
+ * By: Sean Luke
+ */
+
+/**
+ * The Exchanger is a singleton object whose job is to (optionally)
+ * perform individual exchanges between subpopulations in the run,
+ * or exchange individuals with other concurrent evolutionary run processes,
+ * using sockets or whatever.  Keep in mind that other processes may go down,
+ * or be started up from checkpoints, etc.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class Exchanger implements Singleton
+    {
+    /** Initializes contacts with other processes, if that's what you're doing. Called at the beginning of an evolutionary run, before a population is set up. */
+    public void initializeContacts(EvolutionState state) { }
+
+    /** Initializes contacts with other processes, if that's what you're doing.  Called after restarting from a checkpoint. */
+    public void reinitializeContacts(EvolutionState state) { }
+
+    /** Performs exchanges after the population has been evaluated but before it has been bred,
+        once every generation (or pseudogeneration). */
+    public abstract Population preBreedingExchangePopulation(EvolutionState state);
+
+    /** Performs exchanges after the population has been bred but before it has been evaluated,
+        once every generation (or pseudogeneration). */
+    public abstract Population postBreedingExchangePopulation(EvolutionState state);
+
+    /** Called after preBreedingExchangePopulation(...) to evaluate whether or not
+        the exchanger wishes the run to shut down (with ec.EvolutionState.R_FAILURE) --
+        returns a String (which will be printed out as a message) if the exchanger
+        wants to shut down, else returns null if the exchanger does NOT want to shut down.
+        Why would you want to shut down?
+        This would happen for two reasons.  First, another process might have found
+        an ideal individual and the global run is now over.  Second, some network
+        or operating system error may have occurred and the system needs to be shut
+        down gracefully.  Note that if the exchanger wants to shut down, the system
+        will shut down REGARDLESS of whether or not the user stated 
+        ec.EvolutionState.quitOnRunComplete. */
+    public abstract String runComplete(EvolutionState state);
+
+    /** Closes contacts with other processes, if that's what you're doing.  Called at the end of an evolutionary run. result is either ec.EvolutionState.R_SUCCESS or ec.EvolutionState.R_FAILURE, indicating whether or not an ideal individual was found. */
+    public void closeContacts(EvolutionState state, int result) { }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Finisher.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Finisher.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Finisher.java	(revision 6152)
@@ -0,0 +1,31 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * Finisher.java
+ * 
+ * Created: Tue Aug 10 21:09:18 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Finisher is a singleton object which is responsible for cleaning up a
+ * population after a run has completed.  This is typically done after
+ * final statistics have been performed but before the exchanger's
+ * contacts have been closed.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class Finisher implements Singleton
+    {
+    /** Cleans up the population after the run has completed. result is either ec.EvolutionState.R_SUCCESS or ec.EvolutionState.R_FAILURE, indicating whether or not an ideal individual was found. */
+    public abstract void finishPopulation(EvolutionState state, int result);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Fitness.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Fitness.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Fitness.java	(revision 6152)
@@ -0,0 +1,249 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import java.io.*;
+import ec.util.*;
+
+/*
+ * Fitness.java
+ *
+ * Created: Tue Aug 10 20:10:42 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Fitness is a prototype which describes the fitness of an individual.
+ * Every individual contains exactly one Fitness object.
+ * Fitness objects are compared to each other with the equivalentTo()
+ * and betterThan(), etc. methods. 
+ *
+ <p>Rules: 
+ <table>
+ <tr><td><b>comparison</b></td><td><b>method</b></td></tr>
+ <tr><td>a &gt; b</td><td>a.betterThan(b)</td>
+ <tr><td>a &gt;= b</td><td>a.betterThan(b) || a.equivalentTo(b)</td>
+ <tr><td>a = b</td><td>a.equivalentTo(b)</td>
+ </table>
+
+ This applies even to multiobjective pareto-style dominance, eg:
+ <ul>
+ <li> a dominates b :: a &gt; b
+ <li> a and b do not dominate each other :: a = b
+ <li> b dominates a :: a &lt; b
+ </ul>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+
+ <tr><td valign=top><tt>fit</tt></td>
+ <td>default fitness base</td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+
+public abstract class Fitness implements Prototype, Comparable
+    {
+    /** Auxiliary variable, used by coevolutionary processes, to compute the
+        number of trials used to compute this Fitness value.  By default trials=1. */
+    public int trials = 1;
+        
+    /** base parameter for defaults */
+    public static final String P_FITNESS = "fitness";
+
+    /** Basic preamble for printing Fitness values out */
+    public static final String FITNESS_PREAMBLE = "Fitness: ";
+
+    /** Should return an absolute fitness value ranging from negative
+        infinity to infinity, NOT inclusive (thus infinity, negative
+        infinity, and NaN are NOT valid fitness values).  This should
+        be interpreted as: negative infinity is worse than the WORST
+        possible fitness, and positive infinity is better than the IDEAL
+        fitness.
+        
+        <p>You are free to restrict this range any way you like: for example,
+        your fitness values might fall in the range [-5.32, 2.3]
+        
+        <p>Selection methods relying on fitness proportionate information will
+        <b>assume the fitness is non-negative</b> and should throw an error
+        if it is not.  Thus if you plan on using FitProportionateSelection, 
+        BestSelection, or
+        GreedyOverselection, for example, your fitnesses should assume that 0
+        is the worst fitness and positive fitness are better.  If you're using
+        other selection methods (Tournament selection, various ES selection
+        procedures, etc.) your fitness values can be anything.
+        
+        <p>Similarly, if you're writing a selection method and it needs positive
+        fitnesses, you should check for negative values and issue an error; and
+        if your selection method doesn't need an <i>absolute</i> fitness
+        value, it should use the equivalentTo() and betterThan() methods instead.
+        
+        <p> If your fitness scheme does not use a metric quantifiable to
+        a single positive value (for example, MultiObjectiveFitness), you should 
+        perform some reasonable translation.
+    */
+    public abstract float fitness();
+
+    /** Should return true if this is a good enough fitness to end the run */
+    public abstract boolean isIdealFitness();
+
+    /** Should return true if this fitness is in the same equivalence class
+        as _fitness, that is, neither is clearly better or worse than the
+        other.  You may assume that _fitness is of the same class as yourself.
+        For any two fitnesses fit1 and fit2 of the same class,
+        it must be the case that fit1.equivalentTo(fit2) == fit2.equivalentTo(fit1),
+        and that only one of fit1.betterThan(fit2), fit1.equivalentTo(fit2),
+        and fit2.betterThan(fit1) can be true.
+    */
+    public abstract boolean equivalentTo(Fitness _fitness);
+    
+    /** Should return true if this fitness is clearly better than _fitness;
+        You may assume that _fitness is of the same class as yourself. 
+        For any two fitnesses fit1 and fit2 of the same class,
+        it must be the case that fit1.equivalentTo(fit2) == fit2.equivalentTo(fit1),
+        and that only one of fit1.betterThan(fit2), fit1.equivalentTo(fit2),
+        and fit2.betterThan(fit1) can be true.
+    */ 
+    public abstract boolean betterThan(Fitness _fitness);
+
+    /** Should print the fitness out fashion pleasing for humans to read, 
+        with a verbosity of Output.V_NO_GENERAL.
+    */
+    public void printFitnessForHumans(EvolutionState state, int log)
+        {
+        printFitnessForHumans( state, log, Output.V_NO_GENERAL);
+        }
+
+    /** Should print the fitness out fashion pleasing for humans to read, 
+        using state.output.println(...,verbosity,log).  The default version
+        of this method calls fitnessToStringForHumans() and println's the
+        resultant string.
+        @deprecated Verbosity no longer has meaning
+    */
+    public void printFitnessForHumans(EvolutionState state, int log, 
+        int verbosity)
+        {
+        state.output.println( fitnessToStringForHumans(), verbosity, log);
+        }
+
+    /** Should print the fitness out in a computer-readable fashion, 
+        with a verbosity of Output.V_NO_GENERAL.
+    */
+    public void printFitness(EvolutionState state, int log)
+        {
+        printFitness( state, log, Output.V_NO_GENERAL);
+        }
+
+    /** Should print the fitness out in a computer-readable fashion, 
+        using state.output.println(...,verbosity,log).  You might use
+        ec.util.Code to encode fitness values.  The default version
+        of this method calls fitnessToString() and println's the
+        resultant string.
+        @deprecated Verbosity no longer has meaning
+    */
+    public void printFitness(EvolutionState state, int log, 
+        int verbosity)
+        {
+        state.output.println( fitnessToString(), verbosity, log);
+        }
+    
+    /** Should print the fitness out in a computer-readable fashion, 
+        using writer.println(...).  You might use
+        ec.util.Code to encode fitness values.  The default version
+        of this method calls fitnessToString() and println's the
+        resultant string.
+    */
+    public void printFitness(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println( fitnessToString() );
+        }
+
+    /** Reads in the fitness from a form outputted by fitnessToString() and thus
+        printFitnessForHumans(...).  The default version of this method
+        exits the program with an "unimplemented" error. */ 
+    public void readFitness(final EvolutionState state, 
+        final LineNumberReader reader)
+        throws IOException
+        {
+        state.output.fatal("readFitness(EvolutionState, DataOutput)  not implemented in " + this.getClass());
+        }
+        
+    /** Print to a string the fitness in a fashion readable by humans, and not intended
+        to be parsed in again.  The default form
+        simply calls toString(), but you'll probably want to override this to something else. */
+    public String fitnessToStringForHumans()
+        {
+        return toString();
+        }
+        
+    /** Print to a string the fitness in a fashion intended
+        to be parsed in again via readFitness(...).
+        The fitness and evaluated flag should not be included.  The default form
+        simply calls toString(), which is almost certainly wrong, 
+        and you'll probably want to override this to something else. */
+    public String fitnessToString()
+        {
+        return toString();
+        }
+        
+    /** Writes the binary form of an individual out to a DataOutput.  This is not for serialization:
+        the object should only write out the data relevant to the object sufficient to rebuild it from a DataInput.
+        The default version exits the program with an "unimplemented" error; you should override this.
+    */
+    public void writeFitness(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        state.output.fatal("writeFitness(EvolutionState, DataOutput) not implemented in " + this.getClass());
+        }
+
+
+    /** Reads the binary form of an individual from a DataInput.  This is not for serialization:
+        the object should only read in the data written out via printIndividual(state,dataInput).  
+        The default version exits the program with an "unimplemented" error; you should override this.
+    */
+    public void readFitness(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        state.output.fatal("readFitness(EvolutionState, DataOutput) not implemented in " + this.getClass());
+        }
+
+    public Object clone()
+        {
+        try { return super.clone(); }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+
+    public void setup(EvolutionState state, Parameter base)
+        {
+        // by default does nothing
+        }
+
+    /**
+       Returns -1 if I am FITTER than the other Fitness, 1 if I am LESS FIT than the other Fitness,
+       and 0 if we are equivalent.
+    */
+    public int compareTo(Object o)
+        {
+        Fitness other = (Fitness) o;
+        if (this.betterThan(other)) return -1;
+        if (other.betterThan(this)) return 1;
+        return 0;
+        }
+        
+    /** Sets the fitness to be the same value as the mean of the provided fitnesses.  The default
+        version of this method exits with an "unimplemented" error; you should override this. */
+    public void setToMeanOf(EvolutionState state, Fitness[] fitnesses)
+        {
+        state.output.fatal("setToMeanOf(EvolutionState, Fitness[]) not implemented in " + this.getClass());
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/Group.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Group.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Group.java	(revision 6152)
@@ -0,0 +1,45 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * Group.java
+ * 
+ * Created: Tue Aug 10 20:49:45 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Groups are used for populations and subpopulations.  They are slightly
+ * different from Prototypes in a few important ways.
+ *
+ * A Group instance typically is set up with setup(...) and then <i>used</i>
+ * (unlike in a Prototype, where the prototype instance is never used, 
+ * but only makes clones
+ * which are used).  When a new Group instance is needed, it is created by
+ * calling emptyClone() on a previous Group instance, which returns a
+ * new instance set up exactly like the first Group instance had been set up
+ * when setup(...) was called on it.
+ *
+ * Groups are Serializable and Cloneable, but you should not clone
+ * them -- use emptyClone instead.
+ *
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface Group extends Setup, Cloneable
+    {
+    /** Returns a copy of the object just as it had been 
+        immediately after Setup was called on it (or on
+        an ancestor object).  You can obtain a fresh instance
+        using clone(), and then modify that.
+    */
+    public Group emptyClone();
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Individual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Individual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Individual.java	(revision 6152)
@@ -0,0 +1,383 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.Parameter;
+import java.io.*;
+import ec.util.*;
+
+/*
+ * Individual.java
+ * Created: Tue Aug 10 19:58:13 1999
+ */
+
+/**
+ * An Individual is an item in the EC population stew which is evaluated 
+ * and assigned a fitness which determines its likelihood of selection.
+ * Individuals are created most commonly by the newIndividual(...) method
+ * of the ec.Species class.
+ *
+ * <P>In general Individuals are immutable.  That is, once they are created
+ * their genetic material should not be modified.  This protocol helps insure that they are
+ * safe to read under multithreaded conditions.  You can violate this protocol,
+ * but try to do so when you know you have only have a single thread.
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b>reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString<b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans<b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+ *
+ * <p>Since individuals should be largely immutable, why is there a <b>readIndividual</b> method?
+ * after all this method doesn't create a <i>new</i> individual -- it just erases the existing one.  This is
+ * largely historical; but the method is used underneath by the various <b>newIndividual</b> methods in Species,
+ * which <i>do</i> create new individuals read from files.  If you're trying to create a brand new individual
+ * read from a file, look in Species.
+ *
+ * <p> Individuals are Comparable: if you sort Individuals, the FITTER individuals will appear EARLIER in a list or array.
+ *
+ *
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public abstract class Individual implements Prototype, Comparable
+    {
+    /** A reasonable parameter base element for individuals*/
+    public static final String P_INDIVIDUAL = "individual";
+
+    /** A string appropriate to put in front of whether or not the individual has been printed. */
+    public static final String EVALUATED_PREAMBLE = "Evaluated: ";
+    
+    /** The fitness of the Individual. */
+    public Fitness fitness;
+
+    /** The species of the Individual.*/
+    public Species species;
+    
+    public static int count = 0;
+    /** Has the individual been evaluated and its fitness determined yet? */
+    public boolean evaluated;
+        
+    public int birthday = (count++);
+
+    public Object clone()
+        {
+        try 
+            { 
+            Individual myobj = (Individual) (super.clone());
+            if (myobj.fitness != null) myobj.fitness = (Fitness)(fitness.clone());
+            return myobj; 
+            }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+
+   
+    /** Returns the "size" of the individual.  This is used for things like
+        parsimony pressure.  The default form of this method returns 0 --
+        if you care about parsimony pressure, you'll need to override the
+        default to provide a more descriptive measure of size. */
+
+    public long size() { return 0; }
+
+    /** Returns true if I am genetically "equal" to ind.  This should
+        mostly be interpreted as saying that we are of the same class
+        and that we hold the same data. It should NOT be a pointer comparison. */
+    public abstract boolean equals(Object ind);
+
+    /** Returns a hashcode for the individual, such that individuals which
+        are equals(...) each other always return the same
+        hash code. */
+    public abstract int hashCode();
+
+    /** This should be used to set up only those things which you share in common
+        with all other individuals in your species; individual-specific items
+        which make you <i>you</i> should be filled in by Species.newIndividual(...),
+        and modified by breeders. 
+        @see Prototype#setup(EvolutionState,Parameter)
+    */
+    
+    /** Overridden here because hashCode() is not expected to return the pointer
+        to the object.  toString() normally uses hashCode() to print a unique identifier,
+        and that's no longer the case.   You're welcome to override this anyway you 
+        like to make the individual print out in a more lucid fashion. */
+    public String toString()
+        {
+        return "" + this.getClass().getName() + "@" + 
+            System.identityHashCode(this) + "{" + hashCode() + "}";
+        }
+        
+    /** Print to a string the genotype of the Individual in a fashion readable by humans, and not intended
+        to be parsed in again.  The fitness and evaluated flag should not be included.  The default form
+        simply calls toString(), but you'll probably want to override this to something else. */
+    public String genotypeToStringForHumans()
+        {
+        return toString();
+        }
+        
+    /** Print to a string the genotype of the Individual in a fashion intended
+        to be parsed in again via parseGenotype(...).
+        The fitness and evaluated flag should not be included.  The default form
+        simply calls toString(), which is almost certainly wrong, and you'll probably want to override
+        this to something else. */
+    public String genotypeToString()
+        {
+        return toString();
+        }
+              
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // does nothing by default.
+        // So where is the species set?  The Species does so after it
+        // loads me but before it calls setup on me.
+        }
+
+    /** Should print the individual out in a pleasing way for humans,
+        with a verbosity of Output.V_NO_GENERAL.
+    */
+
+    public void printIndividualForHumans(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(EVALUATED_PREAMBLE + Code.encode(evaluated), log);
+        fitness.printFitnessForHumans(state,log);
+        state.output.println( genotypeToStringForHumans(), log );
+        }
+                
+    /** Should print the individual out in a pleasing way for humans,
+        including its
+        fitness, using state.output.println(...,verbosity,log)
+        You can get fitness to print itself at the appropriate time by calling 
+        fitness.printFitnessForHumans(state,log,verbosity);
+                
+        <p>The default form of this method simply prints out whether or not the
+        individual has been evaluated, its fitness, and then calls Individual.genotypeToStringForHumans().
+        Feel free to override this to produce more sophisticated behavior, 
+        though it is rare to need to -- instead you could just override genotypeToStringForHumans().
+        @deprecated Verbosity no longer used.
+    */
+
+    public final void printIndividualForHumans(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        printIndividualForHumans(state, log);
+        }
+
+    /** Should print the individual in a way that can be read by computer,
+        including its fitness, with a verbosity of Output.V_NO_GENERAL.
+    */
+
+    public void printIndividual(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(EVALUATED_PREAMBLE + Code.encode(evaluated), log);
+        fitness.printFitness(state,log);
+        state.output.println( genotypeToString(), log );
+        }
+
+
+    /** Should print the individual in a way that can be read by computer,
+        including its fitness, using state.output.println(...,verbosity,log)
+        You can get fitness to print itself at the appropriate time by calling 
+        fitness.printFitness(state,log,verbosity);
+                
+        <p>The default form of this method simply prints out whether or not the
+        individual has been evaluated, its fitness, and then calls Individual.genotypeToString().
+        Feel free to override this to produce more sophisticated behavior, 
+        though it is rare to need to -- instead you could just override genotypeToString().
+        @deprecated Verbosity no longer used.
+    */
+
+    public final void printIndividual(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        printIndividual( state, log,  Output.V_NO_GENERAL);
+        }
+
+    /** Should print the individual in a way that can be read by computer,
+        including its fitness.  You can get fitness to print itself at the
+        appropriate time by calling fitness.printFitness(state,log,writer); 
+        Usually you should try to use printIndividual(state,log,verbosity)
+        instead -- use this method only if you can't print through the 
+        Output facility for some reason.
+
+        <p>The default form of this method simply prints out whether or not the
+        individual has been evaluated, its fitness, and then calls Individual.genotypeToString().
+        Feel free to override this to produce more sophisticated behavior, 
+        though it is rare to need to -- instead you could just override genotypeToString().
+    */
+
+    public void printIndividual(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println(EVALUATED_PREAMBLE + Code.encode(evaluated));
+        fitness.printFitness(state,writer);
+        writer.println( genotypeToString() );
+        }
+
+    /** Reads in the individual from a form printed by printIndividual(), erasing the previous
+        information stored in this Individual.  If you are trying to <i>create</i> an Individual
+        from information read in from a stream or DataInput,
+        see the various newIndividual() methods in Species. The default form of this method
+        simply reads in evaluation information, then fitness information, and then 
+        calls parseGenotype() (which you should implement).  The Species is not changed or
+        attached, so you may need to do that elsewhere.  Feel free to override 
+        this method to produce more sophisticated behavior, 
+        though it is rare to need to -- instead you could just override parseGenotype(). */ 
+
+    public void readIndividual(final EvolutionState state, 
+        final LineNumberReader reader)
+        throws IOException
+        {
+        evaluated = Code.readBooleanWithPreamble(EVALUATED_PREAMBLE, state, reader);
+        
+        // Next, what's my fitness?
+        fitness.readFitness(state,reader);
+
+        // next, read me in
+        parseGenotype(state, reader);
+        }
+
+    /** This method is used only by the default version of readIndividual(state,reader),
+        and it is intended to be overridden to parse in that part of the individual that
+        was outputted in the genotypeToString() method.  The default version of this method
+        exits the program with an "unimplemented" error.  You'll want to override this method,
+        or to override readIndividual(...) to not use this method. */
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        state.output.fatal("parseGenotype(EvolutionState, LineNumberReader) not implemented in " + this.getClass());
+        }
+        
+    /** Writes the binary form of an individual out to a DataOutput.  This is not for serialization:
+        the object should only write out the data relevant to the object sufficient to rebuild it from a DataInput.
+        The Species will be reattached later, and you should not write it.   The default version of this
+        method writes the evaluated and fitness information, then calls writeGenotype() to write the genotype
+        information.  Feel free to override this method to produce more sophisticated behavior, 
+        though it is rare to need to -- instead you could just override writeGenotype(). 
+    */
+    public void writeIndividual(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeBoolean(evaluated);
+        fitness.writeFitness(state,dataOutput);
+        writeGenotype(state,dataOutput);
+        }
+    
+    
+    /** Writes the genotypic information to a DataOutput.  Largely called by writeIndividual(), and
+        nothing else.  The default simply throws an error.  Various subclasses of Individual override this as
+        appropriate. For example, if your custom individual's genotype consists of an array of 
+        integers, you might do this:
+
+        * <pre><tt>
+        * dataOutput.writeInt(integers.length);
+        * for(int x=0;x<integers.length;x++)
+        *     dataOutput.writeInt(integers[x]);
+        * </tt></pre>
+        */ 
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        state.output.fatal("writeGenotype(EvolutionState, DataOutput) not implemented in " + this.getClass());
+        }
+
+    /** Reads in the genotypic information from a DataInput, erasing the previous genotype
+        of this Individual.  Largely called by readIndividual(), and nothing else.  
+        If you are trying to <i>create</i> an Individual
+        from information read in from a stream or DataInput,
+        see the various newIndividual() methods in Species.
+        The default simply throws an error.  Various subclasses of Individual override this as
+        appropriate.  For example, if your custom individual's genotype consists of an array of 
+        integers, you might do this:
+        
+        * <pre><tt>
+        * integers = new int[dataInput.readInt()];
+        * for(int x=0;x<integers.length;x++)
+        *     integers[x] = dataInput.readInt();
+        * </tt></pre>
+        */
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        state.output.fatal("readGenotype(EvolutionState, DataOutput) not implemented in " + this.getClass());
+        }
+
+    /** Reads the binary form of an individual from a DataInput, erasing the previous
+        information stored in this Individual.  This is not for serialization:
+        the object should only read in the data written out via printIndividual(state,dataInput).  
+        If you are trying to <i>create</i> an Individual
+        from information read in from a stream or DataInput,
+        see the various newIndividual() methods in Species. The default form of this method
+        simply reads in evaluation information, then fitness information, and then 
+        calls readGenotype() (which you will need to override -- its default form simply throws an error).
+        The Species is not changed or attached, so you may need to do that elsewhere.  Feel free to override 
+        this method to produce more sophisticated behavior, though it is rare to need to -- instead you could
+        just override readGenotype().
+    */
+    public void readIndividual(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        evaluated = dataInput.readBoolean();
+        fitness.readFitness(state,dataInput);
+        readGenotype(state,dataInput);
+        }
+    
+    /** Returns the metric distance to another individual, if such a thing can be measured.
+        Subclassess of Individual should implement this if it exists for their representation.
+        The default implementation here, which isn't very helpful, returns 0 if the individuals are equal
+        and infinity if they are not.
+    */
+
+    public double distanceTo(Individual otherInd)
+        {
+        return (equals(otherInd) ? 0 : Double.POSITIVE_INFINITY);
+        }
+
+    /**
+       Returns -1 if I am BETTER in some way than the other Individual, 1 if the other Individual is BETTER than me,
+       and 0 if we are equivalent.  The default implementation assumes BETTER means FITTER, by simply calling
+       compareTo on the fitnesses themse.ves
+    */
+    public int compareTo(Object o)
+        {
+        Individual other = (Individual) o;
+        return fitness.compareTo(other.fitness);
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/Initializer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Initializer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Initializer.java	(revision 6152)
@@ -0,0 +1,52 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * Initializer.java
+ * 
+ * Created: Tue Aug 10 21:07:42 1999
+ * By: Sean Luke
+ */
+
+/**
+ * The Initializer is a singleton object whose job is to initialize the
+ * population at the beginning of the run.  It does this by providing
+ * a population through the initialPopulation(...) method.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt>pop</tt><br>
+ <font size=-1>classname, inherits or = ec.Population</font></td>
+ <td valign=top>(the class for a new population)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><tt>pop</tt></td>
+ <td>The base for a new population's set up parameters</td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class Initializer implements Singleton
+    {
+    /** parameter for a new population */
+    public static final String P_POP = "pop";
+
+    /** Creates and returns a new initial population for the evolutionary run.
+        This is commonly done by setting up a Population (by calling setupPopulation below)
+        then calling its populate() method.  This method
+        will likely only be called once in a run. */
+    public abstract Population initialPopulation(final EvolutionState state, int thread);
+        
+    /** Loads a Population from the parameter file, sets it up, and returns it. */
+    public abstract Population setupPopulation(final EvolutionState state, int thread); 
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Population.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Population.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Population.java	(revision 6152)
@@ -0,0 +1,231 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * Population.java
+ * 
+ * Created: Tue Aug 10 20:50:54 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A Population is the repository for all the Individuals being bred or
+ * evaluated in the evolutionary run at a given time.
+ * A Population is basically an array of Subpopulations, each of which
+ * are arrays of Individuals coupled with a single Species per Subpoulation.
+ *
+ * <p>The first Population is created using the initializePopulation method
+ * of the Initializer object, which typically calls the Population's
+ * populate() method in turn.  On generational systems, subsequent populations
+ * are created on a generation-by-generation basis by the Breeder object,
+ * replacing the previous Population.
+ *
+ * <p>In a multithreaded area of a run, Populations should be considered
+ * immutable.  That is, once they are created, they should not be modified,
+ * nor anything they contain.  This protocol helps ensure read-safety under
+ * multithreading race conditions.
+ *
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>subpops</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the number of subpopulations)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>subpop</tt><i>.n</i><br>
+ <font size=-1>classname, inherits or = ec.Subpopulation</font></td>
+ <td valign=top>(the class for subpopulation #<i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>default-subpop</tt><br>
+ <font size=-1>classname, inherits or = ec.Subpopulation</font></td>
+ <td valign=top>(the class for subpopulation #<i>n</i> if it wasn't specified with <i>base.</i><tt>subpop</tt><i>.n</i>.  
+ Don't use this except in unusual circumstances.  The parameter base is still <i>base.</i><tt>subpop</tt><i>.n</i>.</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>subpop</tt><i>.n</i></td>
+ <td>Subpopulation #<i>n</i>.</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Population implements Group
+    {
+    public Subpopulation[] subpops;
+    public static final String P_SIZE = "subpops";
+    public static final String P_SUBPOP = "subpop";
+    public static final String P_DEFAULT_SUBPOP = "default-subpop";
+    public static final String NUM_SUBPOPS_PREAMBLE = "Number of Subpopulations: ";
+    public static final String SUBPOP_INDEX_PREAMBLE = "Subpopulation Number: ";
+
+
+    /** Returns an instance of Population just like it had been before it was
+        populated with individuals. You may need to override this if you override
+        Population. <b>IMPORTANT NOTE</b>: if the size of the array in
+        Population has been changed, then the clone will take on the new array
+        size.  This helps some evolution strategies.
+        @see Group#emptyClone()
+    */
+
+    public Group emptyClone()
+        {
+        try
+            {
+            Population p = (Population)clone();
+            p.subpops = new Subpopulation[subpops.length];
+            for(int x=0;x<subpops.length;x++)
+                p.subpops[x] = (Subpopulation)(subpops[x].emptyClone());
+            return p;   
+            }
+        catch (CloneNotSupportedException e) { throw new InternalError(); } // never happens
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // how big should subpops be?  Don't have a default base
+
+        Parameter p;
+
+        p = base.push(P_SIZE);
+        int size = state.parameters.getInt(p,null,1);
+        if (size==0) // uh oh
+            state.output.fatal("Population size must be >0.\n",base.push(P_SIZE));
+        subpops = new Subpopulation[size];
+
+        // Load the subpopulations
+        for (int x=0;x<size;x++)
+            {
+            p = base.push(P_SUBPOP).push(""+x);
+            if (!state.parameters.exists(p,null))
+                {
+                p = base.push(P_DEFAULT_SUBPOP);
+                if (state.parameters.exists(p, null))
+                    {
+                    state.output.warning("Class for subpopulation " + x + " not specified, using provided default: " + state.parameters.getString(p, null));
+                    }
+                // else an error will occur on the next line anyway.
+                }
+            subpops[x] = (Subpopulation)(state.parameters.getInstanceForParameterEq(p,null,Subpopulation.class));  // Subpopulation.class is fine
+            subpops[x].setup(state,p);
+            }
+        }
+
+    /** Populates the population with new random individuals. */ 
+    public void populate(EvolutionState state, int thread)
+        {
+        // let's populate!
+        for(int x=0;x<subpops.length;x++)
+            subpops[x].populate(state, thread);
+        }
+        
+        
+    /** Prints an entire population in a form readable by humans. 
+        @deprecated Verbosity no longer has meaning
+    */
+    public final void printPopulationForHumans(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        printPopulationForHumans(state, log);
+        }
+        
+    /** Prints an entire population in a form readable by humans but also parseable by the computer using readPopulation(EvolutionState, LineNumberReader).
+        @deprecated Verbosity no longer has meaning
+    */
+    public final void printPopulation(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        printPopulation(state, log);
+        }
+        
+    /** Prints an entire population in a form readable by humans, with a verbosity of Output.V_NO_GENERAL. */
+    public void printPopulationForHumans(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(NUM_SUBPOPS_PREAMBLE + subpops.length,  log);
+        for(int i = 0 ; i < subpops.length; i++)
+            {
+            state.output.println(SUBPOP_INDEX_PREAMBLE + i,  log);
+            subpops[i].printSubpopulationForHumans(state, log);
+            }
+        }
+        
+    /** Prints an entire population in a form readable by humans but also parseable by the computer using readPopulation(EvolutionState, LineNumberReader), with a verbosity of Output.V_NO_GENERAL. */
+    public void printPopulation(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(NUM_SUBPOPS_PREAMBLE + Code.encode(subpops.length),  log);
+        for(int i = 0 ; i < subpops.length; i++)
+            {
+            state.output.println(SUBPOP_INDEX_PREAMBLE + Code.encode(i),  log);
+            subpops[i].printSubpopulation(state, log);
+            }
+        }
+        
+    /** Prints an entire population in a form readable by humans but also parseable by the computer using readPopulation(EvolutionState, LineNumberReader). */
+    public void printPopulation(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println(NUM_SUBPOPS_PREAMBLE + Code.encode(subpops.length));
+        for(int i = 0 ; i < subpops.length; i++)
+            {
+            writer.println(SUBPOP_INDEX_PREAMBLE + Code.encode(i));         
+            subpops[i].printSubpopulation(state, writer);
+            }
+        }
+    
+    /** Reads a population from the format generated by printPopulation(....).  The number of subpopulations and the species information must be identical. */
+    public void readPopulation(final EvolutionState state, 
+        final LineNumberReader reader) throws IOException
+        {
+        // read the number of subpops and check to see if this appears to be a valid individual
+        int numSubpops = Code.readIntegerWithPreamble(NUM_SUBPOPS_PREAMBLE, state, reader);
+        
+        // read in subpops
+        if (numSubpops != subpops.length)  // definitely wrong
+            state.output.fatal("On reading population from text stream, the number of subpopulations was wrong.");
+
+        for(int i = 0 ; i < subpops.length; i++)
+            {
+            int j = Code.readIntegerWithPreamble(SUBPOP_INDEX_PREAMBLE, state, reader);
+            // sanity check
+            if (j!=i) state.output.warnOnce("On reading population from text stream, some subpopulation indexes in the population did not match.");
+            subpops[i].readSubpopulation(state, reader);
+            }
+        }
+    
+    /** Writes a population in binary form, in a format readable by readPopulation(EvolutionState, DataInput). */
+    public void writePopulation(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(subpops.length);
+        for(int i = 0 ; i < subpops.length; i++)
+            subpops[i].writeSubpopulation(state, dataOutput);
+        }
+    
+    /** Reads a population in binary form, from the format generated by writePopulation(...). The number of subpopulations and the species information must be identical. */
+    public void readPopulation(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int numSubpopulations = dataInput.readInt();
+        if (numSubpopulations != subpops.length)
+            state.output.fatal("On reading subpopulation from binary stream, the number of subpopulations was wrong.");
+
+        for(int i = 0 ; i < subpops.length; i++)
+            subpops[i].readSubpopulation(state, dataInput);
+        }
+
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Problem.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Problem.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Problem.java	(revision 6152)
@@ -0,0 +1,150 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec; 
+
+import ec.util.*;
+
+/* 
+ * Problem.java
+ * 
+ * Created: Fri Oct 15 14:16:17 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Problem is a prototype which defines the problem against which we will
+ * evaluate individuals in a population. 
+ *
+ * <p>Since Problems are Prototypes, you should expect a new Problem class to be
+ * cloned and used, on a per-thread basis, for the evolution of each
+ * chunk of individuals in a new population.  If you for some reason
+ * need global Problem information, you will have to provide it
+ * statically, or copy pointers over during the clone() process
+ * (there is likely only one Problem prototype, depending on the
+ * Evaluator class used).
+ *
+ * <p>Note that Problem does not implement a specific evaluation method.
+ * Your particular Problem subclass will need to implement a some kind of
+ * Problem Form (for example, SimpleProblemForm) appropriate to the kind of
+ * evaluation being performed on the Problem.  These Problem Forms will provide
+ * the evaluation methods necessary.
+ *
+ * <p>Problem forms will define some kind of <i>evaluation</i> method.  This method
+ * may be called in one of two ways by the Evaluator.
+ *
+ * <ul> 
+ * <li> The evaluation is called for a series of individuals.  This is the old approach,
+ * and it means that each individual must be evaluated and modified as specified by the
+ * Problem Form during the evaluation call.
+ * <li> prepareToEvaluate is called, then a series of individuals is evaluated, and then
+ * finishEvaluating is called.  This is the new approach, and in this case the Problem
+ * is free to delay evaluating and modifying the individuals until finishEvaluating has
+ * been called.  The Problem may perfectly well evaluate and modify the individuals during
+ * each evaluation call if it likes.  It's just given this additional option.
+ * </ul>
+ *
+ * <p>Problems should be prepared for both of the above situations.  The easiest way
+ * to handle it is to simply evaluate each individual as his evaluate(...) method is called,
+ * and do nothing during prepareToEvaluate or finishEvaluating.  That should be true for
+ * the vast majority of Problem types.
+ *
+ * @author Sean Luke
+ * @version 2.0 
+ */
+
+public abstract class Problem implements Prototype
+    {
+    public static final String P_PROBLEM = "problem";
+    
+    /** Here's a nice default base for you -- you can change it if you like */
+    public Parameter defaultBase()
+        {
+        return new Parameter(P_PROBLEM);
+        }
+
+    // default form does nothing
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        }
+
+    public Object clone()
+        {
+        try { return super.clone(); }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+
+    /** May be called by the Evaluator prior to a series of individuals to 
+        evaluate, and then ended with a finishEvaluating(...).  If this is the
+        case then the Problem is free to delay modifying the individuals or their
+        fitnesses until at finishEvaluating(...).  If no prepareToEvaluate(...)
+        is called prior to evaluation, the Problem must complete its modification
+        of the individuals and their fitnesses as they are evaluated as stipulated
+        in the relevant evaluate(...) documentation for SimpleProblemForm 
+        or GroupedProblemForm.  The default method does nothing.  Note that
+        prepareToEvaluate() can be called *multiple times* prior to finishEvaluating()
+        being called -- in this case, the subsequent calls may be ignored. */
+    public void prepareToEvaluate(final EvolutionState state, final int threadnum)
+        {
+        }
+        
+    /** Will be called by the Evaluator after prepareToEvaluate(...) is called
+        and then a series of individuals are evaluated.  However individuals may
+        be evaluated without prepareToEvaluate or finishEvaluating being called
+        at all.  See the documentation for prepareToEvaluate for more information. 
+        The default method does nothing.*/
+    public void finishEvaluating(final EvolutionState state, final int threadnum)
+        {
+        }
+
+    /** Called to set up remote evaluation network contacts when the run is started.  By default does nothing. */
+    public void initializeContacts( EvolutionState state )
+        {
+        }
+
+    /**  Called to reinitialize remote evaluation network contacts when the run is restarted from checkpoint.  By default does nothing. */
+    public void reinitializeContacts( EvolutionState state )
+        {
+        }
+    
+    /**  Called to shut down remote evaluation network contacts when the run is completed.  By default does nothing. */
+    public void closeContacts(EvolutionState state, int result)
+        {
+        }
+        
+    /** Asynchronous Steady-State EC only: Returns true if the problem is ready to evaluate.  In most cases, 
+        the default is true.  */ 
+    public boolean canEvaluate()
+        { 
+        return true; 
+        }
+
+    /** Part of SimpleProblemForm.  Included here so you don't have to write the default version, which usually does nothing. */
+    public void describe(
+        final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum,
+        final int log)
+        {
+        return;
+        }
+
+    /** @deprecated.  Use the version without verbosity */
+    public final void describe(final Individual ind, 
+        final EvolutionState state, 
+        final int subpopulation,
+        final int threadnum,
+        final int log,
+        final int verbosity)
+        {
+        describe(state, ind, subpopulation, threadnum, log);
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/Prototype.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Prototype.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Prototype.java	(revision 6152)
@@ -0,0 +1,162 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.Parameter;
+
+/* 
+ * Prototype.java
+ * 
+ * Created: Sat Oct  2 22:04:44 1999
+ * By: Sean Luke
+ *
+ */
+
+/**
+ * Prototype classes typically have one or a few <i>prototype instances</i>
+ * created during the course of a run.  These prototype instances each get
+ * setup(...) called on them.  From then on, all new instances of a Prototype
+ * classes are Cloned from these prototype instances.
+ *
+ * <p>The purpose of a prototype is to make it possible to ask classes,
+ * determined at run-time by user parameters, to instantiate
+ * themselves very many times without using the Reflection library, which 
+ * would be very inefficient.
+ *
+ * <p>ECJ makes extensive use of Prototypes.  Individuals are prototypes.
+ * Species are prototypes.  Fitness objects are prototypes.  Breeding
+ * pipelines and selection methods are prototypes.  In the GP section, 
+ * GPNodes and GPTrees are prototypes.  In the Rule section, Rulesets and
+ * Rules are prototypes.  In the Vector section, VectorGenes are prototypes.
+ * And so on.
+ *
+ * <p>ECJ uses Prototypes almost exclusively instead of calling <tt>new</tt>.
+ * This is because <tt>new</t> requires that you know, in your code, the exact
+ * class of the object to be created.  Doing so programmatically essentially
+ * precludes being able to set up object graphs dynamically from parameter files.
+ * 
+ * <p>Sadly, clone() is rather slower than calling <tt>new</tt>.  However
+ * it <i>is</i> a lot faster than calling java.lang.Class.newInstance(),
+ * and somewhat faster than rolling our own "cloner" method.
+ *
+ * <p>Prototypes must be Cloneable, Serializable (through Setup), and of
+ * course, Setup.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface Prototype extends Cloneable, Setup
+    {
+    /** Creates a new individual cloned from a prototype,
+        and suitable to begin use in its own evolutionary
+        context.
+
+        <p>Typically this should be a full "deep" clone.
+        However, you may share certain elements with other objects
+        rather than clone hem, depending on the situation:
+
+        <p>
+        <ul>
+        <li>If you hold objects which are shared with other instances,
+        don't clone them.
+        <li>If you hold objects which must be unique, clone them.
+        <li>If you hold objects which were given to you as a gesture
+        of kindness, and aren't owned by you, you probably shouldn't clone
+        them.
+        <li> DON'T attempt to clone: Singletons, Cliques, or Groups.
+        <li>Arrays are not cloned automatically; you may need to
+        clone an array if you're not sharing it with other instances.
+        Arrays have the nice feature of being copyable by calling clone()
+        on them.
+        </ul>
+
+        <p><b>Implementations.</b>
+
+        <ul>
+        <li>If no ancestor of yours implements clone(),
+        and you have no need to do clone deeply,
+        and you are abstract, then you should not declare clone().
+        
+        <li>If no ancestor of yours implements clone(),
+        and you have no need to do clone deeply,
+        and you are <b>not</b> abstract, then you should implement
+        it as follows:
+
+        <p>
+        <tt><pre>
+        * public Object clone() 
+        *     {
+        *     try
+        *         { 
+        *         return super.clone();
+        *         }
+        *     catch ((CloneNotSupportedException e)
+        *         { throw new InternalError(); } // never happens
+        *     }
+        </pre></tt>
+        
+        <li>If no ancestor of yours implements clone(), but you
+        need to deep-clone some things, then you should implement it
+        as follows:
+
+        <p>
+        <tt><pre>
+        * public Object clone() 
+        *     {
+        *     try
+        *         { 
+        *         MyObject myobj = (MyObject) (super.clone());
+        *
+        *         // put your deep-cloning code here...
+        *         }
+        *     catch ((CloneNotSupportedException e)
+        *         { throw new InternalError(); } // never happens
+        *     return myobj;
+        *     } 
+        </pre></tt>
+
+        <li>If an ancestor has implemented clone(), and you also need
+        to deep clone some things, then you should implement it as follows:
+
+        <p>
+        <tt><pre>
+        * public Object clone() 
+        *     { 
+        *     MyObject myobj = (MyObject) (super.clone());
+        *
+        *     // put your deep-cloning code here...
+        *
+        *     return myobj;
+        *     } 
+        </pre></tt>
+        </ul>
+    */
+
+    public Object clone();
+
+    /** Sets up the object by reading it from the parameters stored
+        in <i>state</i>, built off of the parameter base <i>base</i>.
+        If an ancestor implements this method, be sure to call
+        super.setup(state,base);  before you do anything else. 
+
+        <p>For prototypes, setup(...) is typically called once for
+        the prototype instance; cloned instances do not receive
+        the setup(...) call.  setup(...) <i>may</i> be called
+        more than once; the only guarantee is that it will get
+        called at least once on an instance or some "parent"
+        object from which it was ultimately cloned. */
+
+    public void setup(final EvolutionState state, final Parameter base);
+
+    /** Returns the default base for this prototype.
+        This should generally be implemented by building off of the static base()
+        method on the DefaultsForm object for the prototype's package. This should
+        be callable during setup(...).  */
+    public Parameter defaultBase();
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/README	(revision 6152)
@@ -0,0 +1,196 @@
+This README is with regard to the 'ec' package in this directory.  Various
+subdirectories contain READMEs of their own for their respective packages.
+If you're looking for overall documentation for ECJ, see the README file
+for the parent directory of this one (that is, the 'ecj' directory).
+
+The 'ec' package contains top-level abstract classes defining most of the
+major elements of evolutionary or stochastic search processes.  You probably
+don't want abstract classes: instead you may wish to examine the 'simple'
+subpackage for concrete implementations of these classes which perform
+basic evolutionary tasks.
+
+
+
+
+DESIGN PATTERNS IN ECJ
+----------------------
+
+ECJ's basic classes sit on a set of simple interfaces defining what would now
+be called 'design patterns'.  Nearly all classes in ECJ use one or more of
+these interfaces, and together the interfaces are largely responsible for
+ECJ's dynamic loading facilities.
+
+
+ec.Setup
+
+ec.Setup is ECJ's top-level design pattern interface.  Setup defines a single
+method, setup(...), which acts as a sort of alternative constructor for
+instances which implement it.  In ECJ most classes are loaded at runtime
+from ECJ's ParameterDatabase.  Instances from such classes are dynamically
+instantiated using their default (no-argument) constructor; the setup(...)
+method then is called to give the objects a chance to set themselves up
+properly from the ParameterDatabase.  This approach was largely done because
+early versions of reflection in Java were inadequate.
+
+ec.Prototype
+
+Prototypes are Setups which are cloneable.  An class implementing Prototype
+is meant to have a single instance of the class (the "prototypical instance")
+loaded and setup from the Parameter Database; further instances of the class
+are constructed by cloning the prototypical instance. A large number of 
+ECJ objects are Prototype, including Individuals and various components of
+Individuals (such as genetic programming tree nodes).
+
+Many ECJ Prototypes support the so-called "flyweight" design pattern, whereby
+large numbers of lightweight instances share a common single special object
+which acts as a repository of default information common to all of them.
+In Java this could be implemented using static members, but static members
+are challenging to serialize (an important thing in ECJ), and so ECJ instead
+uses an actual object instead.  
+
+ec.Group
+
+Groups are very similar to Prototypes: their primary difference is that there
+is no prototypical Group: rather, new Groups can be cloned from currently
+in-use Groups using the method emptyClone().  Examples of Groups include
+Populations and Subpopulations.
+
+ec.Singleton
+
+Singletons are also Setups but are meant to be global objects: only one 
+instance is ever loaded and setup during the course of a run.  Most top-level
+objects (like ECJ's EvolutionState, Breeder, Evaluator, etc. objects) are
+Singletons.
+
+ec.Clique
+
+Cliques are Setups which are small groups of instances of a single class.
+Like Singletons, Cliques are global.  Once the collection of Cliques are loaded
+and setup, no more are usually created.  Cliques are associated with globally
+accessible tables which enable access to all members of the clique.  Cliques
+include genetic programming function sets, genetic programming types, etc.
+
+
+
+THE MAKEUP OF AN EVOLUTIONARY SYSTEM
+------------------------------------
+
+ec.Population
+ec.Subpopulation
+ec.Individual
+
+ECJ's evolutionary system is centered around a single Population, which 
+contains an array of Subpopulations.  Each Subpopulation contains an array of 
+Individuals.  This structure is largely to support techniques such as 
+coevolution which require more than one "population".  In ECJ such methods
+use one or more Subpopulation class to support this.  Though you will likely
+use Population and Subpopulation classes directly, almost certainly you'll
+need to subclass Individual to define its representation.  A number of
+predefined Individuals are available for you.
+
+ec.Species
+
+Individuals in ECJ support the flyweight pattern (see discussion of
+ec.Prototype above) and ec.Species is their collective object.  Many Individuals
+in ECJ share a common Species.  Each Subpopulation is also associated 
+with the Species used by Individuals in that Subpopulation.  Note that 
+multiple subpopulations, and different groups of Individuals, might 
+use the same Species in theory.
+
+The Species object contains the prototypical Individual from which other
+Individuals of that Species are cloned; and also contain Breeding Pipelines
+(see below) which enable Individuals to be bred from other Individuals of
+that Species.
+
+ec.Fitness
+
+Each ECJ individual contains a Fitness.  Different kinds of individuals
+can have different kinds of fitness objects (say, multiobjective fitness
+objects, or single-objective GA-style fitness objects, etc.).  The Fitness
+class is abstract: various Fitness subclasses perform different kinds of
+Fitness concepts.
+
+
+
+
+DOING EVOLUTION
+---------------
+
+ec.Evolve
+
+This class is the entry point for ECJ (it contains the main() method), but
+in fact it does relatively little: its main task is to load an EvolutionState
+from the parameter database, then get it going.
+
+ec.EvolutionState
+
+ECJ's top-level evolutionary loop is handled by subclasses of EvolutionState.
+EvolutionState also contains pointers to all the major elements of evolution,
+and ultimately everything in the entire evolutionary system.  Thus the entire
+process can be serialized (checkpointed) to disk simply by serializing
+EvolutionState.  When ECJ creates an evolutionary process, it first constructs
+an EvolutionState, then has the EvolutionState set up the rest of the process
+from the parameter database.  Because EvolutionState holds everything, it is
+often passed to many functions.
+
+ec.Initializer
+ec.Finisher
+
+To create a random  population and begin evolution, EvolutionState calls upon a
+subclass of Initializer. Likewise, just before quitting, EvolutionState
+calls upon some subclass of Finisher to clean up.
+
+ec.Evaluator
+ec.Problem
+
+EvolutionState calls upon Evaluator to evaluate the population.  Most
+Evaluators are straightforward: go through the population and evaluate each
+individual in turn.  But certain techniques require custom evaluation (such
+as coevolution).  The evaluator relies on a Problem subclass to do its dirty
+work: actually testing a given individual and assessing its fitness.  The
+experimenter (you) is required to provide a Problem subclass for his problem.
+Most of the examples in the "app" directory are largely Problem implementations.
+Often the Evaluator can work in parallel, cloning several Problems, then
+creating several threads, one thread per Problem, in order to assess the
+population more rapidly.
+
+ec.Breeder
+ec.BreedingSource
+ec.BreedingPipeline
+ec.SelectionMethod
+
+To breed a population to form a new population the EvolutionState relies on
+a subclass of Breeder.  Most Breeders work by constructing a "breeding
+pipeline" which selects individuals from the original population, mutates and
+crosses them over, and produces new children.  The breeding pipeline typically
+contains two kinds of objects: SelectionMethod objects, which pick individuals
+from the old population; and BreedingPipeline objects, which receive
+individuals from SelectionMethods or from other BreedingPipeline objects, and
+then mutate or cross over the individuals.  Both BreedingPipeline and 
+SelectionMethod objects are BreedingSources (things other BreedingPipelines
+can get individuals from).  Many breeders can work in parallel,
+constructing several breeding pipelines, one per thread, to speed up the task
+of breeding individuals and forming the next generation.
+
+ec.Exchanger
+
+In between breeding and evaluation, the EvolutionState calls on a subclass
+of Exchanger.  The default implementations do nothing at all, but certain
+versions (like IslandExchange) take this opportunity to exchange individuals
+with far-of processes on other machines.
+
+
+
+STATISTICS
+----------
+
+ec.Statistics
+
+ECJ relies on one or more subclasses of Statistics to write out statistics
+information to various logs.  Statistics can be strung out in a chain, enabling
+you to include as many different Statistics objects as you like.  Different
+Statistics subclasses are available to do various tasks.  Statistics objects
+are called at all sorts of times in the run, in-between nearly every major
+operation, to give you a lot of hooks in which to probe the current state of
+the system.
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/SelectionMethod.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/SelectionMethod.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/SelectionMethod.java	(revision 6152)
@@ -0,0 +1,90 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * SelectionMethod.java
+ * 
+ * Created: Mon Aug 30 19:19:56 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A SelectionMethod is a BreedingSource which provides direct IMMUTABLE pointers
+ * to original individuals in an old population, not fresh mutable copies.
+ * If you use a SelectionMethod as your BreedingSource, you must 
+ * SelectionMethods might include Tournament Selection, Fitness Proportional Selection, etc.
+ * SelectionMethods don't have parent sources.
+ *
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class SelectionMethod extends BreedingSource
+    {
+    public static final int INDS_PRODUCED = 1;
+
+    /** Returns 1 (the typical default value) */
+    public int typicalIndsProduced() { return INDS_PRODUCED; }
+
+    /** A default version of produces -- this method always returns
+        true under the assumption that the selection method works
+        with all Fitnesses.  If this isn't the case, you should override
+        this to return your own assessment. */
+    public boolean produces(final EvolutionState state,
+        final Population newpop,
+        final int subpopulation,
+        final int thread)
+        {
+        return true;
+        }
+
+
+    /** A default version of prepareToProduce which does nothing.  */
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        { return; }
+
+    /** A default version of finishProducing, which does nothing. */
+    public void finishProducing(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        { return; }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        int n=INDS_PRODUCED;
+        if (n<min) n = min;
+        if (n>max) n = max;
+        
+        for(int q=0;q<n;q++)
+            inds[start+q] = state.population.subpops[subpopulation].
+                individuals[produce(subpopulation,state,thread)];
+        return n;
+        }
+    
+    /** An alternative form of "produce" special to Selection Methods;
+        selects an individual from the given subpopulation and 
+        returns its position in that subpopulation. */
+    public abstract int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread);
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/Setup.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Setup.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Setup.java	(revision 6152)
@@ -0,0 +1,41 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.Parameter;
+import java.io.Serializable;
+
+/* 
+ * Setup.java
+ * 
+ * Created: Mon Oct  4 17:15:44 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Setup classes are classes which get set up once from user-supplied parameters
+ * prior to being used.
+ *
+ * Defines a single method, setup(...), which is called at least once for the
+ * object, or for some object from which it was cloned.  This method
+ * allows the object to set itself up by reading from parameter lists and
+ * files on-disk.  You may assume that this method is called in a non-threaded
+ * environment, hence your thread number is 0 (so you can determine which
+ * random number generator to use).
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public strictfp interface Setup extends Serializable
+    {
+    /** Sets up the object by reading it from the parameters stored
+        in <i>state</i>, built off of the parameter base <i>base</i>.
+        If an ancestor implements this method, be sure to call
+        super.setup(state,base);  before you do anything else. */
+    public void setup(final EvolutionState state, final Parameter base);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Singleton.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Singleton.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Singleton.java	(revision 6152)
@@ -0,0 +1,29 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+
+/* 
+ * Singleton.java
+ * 
+ * Created: Wed Oct 13 14:57:00 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A Singleton is a class for which there will be only one instance
+ * in the entire course of a run, and which will exist for pretty
+ * much the entire run.  Singletons are set up using setup(...)
+ * when they are first created.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface Singleton extends Setup
+    {
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Species.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Species.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Species.java	(revision 6152)
@@ -0,0 +1,239 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * Species.java
+ * 
+ * Created: Tue Aug 10 20:31:50 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Species is a prototype which defines the features for a set of individuals
+ * in the population.  Typically, individuals may breed if they belong to the
+ * same species (but it's not a hard-and-fast rule).  Each Subpopulation has
+ * one Species object which defines the species for individuals in that
+ * Subpopulation.
+ *
+ * <p>Species are generally responsible for creating individuals, through
+ * their newIndividual(...) method.  This method usually clones its prototypical
+ * individual and makes some additional modifications to the clone, then returns it.
+ * Note that the prototypical individual does <b>not need to be a complete individual</b> --
+ * for example, GPSpecies holds a GPIndividual which doesn't have any trees (the tree
+ * roots are null).
+ *
+ * <p>Species also holds a prototypical breeding pipeline meant to breed
+ * this individual.  To breed individuals of this species, clone the pipeline
+ * and use the clone.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ind</tt><br>
+ <font size=-1>classname, inherits and != ec.Individual</font></td>
+ <td valign=top>(the class for the prototypical individual for the species)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>fitness</tt><br>
+ <font size=-1>classname, inherits and != ec.Fitness</font></td>
+ <td valign=top>(the class for the prototypical fitness for the species)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>numpipes</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(total number of breeding pipelines for the species)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>pipe</tt><br>
+ <font size=-1>classname, inherits and != ec.BreedingPipeline</font></td>
+ <td valign=top>(the class for the prototypical Breeding Pipeline)</td></tr>
+
+ </table>
+
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ind</tt></td>
+ <td>i_prototype (the prototypical individual)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>pipe</tt></td>
+ <td>pipe_prototype (breeding pipeline prototype)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>fitness</tt></td>
+ <td>f_prototype (the prototypical fitness)</td></tr>
+
+ </table>
+
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class Species implements Prototype
+    {
+    public static final String P_INDIVIDUAL = "ind";
+    public static final String P_PIPE = "pipe";
+    public static final String P_FITNESS = "fitness";
+
+    /** The prototypical individual for this species. */
+    public Individual i_prototype;
+    
+    /** The prototypical breeding pipeline for this species. */
+    public BreedingPipeline pipe_prototype;
+
+    /** The prototypical fitness for individuals of this species. */
+    public Fitness f_prototype;    
+
+    public Object clone()
+        {
+        try
+            {
+            Species myobj = (Species) (super.clone());
+            myobj.i_prototype = (Individual) i_prototype.clone();
+            myobj.f_prototype = (Fitness) f_prototype.clone();
+            myobj.pipe_prototype = (BreedingPipeline) pipe_prototype.clone();
+            return myobj;
+            }
+        catch (CloneNotSupportedException e)
+            { throw new InternalError(); } // never happens
+        } 
+
+
+
+    // deprecate the old ones
+    final private Individual newIndividual(final EvolutionState state,
+        final Subpopulation _population, 
+        final Fitness _fitness) throws IOException { return null; }
+    final private Individual newIndividual(final EvolutionState state,
+        final Subpopulation _population,
+        final Fitness _fitness,
+        final LineNumberReader reader) throws IOException  { return null; }
+    final private Individual newIndividual(final EvolutionState state,
+        final Subpopulation _population,
+        final Fitness _fitness,
+        final DataInput input) throws IOException  { return null; }
+    
+    /** Provides a brand-new individual to fill in a population.  The default form
+        simply calls clone(), creates a fitness, sets evaluated to false, and sets
+        the species.  If you need to make a more custom genotype (as is the case
+        for GPSpecies, which requires a light rather than deep clone), 
+        you will need to override this method as you see fit.
+    */
+    
+    public Individual newIndividual(final EvolutionState state, int thread)
+        {
+        Individual newind = (Individual)(i_prototype.clone());
+
+        // Set the fitness
+        newind.fitness = (Fitness)(f_prototype.clone());
+        newind.evaluated = false;
+
+        // Set the species to me
+        newind.species = this;
+
+        // ...and we're ready!
+        return newind;
+        }
+    
+    /**
+       Provides an individual read from a stream, including
+       the fitness; the individual will
+       appear as it was written by printIndividual(...).  Doesn't 
+       close the stream.  Sets evaluated to false and sets the species.
+       If you need to make a more custom mechanism (as is the case
+       for GPSpecies, which requires a light rather than deep clone), 
+       you will need to override this method as you see fit.
+    */
+
+    public Individual newIndividual(final EvolutionState state,
+        final LineNumberReader reader)
+        throws IOException
+        {
+        Individual newind = (Individual)(i_prototype.clone());
+                
+        // Set the fitness
+        newind.fitness = (Fitness)(f_prototype.clone());
+        newind.evaluated = false; // for sanity's sake, though it's a useless line
+
+        // load that sucker
+        newind.readIndividual(state,reader);
+
+        // Set the species to me
+        newind.species = this;
+
+        // and we're ready!
+        return newind;  
+        }
+
+    /**
+       Provides an individual read from a DataInput source, including
+       the fitness.  Doesn't 
+       close the DataInput.  Sets evaluated to false and sets the species.
+       If you need to make a more custom mechanism (as is the case
+       for GPSpecies, which requires a light rather than deep clone), 
+       you will need to override this method as you see fit.
+    */
+
+    public Individual newIndividual(final EvolutionState state,
+        final DataInput dataInput)
+        throws IOException
+        {
+        Individual newind = (Individual)(i_prototype.clone());
+        
+        // Set the fitness
+        newind.fitness = (Fitness)(f_prototype.clone());
+        newind.evaluated = false; // for sanity's sake, though it's a useless line
+
+        // Set the species to me
+        newind.species = this;
+
+        // load that sucker
+        newind.readIndividual(state,dataInput);
+
+        // and we're ready!
+        return newind;  
+        }
+
+
+    /** The default version of setup(...) loads requested pipelines and calls setup(...) on them and normalizes their probabilities.  
+        If your individual prototype might need to know special things about the species (like parameters stored in it),
+        then when you override this setup method, you'll need to set those parameters BEFORE you call super.setup(...),
+        because the setup(...) code in Species sets up the prototype.
+        @see Prototype#setup(EvolutionState,Parameter)
+    */
+ 
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        // load the breeding pipeline
+        pipe_prototype = (BreedingPipeline)(
+            state.parameters.getInstanceForParameter(
+                base.push(P_PIPE),def.push(P_PIPE),BreedingPipeline.class));
+        pipe_prototype.setup(state,base.push(P_PIPE));
+
+        // I promised over in BreedingSource.java that this method would get called.
+        state.output.exitIfErrors();
+
+        // load our individual prototype
+        i_prototype = (Individual)(state.parameters.getInstanceForParameter(
+                base.push(P_INDIVIDUAL),def.push(P_INDIVIDUAL),
+                Individual. class));
+        // set the species to me before setting up the individual, so they know who I am
+        i_prototype.species = this;
+        i_prototype.setup(state,base.push(P_INDIVIDUAL));
+        
+        // load our fitness
+        f_prototype = (Fitness) state.parameters.getInstanceForParameter(
+            base.push(P_FITNESS),def.push(P_FITNESS),
+            Fitness.class);
+        f_prototype.setup(state,base.push(P_FITNESS));
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/Statistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Statistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Statistics.java	(revision 6152)
@@ -0,0 +1,231 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec;
+import ec.steadystate.*;
+import ec.util.*;
+
+/* 
+ * Statistics.java
+ * 
+ * Created: Tue Aug 10 21:10:48 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Statistics and its subclasses are Cliques which generate statistics
+ * during the run.  Statistics are arranged in a tree hierarchy -- 
+ * The root statistics object may have "children", and when the root is
+ * called, it calls its children with the same message.  You can override
+ * this behavior however you see fit.
+  
+ * <p>There are lots of places where statistics might be nice to print out.
+ * These places are implemented as hooks in the Statistics object which you
+ * can override if you like; otherwise they call the default behavior.  If
+ * you plan on allowing your Statistics subclass to contain children, you
+ * should remember to call the appropriate super.foo() if you 
+ * override any foo() method.
+ *
+ * <p>While there are lots of hooks, various EvolutionState objects only
+ * implement a subset of them.   You'll need to look at the EvolutionState
+ * code to see which ones are implemented to make sure that your statistics
+ * hooks are called appropriately!
+ *
+ * <p>Statistics objects should set up their statistics logs etc. during 
+ * <tt>setup(...)</tt>.  Remember to make the log restartable in
+ * case of restarting from a checkpoint.
+ *
+ * <p><b>Steady-State Statistics</b>.  For convenience, Statistics contains
+ * default implementations of the SteadyStateStatisticsForm methods but
+ * does not implement SteadyStateStatisticsForm.  This mostly is intended
+ * to keep SteadyStateStatistcsForm implementations from having to call
+ * functions on all their children: instead they can just call foo.super();
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>num-children</tt><br>
+ <font size=-1>int &gt;= 0</font></td>
+ <td valign=top>(number of child statistics objects)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>child</tt>.<i>n</i><br>
+ <font size=-1>classname, inherits or equals ec.Statistics</font></td>
+ <td valign=top>(the class of child statistics object number <i>n</i>)</td></tr>
+ </table>
+ 
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>child</tt>.<i>n</i></td>
+ <td>species (child statistics object number <i>n</i>)</td></tr>
+ </table>
+ 
+
+
+ * @author Sean Luke
+ * @version 2.0 
+ */
+
+public class Statistics implements Singleton
+    {
+    public static final String P_NUMCHILDREN = "num-children";
+    public static final String P_CHILD = "child"; 
+    public Statistics[] children;
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        int t = state.parameters.getIntWithDefault(base.push(P_NUMCHILDREN),null,0);
+        if (t < 0) 
+            state.output.fatal("A Statistics object cannot have negative number of children",
+                base.push(P_NUMCHILDREN));
+
+        // load the trees
+        children = new Statistics[t];
+
+        for (int x=0;x<t;x++)
+            {
+            Parameter p = base.push(P_CHILD).push(""+x);
+            children[x] = (Statistics)(state.parameters.getInstanceForParameterEq(p,null,Statistics.class));
+            ((Statistics)children[x]).setup(state,p);
+            }
+        }
+    
+    /** Called immediately before population initialization occurs. */
+    public void preInitializationStatistics(final EvolutionState state) 
+        { 
+        for(int x=0;x<children.length;x++)
+            children[x].preInitializationStatistics(state);
+        }
+        
+    /** GENERATIONAL: Called immediately after population initialization occurs. */
+    public void postInitializationStatistics(final EvolutionState state) 
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].postInitializationStatistics(state);
+        }
+
+    /** Called immediately before checkpointing occurs. */
+    public void preCheckpointStatistics(final EvolutionState state) 
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].preCheckpointStatistics(state);
+        }
+
+    /** Called immediately after checkpointing occurs. */
+    public void postCheckpointStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].postCheckpointStatistics(state);
+        }
+
+    /** GENERATIONAL: Called immediately before evaluation occurs. */
+    public void preEvaluationStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].preEvaluationStatistics(state);
+        }
+
+    /** GENERATIONAL: Called immediately after evaluation occurs. */
+    public void postEvaluationStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].postEvaluationStatistics(state);
+        }
+
+    /** Called immediately before the pre-breeding exchange occurs. */
+    public void prePreBreedingExchangeStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].prePreBreedingExchangeStatistics(state);
+        }
+        
+    /** Called immediately after the pre-breeding exchange occurs. */
+    public void postPreBreedingExchangeStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].postPreBreedingExchangeStatistics(state);
+        }
+
+    /** GENERATIONAL: Called immediately before breeding occurs. */
+    public void preBreedingStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].preBreedingStatistics(state);
+        }
+
+    /** GENERATIONAL: Called immediately after breeding occurs. */
+    public void postBreedingStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].postBreedingStatistics(state);
+        }
+
+    /** Called immediately before the post-breeding exchange occurs. */
+    public void prePostBreedingExchangeStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].prePostBreedingExchangeStatistics(state);
+        }
+
+    /** Called immediately after the post-breeding exchange occurs. */
+    public void postPostBreedingExchangeStatistics(final EvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].postPostBreedingExchangeStatistics(state);
+        }
+
+    /** Called immediately after the run has completed.  <i>result</i>
+        is either <tt>state.R_FAILURE</tt>, indicating that an ideal individual
+        was not found, or <tt>state.R_SUCCESS</tt>, indicating that an ideal
+        individual <i>was</i> found. */
+    public void finalStatistics(final EvolutionState state, final int result)
+        {
+        for(int x=0;x<children.length;x++)
+            children[x].finalStatistics(state, result);
+        }
+    
+    /** STEADY-STATE: called when we created an empty initial Population. */
+    public void enteringInitialPopulationStatistics(final SteadyStateEvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            if (children[x] instanceof SteadyStateStatisticsForm)
+                ((SteadyStateStatisticsForm)children[x]).enteringInitialPopulationStatistics(state);
+        }
+        
+    /** STEADY-STATE: called when a given Subpopulation is entering the Steady-State. */
+    public void enteringSteadyStateStatistics(int subpop, final SteadyStateEvolutionState state)
+        {
+        for(int x=0;x<children.length;x++)
+            if (children[x] instanceof SteadyStateStatisticsForm)
+                ((SteadyStateStatisticsForm)children[x]).enteringSteadyStateStatistics(subpop, state);
+        }
+        
+    /** STEADY-STATE: called each time new individuals are bred during the steady-state
+        process. */
+    public void individualsBredStatistics(SteadyStateEvolutionState state, Individual[] individuals)
+        {
+        for(int x=0;x<children.length;x++)
+            if (children[x] instanceof SteadyStateStatisticsForm)
+                ((SteadyStateStatisticsForm)children[x]).individualsBredStatistics(state, individuals);
+        }
+    
+    /** STEADY-STATE: called each time new individuals are evaluated during the steady-state
+        process.  You can look up the individuals in state.newIndividuals[] */
+    public void individualsEvaluatedStatistics(SteadyStateEvolutionState state, Individual[] newIndividuals, 
+        Individual[] oldIndividuals, int[] subpopulations, int[] indices)
+        {
+        for(int x=0;x<children.length;x++)
+            if (children[x] instanceof SteadyStateStatisticsForm)
+                ((SteadyStateStatisticsForm)children[x]).individualsEvaluatedStatistics(state, newIndividuals, oldIndividuals, subpopulations, indices);
+        }
+        
+    /** STEADY-STATE: called each time the generation count increments */ 
+    public void generationBoundaryStatistics(final EvolutionState state) 
+        {
+        for (int x=0; x < children.length; x++) 
+            if (children[x] instanceof SteadyStateStatisticsForm) 
+                ((SteadyStateStatisticsForm)children[x]).generationBoundaryStatistics(state); 
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/Subpopulation.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/Subpopulation.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/Subpopulation.java	(revision 6152)
@@ -0,0 +1,327 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+
+package ec;
+import java.util.*;
+import java.io.*;
+import ec.util.*;
+
+/* 
+ * Subpopulation.java
+ * 
+ * Created: Tue Aug 10 20:34:14 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Subpopulation is a group which is basically an array of Individuals.
+ * There is always one or more Subpopulations in the Population.  Each
+ * Subpopulation has a Species, which governs the formation of the Individuals
+ * in that Subpopulation.  Subpopulations also contain a Fitness prototype
+ * which is cloned to form Fitness objects for individuals in the subpopulation.
+ *
+ * <p>An initial subpopulation is populated with new random individuals 
+ * using the populate(...) method.  This method typically populates
+ * by filling the array with individuals created using the Subpopulations' 
+ * species' emptyClone() method, though you might override this to create
+ * them with other means, by loading from text files for example.
+ *
+ * <p>In a multithreaded area of a run, Subpopulations should be considered
+ * immutable.  That is, once they are created, they should not be modified,
+ * nor anything they contain.  This protocol helps ensure read-safety under
+ * multithreading race conditions.
+ *
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(total number of individuals in the subpopulation)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>species</tt><br>
+ <font size=-1>classname, inherits and != ec.Species</font></td>
+ <td valign=top>(the class of the subpopulations' Species)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>fitness</tt><br>
+ <font size=-1>classname, inherits and != ec.Fitness</font></td>
+ <td valign=top>(the class for the prototypical Fitness for individuals in this subpopulation)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>file</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(pathname of file from which the population is to be loaded.  If not defined, or empty, then the population will be initialized at random in the standard manner)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>duplicate-retries</tt><br>
+ <font size=-1>int &gt;= 0</font></td>
+ <td valign=top>(during initialization, when we produce an individual which already exists in the subpopulation, the number of times we try to replace it with something unique.  Ignored if we're loading from a file.)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ ec.subpop
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>species</tt></td>
+ <td>species (the subpopulations' species)</td></tr>
+
+ </table>
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+
+public class Subpopulation implements Group
+    {
+    /** A new subpopulation should be loaded from this file if it is non-null;
+        otherwise they should be created at random.  */
+    public File loadInds;
+
+    /** The species for individuals in this subpopulation. */
+    public Species species;
+
+    /** The subpopulation's individuals. */
+    public Individual[] individuals;
+
+    /** Do we allow duplicates? */
+    public int numDuplicateRetries;
+    
+    public static final String P_SUBPOPULATION = "subpop";
+    public static final String P_FILE = "file";
+    public static final String P_SUBPOPSIZE = "size";  // parameter for number of subpops or pops
+    public static final String P_SPECIES = "species";
+    public static final String P_RETRIES = "duplicate-retries";
+
+    public static final String NUM_INDIVIDUALS_PREAMBLE = "Number of Individuals: ";
+    public static final String INDIVIDUAL_INDEX_PREAMBLE = "Individual Number: ";
+
+    public Parameter defaultBase()
+        {
+        return ECDefaults.base().push(P_SUBPOPULATION);
+        }
+
+    /** Returns an instance of Subpopulation just like it had been before it was
+        populated with individuals. You may need to override this if you override
+        Subpopulation.   <b>IMPORTANT NOTE</b>: if the size of the array in
+        Subpopulation has been changed, then the clone will take on the new array
+        size.  This helps some evolution strategies.
+        @see Group#emptyClone()
+    */
+    
+    public Group emptyClone()
+        {
+        try
+            {
+            Subpopulation p = (Subpopulation)clone();
+            p.species = species;  // don't throw it away...maybe this is a bad idea...
+            p.individuals = new Individual[individuals.length];  // empty
+            return p;   
+            }
+        catch (CloneNotSupportedException e) { throw new InternalError(); } // never happens
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        int size;
+
+        // do we load from a file?
+        loadInds = state.parameters.getFile(
+            base.push(P_FILE),null);
+
+        // what species do we use?
+
+        species = (Species) state.parameters.getInstanceForParameter(
+            base.push(P_SPECIES),def.push(P_SPECIES),
+            Species.class);
+        species.setup(state,base.push(P_SPECIES));
+
+        // how big should our subpopulation be?
+        
+        size = state.parameters.getInt(
+            base.push(P_SUBPOPSIZE),def.push(P_SUBPOPSIZE),1);
+        if (size<=0)
+            state.output.fatal(
+                "Subpopulation size must be an integer >= 1.\n",
+                base.push(P_SUBPOPSIZE),def.push(P_SUBPOPSIZE));
+        
+        // How often do we retry if we find a duplicate?
+        numDuplicateRetries = state.parameters.getInt(
+            base.push(P_RETRIES),def.push(P_RETRIES),0);
+        if (numDuplicateRetries < 0) state.output.fatal(
+            "The number of retries for duplicates must be an integer >= 0.\n",
+            base.push(P_RETRIES),def.push(P_RETRIES));
+        
+        individuals = new Individual[size];
+        }
+
+
+
+    public void populate(EvolutionState state, int thread)
+        {
+        // should we load individuals from a file? -- duplicates are permitted
+        if (loadInds!=null)
+            {
+            try { readSubpopulation(state, new LineNumberReader(new FileReader(loadInds))); }
+            catch (IOException e) { state.output.fatal("An IOException occurred when trying to read from the file " + loadInds + ".  The IOException was: \n" + e); }
+            }
+        else
+            {
+            Hashtable h = null;
+            if (numDuplicateRetries >= 1)
+                h = new Hashtable(individuals.length / 2);  // seems reasonable
+
+            for(int x=0;x<individuals.length;x++) 
+                {
+                for(int tries=0; 
+                    tries <= /* Yes, I see that*/ numDuplicateRetries; 
+                    tries++)
+                    {
+                    individuals[x] = species.newIndividual(state, thread);
+
+                    if (numDuplicateRetries >= 1)
+                        {
+                        // check for duplicates
+                        Object o = h.get(individuals[x]);
+                        if (o == null) // found nothing, we're safe
+                            // hash it and go
+                            {
+                            h.put(individuals[x],individuals[x]);
+                            break;
+                            }
+                        }
+                    }  // oh well, we tried to cut down the duplicates
+                }
+            }
+        }
+        
+    /** Prints an entire subpopulation in a form readable by humans. 
+        @deprecated Verbosity no longer has meaning
+    */
+    public final void printSubpopulationForHumans(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        printSubpopulationForHumans(state, log);
+        }
+        
+    /** Prints an entire subpopulation in a form readable by humans but also parseable by the computer using readSubpopulation(EvolutionState, LineNumberReader). 
+        @deprecated Verbosity no longer has meaning
+    */
+    public final void printSubpopulation(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        printSubpopulation(state, log);
+        }
+        
+    /** Prints an entire subpopulation in a form readable by humans, with a verbosity of Output.V_NO_GENERAL. */
+    public void printSubpopulationForHumans(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(NUM_INDIVIDUALS_PREAMBLE + individuals.length, log);
+        for(int i = 0 ; i < individuals.length; i++)
+            {
+            state.output.println(INDIVIDUAL_INDEX_PREAMBLE + Code.encode(i), log);
+            individuals[i].printIndividualForHumans(state, log);
+            }
+        }
+        
+    /** Prints an entire subpopulation in a form readable by humans but also parseable by the computer using readSubpopulation(EvolutionState, LineNumberReader) with a verbosity of Output.V_NO_GENERAL. */
+    public void printSubpopulation(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(NUM_INDIVIDUALS_PREAMBLE + Code.encode(individuals.length), log);
+        for(int i = 0 ; i < individuals.length; i++)
+            {
+            state.output.println(INDIVIDUAL_INDEX_PREAMBLE + Code.encode(i), log);
+            individuals[i].printIndividual(state, log);
+            }
+        }
+        
+    /** Prints an entire subpopulation in a form readable by humans but also parseable by the computer using readSubpopulation(EvolutionState, LineNumberReader). */
+    public void printSubpopulation(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println(NUM_INDIVIDUALS_PREAMBLE + Code.encode(individuals.length));
+        for(int i = 0 ; i < individuals.length; i++)
+            {
+            writer.println(INDIVIDUAL_INDEX_PREAMBLE + Code.encode(i));
+            individuals[i].printIndividual(state, writer);
+            }
+        }
+    
+    /** Reads a subpopulation from the format generated by printSubpopulation(....).  If the number of individuals is not identical, the individuals array will
+        be deleted and replaced with a new array, and a warning will be generated as individuals will have to be created using newIndividual(...) rather
+        than readIndividual(...). */
+    public void readSubpopulation(final EvolutionState state, 
+        final LineNumberReader reader) throws IOException
+        {
+        // read in number of individuals and check to see if this appears to be a valid subpopulation
+        int numIndividuals = Code.readIntegerWithPreamble(NUM_INDIVIDUALS_PREAMBLE, state, reader);
+
+        // read in individuals
+        if (numIndividuals != individuals.length)
+            {
+            state.output.warnOnce("On reading subpopulation from text stream, the subpopulation size didn't match.\n" + 
+                "Had to resize and use newIndividual() instead of readIndividual().");
+            individuals = new Individual[numIndividuals];
+            for(int i = 0 ; i < individuals.length; i++)
+                {
+                int j = Code.readIntegerWithPreamble(INDIVIDUAL_INDEX_PREAMBLE, state, reader);
+                // sanity check
+                if (j!=i) state.output.warnOnce("On reading subpopulation from text stream, some individual indexes in the subpopulation did not match.");
+                individuals[i] = species.newIndividual(state, reader);
+                }
+            }
+        else for(int i = 0 ; i < individuals.length; i++)
+                 {
+                 int j = Code.readIntegerWithPreamble(INDIVIDUAL_INDEX_PREAMBLE, state, reader);
+                 // sanity check
+                 if (j!=i) state.output.warnOnce("On reading subpopulation from text stream, some individual indexes in the subpopulation did not match.");
+                 if (individuals[i] != null)
+                     individuals[i].readIndividual(state, reader);
+                 else
+                     {
+                     state.output.warnOnce("On reading subpopulation from text stream, some of the preexisting subpopulation's slots were null.\n" +
+                         "Had to use newIndividual() instead of readIndividual().  If you're starting an evolutionary run by reading an\n" +
+                         "existing population from a file, this is expected -- ignore this message.");
+                     individuals[i] = species.newIndividual(state, reader);
+                     }
+                 }
+        }
+        
+    /** Writes a subpopulation in binary form, in a format readable by readSubpopulation(EvolutionState, DataInput). */
+    public void writeSubpopulation(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(individuals.length);
+        for(int i = 0 ; i < individuals.length; i++)
+            individuals[i].writeIndividual(state, dataOutput);
+        }
+    
+    /** Reads a subpopulation in binary form, from the format generated by writeSubpopulation(...).  If the number of individuals is not identical, the individuals array will
+        be deleted and replaced with a new array, and a warning will be generated as individuals will have to be created using newIndividual(...) rather
+        than readIndividual(...) */
+    public void readSubpopulation(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int numIndividuals = dataInput.readInt();
+        if (numIndividuals != individuals.length)
+            {
+            state.output.warnOnce("On reading subpopulation from binary stream, the subpopulation size was incorrect.\n" + 
+                "Had to resize and use newIndividual() instead of readIndividual().");
+            individuals = new Individual[numIndividuals];
+            for(int i = 0 ; i < individuals.length; i++)
+                individuals[i] = species.newIndividual(state, dataInput);
+            }
+        else for(int i = 0 ; i < individuals.length; i++)
+                 individuals[i].readIndividual(state, dataInput);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/README	(revision 6152)
@@ -0,0 +1,93 @@
+This is the traditional top-level directory holding ECJ's demo applications.
+When building new apps for research purposes, we find it convenient to stick
+them here as well.
+
+Here's what we've got so far:
+
+
+
+BOOLEAN VECTOR REPRESENTATIONS
+
+hiff		Hierarchical if-and-only-if Functions
+sat		3CNF boolean satisfiability problems
+nk		N-K Landscapes
+
+
+INTEGER VECTOR REPRESENTATIONS
+
+sum		Simple sum demo
+
+
+FLOATING POINT VECTOR REPRESENTATIONS
+
+ecsuite		A host of common floating-point fitness functions
+			-- includes GA, ES, DE, and steady-state code
+bbob		Black Box Optimization 2010 code converted to ECJ
+
+
+GENETIC PROGRAMMING AND GRAMMATICAL EVOLUTION
+
+ant		Artificial Ant
+			-- includes grammatical evolution code
+edge		Edge Encoding
+lawnmower	Lawnmower
+			-- includes ADF and non-ADF code
+			-- includes grammatical evolution code
+multiplexer	"Fast" Multiplexer
+multiplexerslow	Easy to understand Multiplexer
+parity		Parity
+			-- includes ADF and non-ADF code
+regression	Various Symbolic Regression examples
+			-- includes ERC and non-ERC code	
+			-- includes steady-state code
+			-- includes grammatical evolution code
+twobox		Two Box
+			-- includes ADF and non-ADF code
+
+
+COMPETITIVE 1-POPULATION COEVOLUTION
+
+coevolve1	Competitive MaxOnes example
+
+
+COOPERATIVE COEVOLUTION
+
+coevolve2	Cooperative Rosenbrock example
+
+
+ASYNCHRONOUS EVOLUTION
+
+async		Asynchronous evolution demo
+
+
+MULTIOBJECTIVE OPTIMIZATION
+
+moosuite	A host of multiobjective optimization benchmarks
+
+
+SPATIAL EVOLUTION
+
+spatial		A simple spatial evolution demonstration
+
+
+TUTORIAL CODE
+
+tutorial1	-- for the tutorials proper, see the ecj/docs/ directory
+tutorial2
+tutorial3
+tutorial4
+
+
+DISTRIBUTED EVALUATION
+
+star		A distributed valuation demo
+
+
+ISLAND MODELS
+
+-- all island model demonstrations are found not here but instead
+   in the ecj/ec/exchange directory (see 2-Island-Server, 3-Island,
+   and 8-Island)
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/Ant.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/Ant.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/Ant.java	(revision 6152)
@@ -0,0 +1,280 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant;
+import ec.app.ant.func.*;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import java.io.*;
+import java.util.*;
+import ec.simple.*;
+
+/* 
+ * Ant.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Ant implements the Artificial Ant problem.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.ant.AntData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Ant problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>file</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(filename of the .trl file for the Ant problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>turns</tt><br>
+ <font size=-1>int &gt;= 1</td>
+ <td valign=top>(maximal number of moves the ant may make)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Ant extends GPProblem implements SimpleProblemForm
+    {
+    public static final String P_FILE = "file";
+    public static final String P_MOVES = "moves";
+
+    // map point descriptions
+    public static final int ERROR = 0;
+    public static final int FOOD = -1;
+    public static final int EMPTY = 1;
+    public static final int TRAIL = 2;
+    public static final int ATE = 3;
+
+    // orientations
+    public static final int O_UP = 0;
+    public static final int O_LEFT = 1;
+    public static final int O_DOWN = 2;
+    public static final int O_RIGHT = 3;
+
+    // We'll deep clone this anyway, even though we don't
+    // need it by default!
+    public AntData input;
+
+    // maximum number of moves
+    public int maxMoves;
+
+    // how much food we have
+    public int food;
+
+    // our map
+    public int map[][];
+    
+    // store the positions of food so we can reset our map
+    // don't need to be deep-cloned, they're read-only
+    public int foodx[];
+    public int foody[];
+
+    // map[][]'s bounds
+    public int maxx;
+    public int maxy;
+
+    // our position
+    public int posx;
+    public int posy;
+
+    // how many points we've gotten
+    public int sum;
+    
+    // our orientation
+    public int orientation;
+
+    // how many moves we've made
+    public int moves;
+
+    // print modulo for doing the abcdefg.... thing at print-time
+    public int pmod;
+
+    public Object clone()
+        {
+        Ant myobj = (Ant) (super.clone());
+        myobj.input = (AntData)(input.clone());
+        myobj.map = new int[map.length][];
+        for(int x=0;x<map.length;x++)
+            myobj.map[x] = (int[])(map[x].clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // not using any default base -- it's not safe
+
+        // set up our input
+        input = (AntData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA),null, AntData.class);
+        input.setup(state,base.push(P_DATA));
+
+        // how many maxMoves?
+        maxMoves = state.parameters.getInt(base.push(P_MOVES),null,1);
+        if (maxMoves==0)
+            state.output.error("The number of moves an ant has to make must be >0");
+        
+        // load our file
+        File filename = state.parameters.getFile(base.push(P_FILE),null);
+        if (filename==null)
+            state.output.fatal("Ant trail file name not provided.");
+
+        food = 0;
+        try
+            {
+            LineNumberReader lnr = 
+                new LineNumberReader(new FileReader(filename));
+            
+            StringTokenizer st = new StringTokenizer(lnr.readLine()); // ugh
+            maxx = Integer.parseInt(st.nextToken());
+            maxy = Integer.parseInt(st.nextToken());
+            map = new int[maxx][maxy];
+            int y;
+            for(y=0;y<maxy;y++)
+                {
+                String s = lnr.readLine();
+                if (s==null)
+                    {
+                    state.output.warning("Ant trail file ended prematurely");
+                    break;
+                    }
+                int x;
+                for(x=0;x<s.length();x++)
+                    {
+                    if (s.charAt(x)==' ')
+                        map[x][y]=EMPTY;
+                    else if (s.charAt(x)=='#')
+                        { map[x][y]=FOOD; food++; }
+                    else if (s.charAt(x)=='.')
+                        map[x][y]=TRAIL;
+                    else state.output.error("Bad character '" + s.charAt(x) + "' on line number " + lnr.getLineNumber() + " of the Ant trail file.");
+                    }
+                // fill out rest of X's
+                for(int z=x;z<maxx;z++)
+                    map[z][y]=EMPTY;
+                }
+            // fill out rest of Y's
+            for (int z=y;z<maxy;z++)
+                for(int x=0;x<maxx;x++)
+                    map[x][z]=EMPTY;
+            }
+        catch (NumberFormatException e)
+            {
+            state.output.fatal("The Ant trail file does not begin with x and y integer values.");
+            }
+        catch (IOException e)
+            {
+            state.output.fatal("The Ant trail file could not be read due to an IOException:\n" + e);
+            }
+        state.output.exitIfErrors();
+
+        // load foodx and foody reset arrays
+        foodx = new int[food];
+        foody = new int[food];
+        int tmpf = 0;
+        for(int x=0;x<map.length;x++)
+            for(int y=0;y<map[0].length;y++)
+                if (map[x][y]==FOOD) 
+                    { foodx[tmpf] = x; foody[tmpf] = y; tmpf++; }
+        }
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            sum = 0;            
+            posx = 0;
+            posy = 0;
+            orientation = O_RIGHT;
+
+            for(moves=0;moves<maxMoves && sum<food; )
+                ((GPIndividual)ind).trees[0].child.eval(
+                    state,threadnum,input,stack,((GPIndividual)ind),this);
+                
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)(food - sum));
+            f.hits = sum;
+            ind.evaluated = true;
+
+            // clean up array
+            for(int y=0;y<food;y++)
+                map[foodx[y]][foody[y]] = FOOD;
+            }
+        }
+
+    public void describe(
+        final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation, 
+        final int threadnum,
+        final int log)
+
+        {
+        state.output.println("\n\nBest Individual's Map\n=====================", log);
+
+        sum = 0;
+        pmod = 97; /** ascii a */
+        posx = 0;
+        posy = 0;
+        orientation = O_RIGHT;
+
+        int[][] map2 = new int[map.length][];
+        for(int x=0;x<map.length;x++)
+            map2[x] = (int[])(map[x].clone());
+
+        map2[posx][posy] = pmod; pmod++;
+        for(moves=0; moves<maxMoves && sum<food; )
+            ((EvalPrint)(((GPIndividual)ind).trees[0].child)).evalPrint(
+                state,threadnum,input,stack,((GPIndividual)ind),this,
+                map2);
+        // print out the map
+        for(int y=0;y<map2.length;y++)
+            {
+            for(int x=0;x<map2.length;x++)
+                {
+                switch(map2[x][y])
+                    {
+                    case FOOD: 
+                        state.output.print("#",log);
+                        break;
+                    case EMPTY: 
+                        state.output.print(".",log);
+                        break;
+                    case TRAIL: 
+                        state.output.print("+",log);
+                        break;
+                    case ATE:
+                        state.output.print("?",log);
+                        break;
+                    default:
+                        state.output.print(""+((char)map2[x][y]),log);
+                        break;
+                    }
+                }
+            state.output.println("",log);
+            }
+
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/AntData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/AntData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/AntData.java	(revision 6152)
@@ -0,0 +1,29 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant;
+import ec.gp.*;
+
+/* 
+ * AntData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Since Ant doesn't actually pass any information, this
+ * object is effectively empty.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class AntData extends GPData
+    {
+    public void copyTo(final GPData gpd) { }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ant.grammar
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ant.grammar	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ant.grammar	(revision 6152)
@@ -0,0 +1,5 @@
+<prog> ::= <op>
+<op> ::= (if-food-ahead <op> <op>) 
+<op> ::=  (progn2 <op> <op>) 
+<op> ::= (progn3 <op> <op> <op>)
+<op> ::= (left) | (right) | (move)  
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ant.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ant.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ant.params	(revision 6152)
@@ -0,0 +1,46 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+
+### The functions, carefully ordered :-)  (See below)
+
+gp.fs.0.func.0 = ec.app.ant.func.Left
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.ant.func.Right
+gp.fs.0.func.1.nc = nc0
+gp.fs.0.func.2 = ec.app.ant.func.Move
+gp.fs.0.func.2.nc = nc0
+gp.fs.0.func.3 = ec.app.ant.func.IfFoodAhead
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.ant.func.Progn2
+gp.fs.0.func.4.nc = nc2
+gp.fs.0.func.5 = ec.app.ant.func.Progn3
+gp.fs.0.func.5.nc = nc3
+# We won't use this one here
+gp.fs.0.func.6 = ec.app.ant.func.Progn4
+gp.fs.0.func.6.nc = nc4
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.ant.Ant
+eval.problem.data = ec.app.ant.AntData
+
+# Here we determine what kind of Ant we're doing:
+
+# no progn4, 400 moves, Santa Fe trail
+gp.fs.0.size = 6
+eval.problem.moves = 400
+eval.problem.file = santafe.trl
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/EvalPrint.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/EvalPrint.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/EvalPrint.java	(revision 6152)
@@ -0,0 +1,34 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.gp.*;
+
+/* 
+ * EvalPrint.java
+ * 
+ * Created: Wed Nov 17 14:28:22 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface EvalPrint
+    {
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2 );
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/IfFoodAhead.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/IfFoodAhead.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/IfFoodAhead.java	(revision 6152)
@@ -0,0 +1,118 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.app.ant.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * IfFoodAhead.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class IfFoodAhead extends GPNode implements EvalPrint
+    {
+    public String toString() { return "if-food-ahead"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Ant p = (Ant)problem;
+        switch (p.orientation)
+            {
+            case Ant.O_UP:
+                if (p.map[p.posx][(p.posy-1+p.maxy)%p.maxy]==Ant.FOOD)
+                    children[0].eval(state,thread,input,stack,individual,problem);
+                else children[1].eval(state,thread,input,stack,individual,problem);
+                break;
+            case Ant.O_LEFT:
+                if (p.map[(p.posx-1+p.maxx)%p.maxx][p.posy]==Ant.FOOD)
+                    children[0].eval(state,thread,input,stack,individual,problem);
+                else children[1].eval(state,thread,input,stack,individual,problem);
+                break;
+            case Ant.O_DOWN:
+                if (p.map[p.posx][(p.posy+1)%p.maxy]==Ant.FOOD)
+                    children[0].eval(state,thread,input,stack,individual,problem);
+                else children[1].eval(state,thread,input,stack,individual,problem);
+                break;
+            case Ant.O_RIGHT:
+                if (p.map[(p.posx+1)%p.maxx][p.posy]==Ant.FOOD)
+                    children[0].eval(state,thread,input,stack,individual,problem);
+                else children[1].eval(state,thread,input,stack,individual,problem);
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+        }
+
+
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2)
+        {
+        Ant p = (Ant)problem;
+        switch (p.orientation)
+            {
+            case Ant.O_UP:
+                if (p.map[p.posx][(p.posy-1+p.maxy)%p.maxy]==Ant.FOOD)
+                    ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                else ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                break;
+            case Ant.O_LEFT:
+                if (p.map[(p.posx-1+p.maxx)%p.maxx][p.posy]==Ant.FOOD)
+                    ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                else ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                break;
+            case Ant.O_DOWN:
+                if (p.map[p.posx][(p.posy+1)%p.maxy]==Ant.FOOD)
+                    ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                else ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                break;
+            case Ant.O_RIGHT:
+                if (p.map[(p.posx+1)%p.maxx][p.posy]==Ant.FOOD)
+                    ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                else ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Left.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Left.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Left.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.app.ant.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Left.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Left extends GPNode implements EvalPrint
+    {
+    public String toString() { return "left"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Ant p = (Ant)problem;
+        switch (p.orientation)
+            {
+            case Ant.O_UP:
+                p.orientation = Ant.O_LEFT; 
+                break;
+            case Ant.O_LEFT:
+                p.orientation = Ant.O_DOWN;
+                break;
+            case Ant.O_DOWN:
+                p.orientation = Ant.O_RIGHT;
+                break;
+            case Ant.O_RIGHT:
+                p.orientation = Ant.O_UP;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+        p.moves++;
+        }
+
+
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2)
+        {
+        eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Move.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Move.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Move.java	(revision 6152)
@@ -0,0 +1,130 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.app.ant.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Move.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Move extends GPNode implements EvalPrint
+    {
+    public String toString() { return "move"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Ant p = (Ant)problem;
+        switch (p.orientation)
+            {
+            case Ant.O_UP:
+                p.posy--;
+                if (p.posy<0) p.posy = p.maxy-1;
+                break;
+            case Ant.O_LEFT:
+                p.posx--;
+                if (p.posx<0) p.posx = p.maxx-1;
+                break;
+            case Ant.O_DOWN:
+                p.posy++;
+                if (p.posy>=p.maxy) p.posy=0;
+                break;
+            case Ant.O_RIGHT:
+                p.posx++;
+                if (p.posx>=p.maxx) p.posx=0;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+
+        p.moves++;
+        if (p.map[p.posx][p.posy]==Ant.FOOD && p.moves < p.maxMoves )
+            {
+            p.sum++;
+            p.map[p.posx][p.posy]=Ant.ATE;
+            }
+        }
+
+    /** Just like eval, but it retraces the map and prints out info */
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2)
+        {
+        Ant p = (Ant)problem;
+        switch (p.orientation)
+            {
+            case Ant.O_UP:
+                p.posy--;
+                if (p.posy<0) p.posy = p.maxy-1;
+                break;
+            case Ant.O_LEFT:
+                p.posx--;
+                if (p.posx<0) p.posx = p.maxx-1;
+                break;
+            case Ant.O_DOWN:
+                p.posy++;
+                if (p.posy>=p.maxy) p.posy=0;
+                break;
+            case Ant.O_RIGHT:
+                p.posx++;
+                if (p.posx>=p.maxx) p.posx=0;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+
+        p.moves++;
+        if (p.map[p.posx][p.posy]==Ant.FOOD && p.moves < p.maxMoves)
+            {
+            p.sum++;
+            p.map[p.posx][p.posy]=Ant.ATE;
+            }
+
+        if (p.moves<p.maxMoves)
+            {
+            if (++p.pmod > 122 /* ascii z */) p.pmod=97; /* ascii a */
+            map2[p.posx][p.posy]=p.pmod;
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn2.java	(revision 6152)
@@ -0,0 +1,69 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Progn2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Progn2 extends GPNode implements EvalPrint
+    {
+    public String toString() { return "progn2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // Evaluate both children.  Easy as cake.
+        children[0].eval(state,thread,input,stack,individual,problem);
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2 )
+        {
+        // Evaluate both children.  Easy as cake.
+        ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        }
+
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn3.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn3.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn3.java	(revision 6152)
@@ -0,0 +1,70 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Progn3.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Progn3 extends GPNode implements EvalPrint
+    {
+    public String toString() { return "progn3"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=3)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // Evaluate children.  Easy as cake.
+        children[0].eval(state,thread,input,stack,individual,problem);
+        children[1].eval(state,thread,input,stack,individual,problem);
+        children[2].eval(state,thread,input,stack,individual,problem);
+        }
+
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2)
+        {
+        // Evaluate children.  Easy as cake.
+        ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        ((EvalPrint)children[2]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn4.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn4.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Progn4.java	(revision 6152)
@@ -0,0 +1,72 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Progn4.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Progn4 extends GPNode implements EvalPrint
+    {
+    public String toString() { return "progn4"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=4)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // Evaluate children.  Easy as cake.
+        children[0].eval(state,thread,input,stack,individual,problem);
+        children[1].eval(state,thread,input,stack,individual,problem);
+        children[2].eval(state,thread,input,stack,individual,problem);
+        children[3].eval(state,thread,input,stack,individual,problem);
+        }
+
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2)
+        {
+        // Evaluate children.  Easy as cake.
+        ((EvalPrint)children[0]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        ((EvalPrint)children[1]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        ((EvalPrint)children[2]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        ((EvalPrint)children[3]).evalPrint(state,thread,input,stack,individual,problem,map2);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Right.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Right.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/func/Right.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.ant.func;
+import ec.*;
+import ec.app.ant.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Right.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+
+public class Right extends GPNode implements EvalPrint
+    {
+    public String toString() { return "right"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Ant p = (Ant)problem;
+        switch (p.orientation)
+            {
+            case Ant.O_UP:
+                p.orientation = Ant.O_RIGHT; 
+                break;
+            case Ant.O_LEFT:
+                p.orientation = Ant.O_UP;
+                break;
+            case Ant.O_DOWN:
+                p.orientation = Ant.O_LEFT;
+                break;
+            case Ant.O_RIGHT:
+                p.orientation = Ant.O_DOWN;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+        p.moves++;
+        }
+
+    public void evalPrint(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int[][] map2)
+        {
+        eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ge.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ge.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/ge.params	(revision 6152)
@@ -0,0 +1,12 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/ge/ge.params
+parent.1 = ant.params
+
+ge.species.file.0 = ant.grammar
+eval.problem.problem = ec.app.ant.Ant
+eval.problem.problem.data = ec.app.ant.AntData
+eval.problem.problem.moves = 400
+eval.problem.problem.file = santafe.trl
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/losaltos.trl
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/losaltos.trl	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/losaltos.trl	(revision 6152)
@@ -0,0 +1,67 @@
+100 100
+ ###
+   #                                  .###..
+   #                                  #    #
+   #                                  #    #
+   ####.#####           .############..    .
+            #           .                  #
+            #           #                  .
+            #           #                  .
+            #           #                  #
+            .           #                  .
+            #           .                  .
+            #           .                  #
+            #           #                  .
+            #           #            ...###.
+            .       .#...            #
+            .       .                .
+            #       .                .
+            #       #                .#...
+            #       #                    #
+            #       #                    .
+            #       #                    .
+            #       .                ...#.
+            #       .                #
+ ..##..#####.       #                #
+ #                  #                #
+ #                  #                #
+ #                  #                #
+ #                  #                #
+ #                  #                #
+ #     .#####....##..                #
+ #     #                             #
+ .     #                             #
+ .####..                             #
+                                   #.#
+                                   #
+                                   #
+                                   #
+                                   #
+                                   #
+                                   #
+                                   #
+                              ######
+                              .
+                              #
+                              #
+                              #
+                              #
+                              #
+                              #
+                            #..
+                            #
+                            #
+                            #
+                            #
+                            #
+                      .######
+                      .
+                      #
+                      #
+                      #
+                      #
+                      #
+                      #
+                      #
+                      #
+                      #
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/progn4.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/progn4.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/progn4.params	(revision 6152)
@@ -0,0 +1,14 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# defines the Ant problem, 400 moves, Santa Fe trail, using
+# an additional function, "progn4", which was defined as
+# an option in lil-gp, so we include it here.
+
+parent.0 = ant.params
+
+# no progn4, 400 moves, Santa Fe trail
+gp.fs.0.size = 7
+eval.problem.moves = 400
+eval.problem.file = santafe.trl
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ant/santafe.trl
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ant/santafe.trl	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ant/santafe.trl	(revision 6152)
@@ -0,0 +1,33 @@
+32 32
+ ###
+   #
+   #                    .###..
+   #                    #    #
+   #                    #    #
+   ####.#####       .##..    .
+            #       .        #
+            #       #        .
+            #       #        .
+            #       #        #
+            .       #        .
+            #       .        .
+            #       .        #
+            #       #        .
+            #       #  ...###.
+            .   .#...  #
+            .   .      .
+            #   .      .
+            #   #      .#...
+            #   #          #
+            #   #          .
+            #   #          .
+            #   .      ...#.
+            #   .      #
+ ..##..#####.   #
+ #              #
+ #              #
+ #     .#######..
+ #     #
+ .     #
+ .####..
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/async/asesum.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/async/asesum.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/async/asesum.params	(revision 6152)
@@ -0,0 +1,9 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = steadysum.params
+parent.1 = ../../eval/master.params
+
+state = 		ec.eval.AsynchronousEvolutionState
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/async/sum.slave.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/async/sum.slave.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/async/sum.slave.params	(revision 6152)
@@ -0,0 +1,33 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = asesum.params
+
+# We tell our slave that he's a slave.
+eval.i-am-slave = true
+
+
+# You may want to customize each slave by giving it a unique
+# name like this:
+# 
+# eval.slave-name = my-slave-name
+#
+# (do this differently for each slave:, slave-2, slave-3, etc.)
+# Otherwise, each slave will give itself an approximately unique name based
+# on the current time and the IP address of the slave.  The unique name
+# doesn't HAVE to be unique -- it's just for printing/debug purposes.
+
+
+# We want to make sure that the Slave's Statistics object does not
+# override the Master's statistics files.  The easiest way to do this
+# is to eliminate the Statistics object in the slave by setting it
+# to the (empty default) Statistics class with no children.
+
+eval.stat = ec.Statistics
+eval.stat.num-children = 0
+
+
+# The slave needs to know where the Master is.  You need to 
+# change this.
+eval.master.host = 127.0.0.1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/BBOBenchmarks.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/BBOBenchmarks.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/BBOBenchmarks.java	(revision 6152)
@@ -0,0 +1,2160 @@
+package ec.app.bbob;
+
+import java.util.HashMap;
+
+import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Initializer;
+import ec.Population;
+import ec.Problem;
+import ec.Subpopulation;
+import ec.gp.koza.HalfBuilder;
+import ec.simple.SimpleFitness;
+import ec.simple.SimpleProblemForm;
+import ec.util.MersenneTwisterFast;
+import ec.util.Parameter;
+import ec.util.QuickSort;
+import ec.vector.DoubleVectorIndividual;
+
+/* 
+ * MultiObjectiveFitness.java
+ * 
+ * Created: Fri Apr 2 09:00:00 2010
+ * By: Faisal Abidi
+ */
+
+/**
+ * The Black Box Optimization workshop (BBOB) has an annual competition for doing real-valued parameter optimization.
+ * The examples shown here are more or less faithful reproductions of the BBOB 2010 C code, only using Mersenne Twister
+ * instead of BBOB's random number generator.  Unfortunately, the original BBOB code has various magic numbers, unexplained
+ * variables, and unfortunate algorithmic decisions.  We've reproduced them exactly rather than attempt to convert to a 
+ * standard ECJ template, and simply apologize beforehand.
+ *
+ * <p>
+ * <b>Parameters</b><br>
+ * <table>
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>noise</tt><br>
+ * <font size=-1> String = <tt>none </tt>(default)
+ * <tt>, gauss, uniform, cauchy, gauss-moderate, uniform-moderate, cauchy-moderate</tt>
+ * </font></td>
+ * <td valign=top>(what type of noise (if any) to add to the function value)
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>genome-size</tt><br>
+ * <font size=-1> integer &gt; 0 </tt>
+ * </font></td>
+ * <td valign=top>(genome size)
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>noise</tt><br>
+ * <font size=-1> String = <tt>none </tt>(default)
+ * <tt>, sphere, ellipsoidal, rastrigin, buch-rastrigin, linear-slope, attractive-sector, step-elipsoidal, rosenbrock, rosenbrock-rotated, ellipsoidal-2, discus, bent-cigar, sharp-ridge, different-powers, rastrigin-2,
+ * weierstrass, schaffers-f7, schaffers-f7-2, griewak-rosenbrock, schwefel, gallagher-gaussian-101me, gallagher-gaussian-21hi, katsuura, lunacek</tt>
+ * </font></td>
+ * <td valign=top>(The particular function)
+ * </table>
+ * 
+ * 
+ * @author Faisal Abidi
+ * @version 1.0
+ */
+
+public class BBOBenchmarks extends Problem implements SimpleProblemForm
+    {
+    public static final String P_GENOME_SIZE = "genome-size";
+    public static final String P_WHICH_PROBLEM = "type";
+    public static final String P_NOISE = "noise";
+
+    final public String[] problemTypes =
+        { "sphere", "ellipsoidal", "rastrigin", "buche-rastrigin", "linear-slope", "attractive-sector", "step-ellipsoidal", "rosenbrock", "rosenbrock-rotated", "ellipsoidal-2", "discus", "bent-cigar", "sharp-ridge", "different-powers", "rastrigin-2",
+          "weierstrass", "schaffers-f7", "schaffers-f7-2", "griewank-rosenbrock", "schwefel", "gallagher-gaussian-101me", "gallagher-gaussian-21hi", "katsuura", "lunacek" };
+
+    final static public int SPHERE = 0;
+    final static public int ELLIPSOIDAL = 1;
+    final static public int RASTRIGIN = 2;
+    final static public int BUCHE_RASTRIGIN = 3;
+    final static public int LINEAR_SLOPE = 4;
+    final static public int ATTRACTIVE_SECTOR = 5;
+    final static public int STEP_ELLIPSOIDAL = 6;
+    final static public int ROSENBROCK = 7;
+    final static public int ROSENBROCK_ROTATED = 8;
+    final static public int ELLIPSOIDAL_2 = 9;
+    final static public int DISCUS = 10;
+    final static public int BENT_CIGAR = 11;
+    final static public int SHARP_RIDGE = 12;
+    final static public int DIFFERENT_POWERS = 13;
+    final static public int RASTRIGIN_2 = 14;
+    final static public int WEIERSTRASS = 15;
+    final static public int SCHAFFERS_F7 = 16;
+    final static public int SCHAFFERS_F7_2 = 17;
+    final static public int GRIEWANK_ROSENBROCK = 18;
+    final static public int SCHWEFEL = 19;
+    final static public int GALLAGHER_GAUSSIAN_101ME = 20;
+    final static public int GALLAGHER_GAUSSIAN_21HI = 21;
+    final static public int KATSUURA = 22;
+    final static public int LUNACEK = 23;
+
+    // Noise types
+    final public String[] noiseTypes =
+        { "none", "gauss", "uniform", "cauchy", "gauss-moderate", "uniform-moderate", "cauchy-moderate" };
+
+    final static public int NONE = 0;
+    final static public int GAUSSIAN = 1;
+    final static public int UNIFORM = 2;
+    final static public int CAUCHY = 3;
+    final static public int GAUSSIAN_MODERATE = 4;
+    final static public int UNIFORM_MODERATE = 5;
+    final static public int CAUCHY_MODERATE = 6;
+
+    public int problemType = 0; // defaults on SPHERE
+
+    public int noise = NONE; // defaults to NONE
+
+    final public int NHIGHPEAKS21 = 101;
+    final public int NHIGHPEAKS22 = 21;
+
+    // DO NOT MODIFY THESE VARIABLES except in the setup method: global
+    // variables are not threadsafe.
+    double fOpt;
+    double[] xOpt;
+    double fAdd_Init;
+
+    double f0;
+    double[][] rotation;
+    double[][] rot2;
+    double[][] linearTF;
+    double[] peaks21;
+    double[] peaks22;
+    int[] rperm;
+    int[] rperm21;
+    int[] rperm22;
+    double[][] xLocal;
+    double[][] xLocal21;
+    double[][] xLocal22;
+    double[][] arrScales;
+    double[][] arrScales21;
+    double[][] arrScales22;
+    double[] aK;
+    double[] bK;
+    double[] peakvalues;
+    double scales;
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+        String wp = state.parameters.getStringWithDefault(base.push(P_WHICH_PROBLEM), null, "");
+        int i, j, k;
+        Parameter p = new Parameter(Initializer.P_POP);
+        int genomeSize = state.parameters.getInt(p.push(Population.P_SUBPOP).push("0").push(Subpopulation.P_SPECIES).push(P_GENOME_SIZE), null, 1);
+        String noiseStr = state.parameters.getString(new Parameter(P_NOISE), null);
+        for (i = 0; i < noiseTypes.length; i++)
+            if (noiseStr.equals(noiseTypes[i]))
+                noise = i;
+                                
+        double condition = 10.0;
+        double alpha = 100.0;
+        double tmp, tmp2, maxCondition;
+        double[] fitValues = { 1.1, 9.1 };
+
+        double[] arrCondition, peaks, tmpvect;
+
+        for (i = 0; i < problemTypes.length; i++)
+            if (wp.equals(problemTypes[i]))
+                problemType = i;
+
+        // common Initialization
+        fOpt = computeFopt(state.random[0]);
+        xOpt = new double[genomeSize];
+
+        switch (problemType)
+            {
+            case SPHERE:
+                /* INITIALIZATION */
+                computeXopt(xOpt, state.random[0]);
+                break;
+                        
+            case ELLIPSOIDAL: // f2
+                computeXopt(xOpt, state.random[0]);
+                rotation = new double[genomeSize][genomeSize];
+                computeRotation(rotation, state.random[0], genomeSize);
+                if (noise != NONE)
+                    {
+                    rot2 = new double[genomeSize][genomeSize];
+                    computeRotation(rot2, state.random[0], genomeSize);
+                    }
+                break;
+                        
+            case RASTRIGIN:
+                computeXopt(xOpt, state.random[0]);
+                break;
+                        
+            case BUCHE_RASTRIGIN:
+                computeXopt(xOpt, state.random[0]);
+                for (i = 0; i < genomeSize; i += 2)
+                    xOpt[i] = Math.abs(xOpt[i]); /* Skew */
+                break;
+                        
+            case LINEAR_SLOPE:
+                computeXopt(xOpt, state.random[0]);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.pow(Math.sqrt(alpha), ((double) i) / ((double) (genomeSize - 1)));
+                    if (xOpt[i] > 0)
+                        {
+                        xOpt[i] = 5.;
+                        }
+                    else if (xOpt[i] < 0)
+                        {
+                        xOpt[i] = -5.;
+                        }
+                    fAdd_Init += 5. * tmp;
+                    }
+                break;
+                        
+            case ATTRACTIVE_SECTOR:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                /* decouple scaling from function definition */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        linearTF[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            linearTF[i][j] += rotation[i][k] * Math.pow(Math.sqrt(condition), ((double) k) / ((double) (genomeSize - 1))) * rot2[k][j];
+                            }
+                        }
+                    }
+                break;
+                        
+            case STEP_ELLIPSOIDAL:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                break;
+                        
+            case ROSENBROCK:
+                computeXopt(xOpt, state.random[0]);
+                scales = Math.max(1.0, Math.sqrt(genomeSize) / 8.0);
+                if (noise == NONE)
+                    for (i = 0; i < genomeSize; i++)
+                        xOpt[i] *= 0.75;
+                break;
+                        
+            case ROSENBROCK_ROTATED:
+                /* INITIALIZATION */
+                linearTF = new double[genomeSize][genomeSize];
+                rotation = new double[genomeSize][genomeSize];
+                /* computeXopt(state.random[0], genomeSize); */
+                computeRotation(rotation, state.random[0], genomeSize);
+                scales = Math.max(1.0, Math.sqrt(genomeSize) / 8.);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        linearTF[i][j] = scales * rotation[i][j];
+                    }
+                break;
+                        
+            case ELLIPSOIDAL_2:
+                rotation = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                break;
+                        
+            case DISCUS:
+                rotation = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                break;
+                        
+            case BENT_CIGAR:
+                rotation = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                break;
+                        
+            case SHARP_RIDGE:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        linearTF[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            linearTF[i][j] += rotation[i][k] * Math.pow(Math.sqrt(condition), ((double) k) / ((double) (genomeSize - 1))) * rot2[k][j];
+                            }
+                        }
+                    }
+                break;
+                        
+            case DIFFERENT_POWERS:
+                rotation = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                break;
+                        
+            case RASTRIGIN_2:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        linearTF[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            linearTF[i][j] += rotation[i][k] * Math.pow(Math.sqrt(condition), ((double) k) / ((double) (genomeSize - 1))) * rot2[k][j];
+                            }
+                        }
+                    }
+                break;
+                        
+            case WEIERSTRASS:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                aK = new double[12];
+                bK = new double[12];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        linearTF[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            linearTF[i][j] += rotation[i][k] * Math.pow(1.0 / Math.sqrt(condition), ((double) k) / ((double) (genomeSize - 1))) * rot2[k][j];
+                            }
+                        }
+                    }
+
+                f0 = 0.0;
+                for (i = 0; i < 12; i++) /*
+                                          * number of summands, 20 in CEC2005, 10/12
+                                          * saves 30% of time
+                                          */
+                    {
+                    aK[i] = Math.pow(0.5, (double) i);
+                    bK[i] = Math.pow(3., (double) i);
+                    f0 += aK[i] * Math.cos(2 * Math.PI * bK[i] * 0.5);
+                    }
+                break;
+                        
+            case SCHAFFERS_F7:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                break;
+                        
+            case SCHAFFERS_F7_2:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                break;
+                        
+            case GRIEWANK_ROSENBROCK:
+                rotation = new double[genomeSize][genomeSize];
+                scales = Math.max(1.0, Math.sqrt(genomeSize) / 8.0);
+                computeRotation(rotation, state.random[0], genomeSize);
+                if (noise == NONE)
+                    {
+                    rot2 = new double[genomeSize][genomeSize];
+                    linearTF = new double[genomeSize][genomeSize];
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            linearTF[i][j] = scales * rotation[i][j];
+                            }
+                        }
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        xOpt[i] = 0.0;
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            xOpt[i] += linearTF[j][i] * 0.5 / scales / scales;
+                            }
+                        }
+                    }
+                else
+                    {
+                    // TODO
+                    }
+                break;
+                        
+            case SCHWEFEL:
+                /* INITIALIZATION */
+                tmpvect = new double[genomeSize];
+
+                for (i = 0; i < genomeSize; i++)
+                    tmpvect[i] = nextDoubleClosedInterval(state.random[0]);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    xOpt[i] = 0.5 * 4.2096874633;
+                    if (tmpvect[i] - 0.5 < 0)
+                        xOpt[i] *= -1.;
+                    }
+                break;
+                        
+            case GALLAGHER_GAUSSIAN_101ME:
+                rotation = new double[genomeSize][genomeSize];
+                maxCondition = 1000.0;
+                arrCondition = new double[NHIGHPEAKS21];
+                peaks21 = new double[genomeSize * NHIGHPEAKS21];
+                rperm21 = new int[Math.max(genomeSize, NHIGHPEAKS21)];
+                peaks = peaks21;
+                peakvalues = new double[NHIGHPEAKS21];
+                arrScales21 = new double[NHIGHPEAKS21][genomeSize];
+                xLocal21 = new double[genomeSize][NHIGHPEAKS21];
+                computeRotation(rotation, state.random[0], genomeSize);
+
+                for (i = 0; i < NHIGHPEAKS21 - 1; i++)
+                    peaks[i] = nextDoubleClosedInterval(state.random[0]);
+                rperm = rperm21;
+                for (i = 0; i < NHIGHPEAKS21 - 1; i++)
+                    rperm[i] = i;
+                QuickSort.qsort(rperm);
+
+                /* Random permutation */
+
+                arrCondition[0] = Math.sqrt(maxCondition);
+                peakvalues[0] = 10;
+                for (i = 1; i < NHIGHPEAKS21; i++)
+                    {
+                    arrCondition[i] = Math.pow(maxCondition, (double) (rperm[i - 1]) / ((double) (NHIGHPEAKS21 - 2)));
+                    peakvalues[i] = (double) (i - 1) / (double) (NHIGHPEAKS21 - 2) * (fitValues[1] - fitValues[0]) + fitValues[0];
+                    }
+                arrScales = arrScales21;
+                for (i = 0; i < NHIGHPEAKS21; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        peaks[j] = nextDoubleClosedInterval(state.random[0]);
+                    for (j = 0; j < genomeSize; j++)
+                        rperm[j] = j;
+                    // qsort(rperm, genomeSize, sizeof(int), compare_doubles);
+                    QuickSort.qsort(rperm);
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        arrScales[i][j] = Math.pow(arrCondition[i], ((double) rperm[j]) / ((double) (genomeSize - 1)) - 0.5);
+                        }
+                    }
+
+                for (i = 0; i < genomeSize * NHIGHPEAKS21; i++)
+                    peaks[i] = nextDoubleClosedInterval(state.random[0]);
+                xLocal = xLocal21;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    xOpt[i] = 0.8 * (10. * peaks[i] - 5.);
+                    for (j = 0; j < NHIGHPEAKS21; j++)
+                        {
+                        xLocal[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            xLocal[i][j] += rotation[i][k] * (10. * peaks[j * genomeSize + k] - 5.);
+                            }
+                        if (j == 0)
+                            xLocal[i][j] *= 0.8;
+                        }
+                    }
+                break;
+                        
+            case GALLAGHER_GAUSSIAN_21HI:
+                rotation = new double[genomeSize][genomeSize];
+                maxCondition = 1000.0;
+                arrCondition = new double[NHIGHPEAKS22];
+                peaks22 = new double[genomeSize * NHIGHPEAKS22];
+                rperm22 = new int[Math.max(genomeSize, NHIGHPEAKS22)];
+                arrScales22 = new double[NHIGHPEAKS22][genomeSize];
+                xLocal22 = new double[genomeSize][NHIGHPEAKS22];
+                peaks = peaks22;
+                peakvalues = new double[NHIGHPEAKS22];
+                computeRotation(rotation, state.random[0], genomeSize);
+                peaks = peaks22;
+                for (i = 0; i < NHIGHPEAKS22 - 1; i++)
+                    peaks[i] = nextDoubleClosedInterval(state.random[0]);
+                rperm = rperm22;
+                for (i = 0; i < NHIGHPEAKS22 - 1; i++)
+                    rperm[i] = i;
+                // NOTE: confirm if this is a valid java conversion.
+                QuickSort.qsort(rperm);
+                /* Random permutation */
+                arrCondition[0] = maxCondition;
+                peakvalues[0] = 10;
+                for (i = 1; i < NHIGHPEAKS22; i++)
+                    {
+                    arrCondition[i] = Math.pow(maxCondition, (double) (rperm[i - 1]) / ((double) (NHIGHPEAKS22 - 2)));
+                    peakvalues[i] = (double) (i - 1) / (double) (NHIGHPEAKS22 - 2) * (fitValues[1] - fitValues[0]) + fitValues[0];
+                    }
+                arrScales = arrScales22;
+                for (i = 0; i < NHIGHPEAKS22; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        peaks[j] = nextDoubleClosedInterval(state.random[0]);
+                    for (j = 0; j < genomeSize; j++)
+                        rperm[j] = j;
+                    // qsort(rperm, genomeSize, sizeof(int), compare_doubles);
+                    // NOTE: confirm if converted correctly
+                    QuickSort.qsort(rperm);
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        arrScales[i][j] = Math.pow(arrCondition[i], ((double) rperm[j]) / ((double) (genomeSize - 1)) - 0.5);
+                        }
+                    }
+
+                for (i = 0; i < genomeSize * NHIGHPEAKS22; i++)
+                    peaks[i] = nextDoubleClosedInterval(state.random[0]);
+                xLocal = xLocal22;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    xOpt[i] = 0.8 * (9.8 * peaks[i] - 4.9);
+                    for (j = 0; j < NHIGHPEAKS22; j++)
+                        {
+                        xLocal[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            xLocal[i][j] += rotation[i][k] * (9.8 * peaks[j * genomeSize + k] - 4.9);
+                            }
+                        if (j == 0)
+                            xLocal[i][j] *= 0.8;
+                        }
+                    }
+                break;
+                        
+            case KATSUURA:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        linearTF[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            linearTF[i][j] += rotation[i][k] * Math.pow(Math.sqrt(condition), ((double) k) / (double) (genomeSize - 1)) * rot2[k][j];
+                            }
+                        }
+                    }
+                break;
+                        
+            case LUNACEK:
+                rotation = new double[genomeSize][genomeSize];
+                rot2 = new double[genomeSize][genomeSize];
+                tmpvect = new double[genomeSize];
+                linearTF = new double[genomeSize][genomeSize];
+                double mu1 = 2.5;
+                computeXopt(xOpt, state.random[0]);
+                computeRotation(rotation, state.random[0], genomeSize);
+                computeRotation(rot2, state.random[0], genomeSize);
+                gauss(tmpvect, state.random[0]);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    xOpt[i] = 0.5 * mu1;
+                    if (tmpvect[i] < 0.)
+                        xOpt[i] *= -1.;
+                    }
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        linearTF[i][j] = 0.0;
+                        for (k = 0; k < genomeSize; k++)
+                            {
+                            linearTF[i][j] += rotation[i][k] * Math.pow(Math.sqrt(condition), ((double) k) / ((double) (genomeSize - 1))) * rot2[k][j];
+                            }
+                        }
+                    }
+                break;
+                        
+            default:
+                String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                for (i = 0; i < problemTypes.length; i++)
+                    outputStr += problemTypes[i] + "\n";
+                state.output.fatal(outputStr, base.push(P_WHICH_PROBLEM));
+            }
+
+        }
+
+    public void evaluate(EvolutionState state, Individual ind, int subpopulation, int threadnum)
+        {
+        if (!(ind instanceof DoubleVectorIndividual))
+            state.output.fatal("The individuals for this problem should be DoubleVectorIndividuals.");
+        DoubleVectorIndividual temp = (DoubleVectorIndividual) ind;
+        double[] genome = temp.genome;
+        int genomeSize = genome.length;
+        double value = 0;
+        float fit;
+        int i, j;
+        double condition, alpha, beta, tmp = 0.0, tmp2, fAdd, fPen = 0.0, x1, fac, a, f = 0.0, f2;
+        double[] tmx = new double[genomeSize];
+        double[] tmpvect = new double[genomeSize];
+        switch (problemType)
+            {
+            case SPHERE:// f1
+                        /* Sphere function */
+                fAdd = fOpt;
+                if (noise != NONE)
+                    {
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmp = Math.abs(genome[i]) - 5.;
+                        if (tmp > 0.0)
+                            {
+                            fPen += tmp * tmp;
+                            }
+                        }
+                    fAdd += 100. * fPen;
+                    }
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = genome[i] - xOpt[i];
+                    value += tmp * tmp;
+                    }
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    case GAUSSIAN_MODERATE:
+                        value = fGauss(value, 0.01, state.random[threadnum]);
+                        break;
+                    case UNIFORM_MODERATE:
+                        value = fUniform(value, 0.01 * (0.49 + 1. / genomeSize), 0.01, state.random[threadnum]);
+                        break;
+                    case CAUCHY_MODERATE:
+                        value = fCauchy(value, 0.01, 0.05, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < noiseTypes.length; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case ELLIPSOIDAL:// f2
+                /*
+                 * separable ellipsoid with monotone transformation with noiseless
+                 * condition 1e6 and noisy condition 1e4
+                 */
+                fAdd = fOpt;
+                if (noise == NONE)
+                    {
+                    condition = 1e6;
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmx[i] = genome[i] - xOpt[i];
+                        }
+                    }
+                else
+                    {
+                    condition = 1e4;
+                    fAdd = fOpt;
+
+                    /* BOUNDARY HANDLING */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmp = Math.abs(genome[i]) - 5.;
+                        if (tmp > 0.)
+                            {
+                            fPen += tmp * tmp;
+                            }
+                        }
+                    fAdd += 100. * fPen;
+
+                    /* TRANSFORMATION IN SEARCH SPACE */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmx[i] = 0.;
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            tmx[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                            }
+                        }
+                    }
+
+                monotoneTFosc(tmx);
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    value += Math.pow(condition, ((double) i) / ((double) (genomeSize - 1))) * tmx[i] * tmx[i];
+                    }
+
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < 4; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+
+            case RASTRIGIN:// f3
+                /* Rastrigin with monotone transformation separable "condition" 10 */
+                condition = 10;
+                beta = 0.2;
+                fAdd = fOpt;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = genome[i] - xOpt[i];
+                    }
+                monotoneTFosc(tmx);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = ((double) i) / ((double) (genomeSize - 1));
+                    if (tmx[i] > 0)
+                        tmx[i] = Math.pow(tmx[i], 1 + beta * tmp * Math.sqrt(tmx[i]));
+                    tmx[i] = Math.pow(Math.sqrt(condition), tmp) * tmx[i];
+                    }
+                /* COMPUTATION core */
+                tmp = 0;
+                tmp2 = 0;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp += Math.cos(2 * Math.PI * tmx[i]);
+                    tmp2 += tmx[i] * tmx[i];
+                    }
+                value = 10 * (genomeSize - tmp) + tmp2;
+                value += fAdd;
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case BUCHE_RASTRIGIN:// f4
+                /* skew Rastrigin-Bueche, condition 10, skew-"condition" 100 */
+                condition = 10.0;
+                alpha = 100;
+                fAdd = fOpt;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        fPen += tmp * tmp;
+                    }
+                fPen *= 1e2;
+                fAdd += fPen;
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = genome[i] - xOpt[i];
+                    }
+
+                monotoneTFosc(tmx);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    if (i % 2 == 0 && tmx[i] > 0)
+                        tmx[i] = Math.sqrt(alpha) * tmx[i];
+                    tmx[i] = Math.pow(Math.sqrt(condition), ((double) i) / ((double) (genomeSize - 1))) * tmx[i];
+                    }
+                /* COMPUTATION core */
+                tmp = 0.0;
+                tmp2 = 0.0;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp += Math.cos(2 * Math.PI * tmx[i]);
+                    tmp2 += tmx[i] * tmx[i];
+                    }
+                value = 10 * (genomeSize - tmp) + tmp2;
+                value += fAdd;
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case LINEAR_SLOPE:// f5
+                /* linear slope */
+                alpha = 100;
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+                /* move "too" good coordinates back into domain */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    if ((xOpt[i] == 5.) && (genome[i] > 5))
+                        tmx[i] = 5.;
+                    else if ((xOpt[i] == -5.) && (genome[i] < -5))
+                        tmx[i] = -5.;
+                    else
+                        tmx[i] = genome[i];
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    if (xOpt[i] > 0)
+                        {
+                        value -= Math.pow(Math.sqrt(alpha), ((double) i) / ((double) (genomeSize - 1))) * tmx[i];
+                        }
+                    else
+                        {
+                        value += Math.pow(Math.sqrt(alpha), ((double) i) / ((double) (genomeSize - 1))) * tmx[i];
+                        }
+                    }
+                value += fAdd;
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case ATTRACTIVE_SECTOR:// f6
+                /* attractive sector function */
+                alpha = 100.0;
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += linearTF[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    if (tmx[i] * xOpt[i] > 0)
+                        tmx[i] *= alpha;
+                    value += tmx[i] * tmx[i];
+                    }
+
+                /* monotoneTFosc... */
+                if (value > 0)
+                    {
+                    value = Math.pow(Math.exp(Math.log(value) / 0.1 + 0.49 * (Math.sin(Math.log(value) / 0.1) + Math.sin(0.79 * Math.log(value) / 0.1))), 0.1);
+                    }
+                else if (value < 0)
+                    {
+                    value = -Math.pow(Math.exp(Math.log(-value) / 0.1 + 0.49 * (Math.sin(0.55 * Math.log(-value) / 0.1) + Math.sin(0.31 * Math.log(-value) / 0.1))), 0.1);
+                    }
+                value = Math.pow(value, 0.9);
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case STEP_ELLIPSOIDAL:// f7
+                /* step-ellipsoid, condition 100 */
+                condition = 100.0;
+                alpha = 10.0;
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.0;
+                    if (tmp > 0.0)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                if (noise == NONE)
+                    fAdd += fPen;
+                else
+                    fAdd += 100. * fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+
+                    tmpvect[i] = 0.0;
+                    tmp = Math.sqrt(Math.pow(condition / 10., ((double) i) / ((double) (genomeSize - 1))));
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmpvect[i] += tmp * rot2[i][j] * (genome[j] - xOpt[j]);
+                        }
+
+                    }
+                x1 = tmpvect[0];
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    if (Math.abs(tmpvect[i]) > 0.5)
+                        tmpvect[i] = Math.round(tmpvect[i]);
+                    else
+                        tmpvect[i] = Math.round(alpha * tmpvect[i]) / alpha;
+                    }
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * tmpvect[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    value += Math.pow(condition, ((double) i) / ((double) (genomeSize - 1))) * tmx[i] * tmx[i];
+                    }
+                value = 0.1 * Math.max(1e-4 * Math.abs(x1), value);
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < 4; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case ROSENBROCK:// f8
+                /* Rosenbrock, non-rotated */
+                fAdd = fOpt;
+                if (noise == NONE)
+                    {
+                    /* TRANSFORMATION IN SEARCH SPACE */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmx[i] = scales * (genome[i] - xOpt[i]) + 1;
+                        }
+                    }
+                else
+                    {
+                    /* BOUNDARY HANDLING */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmp = Math.abs(genome[i]) - 5.;
+                        if (tmp > 0.)
+                            {
+                            fPen += tmp * tmp;
+                            }
+                        }
+                    fAdd += 100.0 * fPen;
+                    /* TRANSFORMATION IN SEARCH SPACE */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmx[i] = scales * (genome[i] - 0.75 * xOpt[i]) + 1;
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize - 1; i++)
+                    {
+                    tmp = (tmx[i] * tmx[i] - tmx[i + 1]);
+                    value += tmp * tmp;
+                    }
+                value *= 1e2;
+                for (i = 0; i < genomeSize - 1; i++)
+                    {
+                    tmp = (tmx[i] - 1.);
+                    value += tmp * tmp;
+                    }
+
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    case GAUSSIAN_MODERATE:
+                        value = fGauss(value, 0.01, state.random[threadnum]);
+                        break;
+                    case UNIFORM_MODERATE:
+                        value = fUniform(value, 0.01 * (0.49 + 1. / genomeSize), 0.01, state.random[threadnum]);
+                        break;
+                    case CAUCHY_MODERATE:
+                        value = fCauchy(value, 0.01, 0.05, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < noiseTypes.length; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }                       
+                        
+                value += fAdd;
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+
+                        
+                        
+                        
+            case ROSENBROCK_ROTATED:// f9
+                /* Rosenbrock, rotated */
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.5;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += linearTF[i][j] * genome[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize - 1; i++)
+                    {
+                    tmp = (tmx[i] * tmx[i] - tmx[i + 1]);
+                    value += tmp * tmp;
+                    }
+                value *= 1e2;
+                for (i = 0; i < genomeSize - 1; i++)
+                    {
+                    tmp = (tmx[i] - 1.);
+                    value += tmp * tmp;
+                    }
+
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case ELLIPSOIDAL_2:// f10
+                /* ellipsoid with monotone transformation, condition 1e6 */
+                condition = 1e6;
+
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                monotoneTFosc(tmx);
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    fAdd += Math.pow(condition, ((double) i) / ((double) (genomeSize - 1))) * tmx[i] * tmx[i];
+                    }
+                value = fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case DISCUS:// f11
+                        /* DISCUS (tablet) with monotone transformation, condition 1e6 */
+                condition = 1e6;
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                monotoneTFosc(tmx);
+
+                /* COMPUTATION core */
+                value = condition * tmx[0] * tmx[0];
+                for (i = 1; i < genomeSize; i++)
+                    {
+                    value += tmx[i] * tmx[i];
+                    }
+                value += fAdd; /* without noise */
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case BENT_CIGAR:// f12
+                /* bent cigar with asymmetric space distortion, condition 1e6 */
+                condition = 1e6;
+                beta = 0.5;
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmpvect[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmpvect[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    if (tmpvect[i] > 0)
+                        {
+                        tmpvect[i] = Math.pow(tmpvect[i], 1 + beta * ((double) i) / ((double) (genomeSize - 1)) * Math.sqrt(tmpvect[i]));
+                        }
+                    }
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * tmpvect[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                value = tmx[0] * tmx[0];
+                for (i = 1; i < genomeSize; i++)
+                    {
+                    value += condition * tmx[i] * tmx[i];
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case SHARP_RIDGE:// f13
+                /* sharp ridge */
+                condition = 10.0;
+                alpha = 100.0;
+
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += linearTF[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 1; i < genomeSize; i++)
+                    {
+                    value += tmx[i] * tmx[i];
+                    }
+                value = alpha * Math.sqrt(value);
+                value += tmx[0] * tmx[0];
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case DIFFERENT_POWERS:// f14
+                /* sum of different powers, between x^2 and x^6 */
+                alpha = 4.0;
+                fAdd = fOpt;
+                if (noise != NONE)
+                    {
+                    /* BOUNDARY HANDLING */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmp = Math.abs(genome[i]) - 5.;
+                        if (tmp > 0.)
+                            {
+                            fPen += tmp * tmp;
+                            }
+                        }
+                    fAdd += 100. * fPen;
+                    }
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    value += Math.pow(Math.abs(tmx[i]), 2. + alpha * ((double) i) / ((double) (genomeSize - 1)));
+                    }
+                value = Math.sqrt(value);
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < 4; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case RASTRIGIN_2:// f15
+                /* Rastrigin with asymmetric non-linear distortion, "condition" 10 */
+                condition = 10.0;
+                beta = 0.2;
+                tmp = tmp2 = 0;
+
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmpvect[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmpvect[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                monotoneTFosc(tmpvect);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    if (tmpvect[i] > 0)
+                        tmpvect[i] = Math.pow(tmpvect[i], 1 + beta * ((double) i) / ((double) (genomeSize - 1)) * Math.sqrt(tmpvect[i]));
+                    }
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += linearTF[i][j] * tmpvect[j];
+                        }
+                    }
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp += Math.cos(2. * Math.PI * tmx[i]);
+                    tmp2 += tmx[i] * tmx[i];
+                    }
+                value = 10. * ((double) genomeSize - tmp) + tmp2;
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case WEIERSTRASS:// f16
+                /* Weierstrass, condition 100 */
+                condition = 100.0;
+                fPen = 0;
+
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += 10. / (double) genomeSize * fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmpvect[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmpvect[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    }
+
+                monotoneTFosc(tmpvect);
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += linearTF[i][j] * tmpvect[j];
+                        }
+                    }
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = 0.0;
+                    for (j = 0; j < 12; j++)
+                        {
+                        tmp += Math.cos(2 * Math.PI * (tmx[i] + 0.5) * bK[j]) * aK[j];
+                        }
+                    value += tmp;
+                    }
+                value = 10. * Math.pow(value / (double) genomeSize - f0, 3.);
+                value += fAdd;
+                ;
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case SCHAFFERS_F7:// f17
+                /*
+                 * Schaffers F7 with asymmetric non-linear transformation, condition
+                 * 10
+                 */
+                condition = 10.0;
+                beta = 0.5;
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += 10. * fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmpvect[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmpvect[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    if (tmpvect[i] > 0)
+                        tmpvect[i] = Math.pow(tmpvect[i], 1 + beta * ((double) i) / ((double) (genomeSize - 1)) * Math.sqrt(tmpvect[i]));
+                    }
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    tmp = Math.pow(Math.sqrt(condition), ((double) i) / ((double) (genomeSize - 1)));
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += tmp * rot2[i][j] * tmpvect[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize - 1; i++)
+                    {
+                    tmp = tmx[i] * tmx[i] + tmx[i + 1] * tmx[i + 1];
+                    value += Math.pow(tmp, 0.25) * (Math.pow(Math.sin(50 * Math.pow(tmp, 0.1)), 2.0) + 1.0);
+                    }
+                value = Math.pow(value / (double) (genomeSize - 1), 2.);
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < 4; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case SCHAFFERS_F7_2:// f18
+                /*
+                 * Schaffers F7 with asymmetric non-linear transformation, condition
+                 * 1000
+                 */
+                condition = 1e3;
+                beta = 0.5;
+                fPen = 0.0;
+                fAdd = fOpt;
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += 10. * fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmpvect[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmpvect[i] += rotation[i][j] * (genome[j] - xOpt[j]);
+                        }
+                    if (tmpvect[i] > 0)
+                        tmpvect[i] = Math.pow(tmpvect[i], 1. + beta * ((double) i) / ((double) (genomeSize - 1)) * Math.sqrt(tmpvect[i]));
+                    }
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    tmp = Math.pow(Math.sqrt(condition), ((double) i) / ((double) (genomeSize - 1)));
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += tmp * rot2[i][j] * tmpvect[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize - 1; i++)
+                    {
+                    tmp = tmx[i] * tmx[i] + tmx[i + 1] * tmx[i + 1];
+                    value += Math.pow(tmp, 0.25) * (Math.pow(Math.sin(50. * Math.pow(tmp, 0.1)), 2.) + 1.);
+                    }
+                value = Math.pow(value / (double) (genomeSize - 1), 2.);
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case GRIEWANK_ROSENBROCK:// f19
+                /* F8f2 sum of Griewank-Rosenbrock 2-D blocks */
+                fAdd = fOpt;
+                if (noise == NONE)
+                    {
+                    /* TRANSFORMATION IN SEARCH SPACE */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmx[i] = 0.5;
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            tmx[i] += linearTF[i][j] * genome[j];
+                            }
+                        }
+                    /* COMPUTATION core */
+                    for (i = 0; i < genomeSize - 1; i++)
+                        {
+                        tmp2 = tmx[i] * tmx[i] - tmx[i + 1];
+                        f2 = 100. * tmp2 * tmp2;
+                        tmp2 = 1 - tmx[i];
+                        f2 += tmp2 * tmp2;
+                        tmp += f2 / 4000. - Math.cos(f2);
+                        }
+                    value = 10. + 10. * tmp / (double) (genomeSize - 1);
+                    }
+                else
+                    {
+                    /* BOUNDARY HANDLING */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmp = Math.abs(genome[i]) - 5.0;
+                        if (tmp > 0.0)
+                            {
+                            fPen += tmp * tmp;
+                            }
+                        }
+                    fAdd += 100.0 * fPen;
+
+                    /* TRANSFORMATION IN SEARCH SPACE */
+                    for (i = 0; i < genomeSize; i++)
+                        {
+                        tmx[i] = 0.5;
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            tmx[i] += scales * rotation[i][j] * genome[j];
+                            }
+                        }
+                    /* COMPUTATION core */
+                    tmp = 0.;
+                    for (i = 0; i < genomeSize - 1; i++)
+                        {
+                        f2 = 100. * (tmx[i] * tmx[i] - tmx[i + 1]) * (tmx[i] * tmx[i] - tmx[i + 1]) + (1 - tmx[i]) * (1 - tmx[i]);
+                        tmp += f2 / 4000. - Math.cos(f2);
+                        }
+                    value = 1. + 1. * tmp / (double) (genomeSize - 1);
+                    }
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < 4; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case SCHWEFEL:// f20
+                /* Schwefel with tridiagonal variable transformation */
+                condition = 10.0;
+                fPen = 0.0;
+                fAdd = fOpt;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmpvect[i] = 2. * genome[i];
+                    if (xOpt[i] < 0.)
+                        tmpvect[i] *= -1.;
+                    }
+
+                tmx[0] = tmpvect[0];
+                for (i = 1; i < genomeSize; i++)
+                    {
+                    tmx[i] = tmpvect[i] + 0.25 * (tmpvect[i - 1] - 2. * Math.abs(xOpt[i - 1]));
+                    }
+
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] -= 2 * Math.abs(xOpt[i]);
+                    tmx[i] *= Math.pow(Math.sqrt(condition), ((double) i) / ((double) (genomeSize - 1)));
+                    tmx[i] = 100. * (tmx[i] + 2 * Math.abs(xOpt[i]));
+                    }
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(tmx[i]) - 500.0;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += 0.01 * fPen;
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    value += tmx[i] * Math.sin(Math.sqrt(Math.abs(tmx[i])));
+                    }
+                value = 0.01 * ((418.9828872724339) - value / (double) genomeSize);
+                value += fAdd;/* without noise */
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case GALLAGHER_GAUSSIAN_101ME:// f21
+                /*
+                 * Gallagher with 101 Gaussian peaks, condition up to 1000, one
+                 * global rotation
+                 */
+                a = 0.1;
+                fac = -0.5 / (double) genomeSize;
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                if (noise == NONE)
+                    fAdd += fPen;
+                else
+                    fAdd += 100. * fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * genome[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                if (noise == NONE)
+                    for (i = 0; i < NHIGHPEAKS21; i++)
+                        {
+                        tmp2 = 0.0;
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            tmp = (tmx[j] - xLocal[j][i]);
+                            tmp2 += arrScales[i][j] * tmp * tmp;
+                            }
+                        tmp2 = peakvalues[i] * Math.exp(fac * tmp2);
+                        f = Math.max(f, tmp2);
+                        }
+                else
+                    /* COMPUTATION core */
+                    for (i = 0; i < NHIGHPEAKS21; i++)
+                        {
+                        tmp2 = 0.;
+                        for (j = 0; j < genomeSize; j++)
+                            {
+                            tmp2 += arrScales[i][j] * (tmx[j] - xLocal[j][i]) * (tmx[j] - xLocal[j][i]);
+                            }
+                        tmp2 = peakvalues[i] * Math.exp(fac * tmp2);
+                        f = Math.max(f, tmp2);
+                        }
+
+                f = 10.0 - f;
+                /* monotoneTFosc */
+                if (f > 0)
+                    {
+                    value = Math.log(f) / a;
+                    value = Math.pow(Math.exp(value + 0.49 * (Math.sin(value) + Math.sin(0.79 * value))), a);
+                    }
+                else if (f < 0)
+                    {
+                    value = Math.log(-f) / a;
+                    value = -Math.pow(Math.exp(value + 0.49 * (Math.sin(0.55 * value) + Math.sin(0.31 * value))), a);
+                    }
+                else
+                    value = f;
+
+                value *= value;
+                switch (noise)
+                    {
+                    case NONE:
+                        break;
+                    case GAUSSIAN:
+                        value = fGauss(value, 1.0, state.random[threadnum]);
+                        break;
+                    case UNIFORM:
+                        value = fUniform(value, 0.49 + 1.0 / genomeSize, 1.0, state.random[threadnum]);
+                        break;
+                    case CAUCHY:
+                        value = fCauchy(value, 1.0, 0.2, state.random[threadnum]);
+                        break;
+                    default:
+                        String outputStr = "Invalid value for parameter, or parameter not found.\n" + "Acceptable values are:\n";
+                        for (i = 0; i < 4; i++)
+                            outputStr += noiseTypes[i] + "\n";
+                        state.output.fatal(outputStr, new Parameter(P_NOISE));
+                        break;
+                    }
+                value += fAdd;
+                ; /* without noise */
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case GALLAGHER_GAUSSIAN_21HI:// f22
+                /*
+                 * Gallagher with 21 Gaussian peaks, condition up to 1000, one
+                 * global rotation
+                 */
+                a = 0.1;
+                f = 0;
+                fac = -0.5 / (double) genomeSize;
+                fPen = 0.0;
+
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmx[i] += rotation[i][j] * genome[j];
+                        }
+                    }
+
+                /* COMPUTATION core */
+                for (i = 0; i < NHIGHPEAKS22; i++)
+                    {
+                    tmp2 = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmp = (tmx[j] - xLocal[j][i]);
+                        tmp2 += arrScales[i][j] * tmp * tmp;
+                        }
+                    tmp2 = peakvalues[i] * Math.exp(fac * tmp2);
+                    f = Math.max(f, tmp2);
+                    }
+
+                f = 10. - f;
+                if (f > 0)
+                    {
+                    value = Math.log(f) / a;
+                    value = Math.pow(Math.exp(value + 0.49 * (Math.sin(value) + Math.sin(0.79 * value))), a);
+                    }
+                else if (f < 0)
+                    {
+                    value = Math.log(-f) / a;
+                    value = -Math.pow(Math.exp(value + 0.49 * (Math.sin(0.55 * value) + Math.sin(0.31 * value))), a);
+                    }
+                else
+                    value = f;
+
+                value *= value;
+                value += fAdd;
+                ; /* without noise */
+
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case KATSUURA:// f23
+                /* Katsuura function */
+                condition = 100.0;
+                fAdd = 0;
+                fPen = 0;
+                double arr;
+                double prod = 1.0;
+                double[] ptmx,
+                    plinTF,
+                    ptmp;
+
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                /* write rotated difference vector into tmx */
+                for (j = 0; j < genomeSize; j++)
+                    /* store difference vector */
+                    tmpvect[j] = genome[j] - xOpt[j];
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 0.0;
+                    ptmx = tmx;
+                    plinTF = linearTF[i];
+                    ptmp = tmpvect;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        // *ptmx += *plinTF++ * *ptmp++;
+                        ptmx[j] += plinTF[j] * ptmp[j];
+                        }
+                    }
+
+                /*
+                 * for (i = 0; i < genomeSize; i++) { tmx[i] = 0.0; for (j = 0; j <
+                 * genomeSize; j++) { tmx[i] += linearTF[i][j] * (genome[j] -
+                 * xOpt[j]); } }
+                 */
+
+                /* COMPUTATION core */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = 0.0;
+                    for (j = 1; j < 33; j++)
+                        {
+                        tmp2 = Math.pow(2., (double) j);
+                        arr = tmx[i] * tmp2;
+                        tmp += Math.abs(arr - Math.round(arr)) / tmp2;
+                        }
+                    tmp = 1. + tmp * (double) (i + 1);
+                    prod *= tmp;
+                    }
+                value = 10. / (double) genomeSize / (double) genomeSize * (-1. + Math.pow(prod, 10. / Math.pow((double) genomeSize, 1.2)));
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+                        
+                        
+                        
+            case LUNACEK:// f24
+                /* Lunacek bi-Rastrigin, condition 100 */
+                /* in PPSN 2008, Rastrigin part rotated and scaled */
+                condition = 100.0;
+                double mu1 = 2.5;
+                double tmp3,
+                    tmp4;
+                fPen = tmp2 = tmp3 = tmp4 = 0.0;
+                double s = 1. - 0.5 / (Math.sqrt((double) (genomeSize + 20)) - 4.1);
+                double d = 1.;
+                double mu2 = -Math.sqrt((mu1 * mu1 - d) / s);
+
+                fAdd = fOpt;
+
+                /* BOUNDARY HANDLING */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp = Math.abs(genome[i]) - 5.;
+                    if (tmp > 0.)
+                        {
+                        fPen += tmp * tmp;
+                        }
+                    }
+                fAdd += 1e4 * fPen;
+
+                /* TRANSFORMATION IN SEARCH SPACE */
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmx[i] = 2. * genome[i];
+                    if (xOpt[i] < 0.)
+                        tmx[i] *= -1.;
+                    }
+
+                /* COMPUTATION core */
+                tmp = 0.0;
+                for (i = 0; i < genomeSize; i++)
+                    {
+                    tmp2 += (tmx[i] - mu1) * (tmx[i] - mu1);
+                    tmp3 += (tmx[i] - mu2) * (tmx[i] - mu2);
+                    tmp4 = 0.0;
+                    for (j = 0; j < genomeSize; j++)
+                        {
+                        tmp4 += linearTF[i][j] * (tmx[j] - mu1);
+                        }
+                    tmp += Math.cos(2 * Math.PI * tmp4);
+                    }
+                value = Math.min(tmp2, d * (double) genomeSize + s * tmp3) + 10. * ((double) genomeSize - tmp);
+                value += fAdd;
+                fit = (float) (-value);
+                ((SimpleFitness) (ind.fitness)).setFitness(state, fit, fit == 0.0f);
+            break;
+            default:
+                break;
+            }
+        }
+
+
+    final static public double TOL = 1e-8;
+
+    void gauss(double[] g, MersenneTwisterFast random)
+        {
+        /*
+         * samples N standard normally distributed numbers being the same for a
+         * given seed.
+         */
+        double[] uniftmp = new double[2 * g.length];
+        int i;
+        for (i = 0; i < uniftmp.length; i++)
+            uniftmp[i] = nextDoubleClosedInterval(random);
+        for (i = 0; i < g.length; i++)
+            {
+
+            g[i] = Math.sqrt(-2 * Math.log(uniftmp[i])) * Math.cos(2 * Math.PI * uniftmp[g.length + i]);
+            if (g[i] == 0.0)
+                g[i] = 1e-99;
+            }
+        return;
+        }
+
+    void gauss(double[] g, MersenneTwisterFast random, int n)
+        {
+        /*
+         * samples N standard normally distributed numbers being the same for a
+         * given seed.
+         */
+        double[] uniftmp = new double[2 * g.length];
+        int i;
+        for (i = 0; i < uniftmp.length; i++)
+            uniftmp[i] = nextDoubleClosedInterval(random);
+        for (i = 0; i < n; i++)
+            {
+            g[i] = Math.sqrt(-2 * Math.log(uniftmp[i])) * Math.cos(2 * Math.PI * uniftmp[n + i]);
+            if (g[i] == 0.0)
+                g[i] = 1e-99;
+            }
+        return;
+        }
+
+    void computeXopt(double[] xOpt, MersenneTwisterFast random)
+        {
+        int i;
+        int n = xOpt.length;
+        for (i = 0; i < n; i++)
+            {
+            xOpt[i] = 8 * (int) Math.floor(1e4 * nextDoubleClosedInterval(random)) / 1e4 - 4;
+            if (xOpt[i] == 0.0)
+                xOpt[i] = -1e-5;
+            }
+        }
+
+    void monotoneTFosc(double[] f)
+        {
+        double a = 0.1;
+        int i;
+        int n = f.length;
+        for (i = 0; i < n; i++)
+            {
+            if (f[i] > 0)
+                {
+                f[i] = Math.log(f[i]) / a;
+                f[i] = Math.pow(Math.exp(f[i] + 0.49 * (Math.sin(f[i]) + Math.sin(0.79 * f[i]))), a);
+                }
+            else if (f[i] < 0)
+                {
+                f[i] = Math.log(-f[i]) / a;
+                f[i] = -Math.pow(Math.exp(f[i] + 0.49 * (Math.sin(0.55 * f[i]) + Math.sin(0.31 * f[i]))), a);
+                }
+            }
+        }
+
+    double[][] reshape(double[][] b, double[] vector, int m, int n)
+        {
+        int i, j;
+        for (i = 0; i < m; i++)
+            {
+            for (j = 0; j < n; j++)
+                {
+                b[i][j] = vector[j * m + i];
+                }
+            }
+        return b;
+        }
+
+    void computeRotation(double[][] b, MersenneTwisterFast random, int genomeSize)
+        {
+        double[] gvect = new double[genomeSize * genomeSize];
+        double prod;
+        int i, j, k; /* Loop over pairs of column vectors */
+
+        gauss(gvect, random);
+        reshape(b, gvect, genomeSize, genomeSize);
+        /* 1st coordinate is row, 2nd is column. */
+
+        for (i = 0; i < genomeSize; i++)
+            {
+            for (j = 0; j < i; j++)
+                {
+                prod = 0;
+                for (k = 0; k < genomeSize; k++)
+                    {
+                    prod += b[k][i] * b[k][j];
+                    }
+                for (k = 0; k < genomeSize; k++)
+                    {
+                    b[k][i] -= prod * b[k][j];
+                    }
+                }
+            prod = 0;
+            for (k = 0; k < genomeSize; k++)
+                {
+                prod += b[k][i] * b[k][i];
+                }
+            for (k = 0; k < genomeSize; k++)
+                {
+                b[k][i] /= Math.sqrt(prod);
+                }
+            }
+        }
+
+    double fGauss(double fTrue, double beta, MersenneTwisterFast random)
+        {
+        double fVal = fTrue * Math.exp(beta * nextDoubleClosedInterval(random));
+        fVal += 1.01 * TOL;
+        if (fTrue < TOL)
+            {
+            fVal = fTrue;
+            }
+        return fVal;
+        }
+
+    double fUniform(double fTrue, double alpha, double beta, MersenneTwisterFast random)
+        {
+        double fVal = Math.pow(nextDoubleClosedInterval(random), beta) * fTrue * Math.max(1.0, Math.pow(1e9 / (fTrue + 1e-99), alpha * nextDoubleClosedInterval(random)));
+        fVal += 1.01 * TOL;
+        if (fTrue < TOL)
+            {
+            fVal = fTrue;
+            }
+        return fVal;
+        }
+
+    double fCauchy(double fTrue, double alpha, double p, MersenneTwisterFast random)
+        {
+        double fVal;
+        double tmp = nextDoubleClosedInterval(random) / Math.abs(nextDoubleClosedInterval(random) + 1e-199);
+        /*
+         * tmp is so as to actually do the calls to randn in order for the
+         * number of calls to be the same as in the Matlab code.
+         */
+        if (nextDoubleClosedInterval(random) < p)
+            fVal = fTrue + alpha * Math.max(0., 1e3 + tmp);
+        else
+            fVal = fTrue + alpha * 1e3;
+
+        fVal += 1.01 * TOL;
+        if (fTrue < TOL)
+            {
+            fVal = fTrue;
+            }
+        return fVal;
+        }
+
+    double computeFopt(MersenneTwisterFast random)
+        {
+        double[] gval = new double[1];
+        double[] gval2 = new double[1];
+        gauss(gval, random, 1);
+        gauss(gval2, random, 1);
+        return Math.min(1000.0, Math.max(-1000.0, (Math.round(100.0 * 100.0 * gval[0] / gval2[0]) / 100.0)));
+        }
+
+    double nextDoubleClosedInterval(MersenneTwisterFast random)
+        {
+        double tmp = random.nextDouble() * 2.0;
+        while (tmp > 1.0)
+            tmp = random.nextDouble() * 2.0;
+        return tmp;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/bbob.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/bbob.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/bbob.params	(revision 6152)
@@ -0,0 +1,46 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../ec.params
+
+eval.problem = ec.app.bbob.BBOBenchmarks
+eval.problem.type = sphere
+noise		= 	none
+
+
+
+state = 				ec.simple.SimpleEvolutionState
+init = 					ec.simple.SimpleInitializer
+finish = 	        		ec.simple.SimpleFinisher
+exch = 					ec.simple.SimpleExchanger
+breed =					ec.simple.SimpleBreeder
+eval =					ec.simple.SimpleEvaluator
+stat =					ec.simple.SimpleStatistics
+generations =				50
+quit-on-run-complete =			true
+pop = 					ec.Population
+pop.subpops =				1
+pop.subpop.0 = 				ec.Subpopulation
+pop.subpop.0.duplicate-retries =	2
+pop.subpop.0.species =                  ec.vector.FloatVectorSpecies
+pop.subpop.0.species.pipe = 		ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0 = 	ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same
+
+pop.subpop.0.species.fitness =		ec.simple.SimpleFitness
+pop.subpop.0.species.ind =		ec.vector.DoubleVectorIndividual
+
+# you can change these to whatever tickles your fancy
+pop.subpop.0.species.min-gene =	-5.12
+pop.subpop.0.species.max-gene =	5.12
+pop.subpop.0.species.genome-size = 	50
+
+
+select.tournament.size = 		2
+pop.subpop.0.species.mutation-prob = 0.005
+pop.subpop.0.species.crossover-type = one
+
+pop.subpop.0.size =			200
+stat.file				$out.stat
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/de.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/de.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/bbob/de.params	(revision 6152)
@@ -0,0 +1,21 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =				bbob.params
+
+breed =                                 ec.de.DEBreeder
+# Other breed choices: ec.de.Best1BinDEBreeder, ec.de.Rand1EitherOrDEBreeder,
+# ec.de.Rand1ExpDEBreeder
+
+
+# Differential Evolution requires a special statistics object 
+# (ec.de.DEStatistics) to deal with certain issues that arise in parent/child 
+# competition.  See the DEStatistics documentation for more discussion.  The 
+# way we use the object is as the primary statistics object, and then we hang
+# SimpleStatistics as a subsidiary statistics object off of it like so:
+stat = 					ec.de.DEStatistics
+stat.num-children = 			1
+stat.child.0 = 				ec.simple.SimpleStatistics
+stat.child.0.file = 			$out.stat
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve1/CompetitiveMaxOne.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve1/CompetitiveMaxOne.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve1/CompetitiveMaxOne.java	(revision 6152)
@@ -0,0 +1,118 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.coevolve1;
+
+import ec.simple.SimpleFitness;
+import ec.coevolve.*;
+import ec.*;
+import ec.vector.*;
+
+public class CompetitiveMaxOne extends Problem implements GroupedProblemForm
+    {
+
+    public void preprocessPopulation( final EvolutionState state, Population pop, boolean countVictoriesOnly )
+        {
+        for( int i = 0 ; i < pop.subpops.length ; i++ )
+            for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
+                {
+                SimpleFitness sf = ((SimpleFitness)(pop.subpops[i].individuals[j].fitness));
+                sf.trials = 0;
+                sf.setFitness( state, 0, false );
+                }
+        }
+
+    public void postprocessPopulation( final EvolutionState state, Population pop, boolean countVictoriesOnly )
+        {
+        for( int i = 0 ; i < pop.subpops.length ; i++ )
+            for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
+                {
+                if (!countVictoriesOnly)   // gotta average by number of trials
+                    {
+                    SimpleFitness sf = ((SimpleFitness)(pop.subpops[i].individuals[j].fitness));
+                    sf.setFitness( state, sf.fitness() / sf.trials, false );
+                    }
+                pop.subpops[i].individuals[j].evaluated = true;
+                }
+        }
+
+    public void evaluate(final EvolutionState state,
+        final Individual[] ind,  // the individuals to evaluate together
+        final boolean[] updateFitness,  // should this individuals' fitness be updated?
+        final boolean countVictoriesOnly,
+        int[] subpops,
+        final int threadnum)
+        {
+        if( ind.length != 2 || updateFitness.length != 2 )
+            state.output.fatal( "The InternalSumProblem evaluates only two individuals at a time." );
+
+        if( ! ( ind[0] instanceof BitVectorIndividual ) )
+            state.output.fatal( "The individuals in the InternalSumProblem should be FloatVectorIndividuals." );
+
+        if( ! ( ind[1] instanceof BitVectorIndividual ) )
+            state.output.fatal( "The individuals in the InternalSumProblem should be FloatVectorIndividuals." );
+        
+        int value1=0;
+        int value2=0;
+
+        BitVectorIndividual temp;
+
+        // calculate the function value for the first individual
+        temp = (BitVectorIndividual)ind[0];
+        for( int i = 0 ; i < temp.genome.length ; i++ )
+            if( temp.genome[i] ) value1++;
+
+        // calculate the function value for the second individual
+        temp = (BitVectorIndividual)ind[1];
+        for( int i = 0 ; i < temp.genome.length ; i++ )
+            if( temp.genome[i] ) value2 ++;
+
+        boolean firstWinsIfDraw = false;
+        if( value1 == value2 )
+            firstWinsIfDraw = state.random[threadnum].nextBoolean( 0.5 );
+
+        if( updateFitness[0] )
+            {
+            SimpleFitness fit = ((SimpleFitness)(ind[0].fitness));
+            fit.trials++;
+            if( countVictoriesOnly )
+                {
+                if( ( value1 > value2 ) || 
+                    ( value1 == value2 && firstWinsIfDraw ) )
+                    {
+                    fit.setFitness( state, (float)(fit.fitness() + 1), false );
+                    }
+                }
+            else
+                fit.setFitness( state, (float)(fit.fitness() + value1 - value2), false );
+            }
+
+        if( updateFitness[1] )
+            {
+            SimpleFitness fit = ((SimpleFitness)(ind[1].fitness));
+            fit.trials++;
+
+            if( countVictoriesOnly )
+                {
+                if( ( value2 > value1 ) ||
+                    ( value2 == value1 && !firstWinsIfDraw ) )
+                    {
+                    fit.setFitness( state, (float)(fit.fitness() + 1), false );
+                    }
+                }
+            else
+                fit.setFitness( state, (float)(fit.fitness() + value2 - value1), false );
+            }
+
+        }
+
+    }
+
+
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve1/coevolve1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve1/coevolve1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve1/coevolve1.params	(revision 6152)
@@ -0,0 +1,61 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 				../../simple/simple.params
+
+generations =				100
+quit-on-run-complete =			true
+eval =					ec.coevolve.CompetitiveEvaluator
+
+pop = 					ec.Population
+pop.subpops =				1
+pop.subpop.0 = 				ec.Subpopulation
+pop.subpop.0.size =			31
+pop.subpop.0.duplicate-retries =	2
+pop.subpop.0.species =                  ec.vector.VectorSpecies
+pop.subpop.0.species.genome-size = 	50
+pop.subpop.0.species.chunk-size =	1
+pop.subpop.0.species.pipe = 		ec.breed.ForceBreedingPipeline
+pop.subpop.0.species.pipe.num-inds = 	2
+pop.subpop.0.species.pipe.source.0 = 	ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0.source.0 =			ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0.source.0 = 		ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.0.source.0.size = 	3
+pop.subpop.0.species.pipe.source.0.source.0.source.1 = 	  	same
+pop.subpop.0.species.pipe.source.0.source.0.source.1.size = 	3
+
+pop.subpop.0.species.fitness =		ec.simple.SimpleFitness
+pop.subpop.0.species.ind =		ec.vector.BitVectorIndividual
+pop.subpop.0.species.mutation-prob = 	0.01
+pop.subpop.0.species.crossover-type = 	one
+
+stat.file				$out.stat
+
+select.tournament.size = 2
+
+eval.problem =				ec.app.coevolve1.CompetitiveMaxOne
+eval.problem.hist-size =		1
+stat.child.0.hist-size =		1
+stat.child.0.file =			compete.stat
+
+stat =					ec.simple.SimpleStatistics
+stat.gather-full =			true
+stat.num-children =			0
+
+breed.elite.0 =				1
+
+# for single elimination tournament
+#eval.style =				single-elim-tournament
+
+# for round robin
+#eval.style =				round-robin
+
+# for random one way tournament
+eval.style =				rand-1-way
+eval.group-size =			7
+
+# for random two way tournament
+#eval.style =				rand-2-way
+#eval.group-size =			7
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryDoubleVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryDoubleVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryDoubleVectorIndividual.java	(revision 6152)
@@ -0,0 +1,33 @@
+package ec.app.coevolve2;
+
+import ec.*;
+import ec.coevolve.*;
+import ec.vector.DoubleVectorIndividual;
+import ec.simple.SimpleFitness;
+
+/** This class exists solely to print out the DoubleVectorIndividual and its collaborators in 
+    a nice way for statistics purposes. */
+        
+public class CoevolutionaryDoubleVectorIndividual extends DoubleVectorIndividual
+    {
+    public CoevolutionaryDoubleVectorIndividual[] context;
+    boolean dontPrintContext = false;
+
+    public void printIndividualForHumans(EvolutionState state, int log)
+        {
+        super.printIndividualForHumans(state, log);
+        if (!dontPrintContext && context != null)
+            {
+            for(int i = 0; i < context.length; i++)
+                if (context[i] != null)
+                    {
+                    state.output.println("--Collaborator " + i + ":", log);
+                    // this is a hack but it should be fine because printing
+                    // individuals for humans is essentially always single-threaded
+                    context[i].dontPrintContext = true;
+                    context[i].printIndividualForHumans(state, log);
+                    context[i].dontPrintContext = false;
+                    }
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryECSuite.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryECSuite.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryECSuite.java	(revision 6152)
@@ -0,0 +1,88 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.coevolve2;
+
+import ec.*;
+import ec.app.ecsuite.*;
+import ec.coevolve.*;
+import ec.vector.DoubleVectorIndividual;
+import ec.simple.SimpleFitness;
+
+public class CoevolutionaryECSuite extends ECSuite implements GroupedProblemForm
+    {
+    public void preprocessPopulation(final EvolutionState state, Population pop, boolean countVictoriesOnly)
+        {
+        for( int i = 0 ; i < pop.subpops.length ; i++ )
+            for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
+                ((SimpleFitness)(pop.subpops[i].individuals[j].fitness)).setFitness( state, Integer.MIN_VALUE, false );
+        }
+
+    public void postprocessPopulation(final EvolutionState state, Population pop, boolean countVictoriesOnly)
+        {
+        for( int i = 0 ; i < pop.subpops.length ; i++ )
+            for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
+                pop.subpops[i].individuals[j].evaluated = true;
+        }
+
+    public void evaluate(final EvolutionState state,
+        final Individual[] ind,  // the individuals to evaluate together
+        final boolean[] updateFitness,  // should this individuals' fitness be updated?
+        final boolean countVictoriesOnly, // can be neglected in cooperative coevolution
+        int[] subpops,
+        final int threadnum)
+        {
+        if (ind.length == 0)
+            state.output.fatal("Number of individuals provided to CoevolutionaryECSuite is 0!");
+        if (ind.length == 1)
+            state.output.warnOnce("Coevolution used, but number of individuals provided to CoevolutionaryECSuite is 1.");
+                
+        int size = 0;
+        for(int i = 0 ; i < ind.length; i++)
+            if ( ! ( ind[i] instanceof CoevolutionaryDoubleVectorIndividual ) )
+                state.output.error( "Individual " + i + "in coevolution is not a CoevolutionaryDoubleVectorIndividual." );
+            else
+                {
+                CoevolutionaryDoubleVectorIndividual coind = (CoevolutionaryDoubleVectorIndividual)(ind[i]);
+                size += coind.genome.length;
+                }
+        state.output.exitIfErrors();
+                
+        // concatenate all the arrays
+        double[] vals = new double[size];
+        int pos = 0;
+        for(int i = 0 ; i < ind.length; i++)
+            {
+            System.err.println("-->" + i);
+            CoevolutionaryDoubleVectorIndividual coind = (CoevolutionaryDoubleVectorIndividual)(ind[i]);
+            System.err.println(coind.genome.length);
+            System.arraycopy(coind.genome, 0, vals, pos, coind.genome.length);
+            pos += coind.genome.length;
+            }
+
+        double fit = (function(state, problemType, vals, threadnum));
+        boolean isOptimal = isOptimal(problemType, fit);
+
+        for(int i = 0 ; i < ind.length; i++)
+            {
+            CoevolutionaryDoubleVectorIndividual coind = (CoevolutionaryDoubleVectorIndividual)(ind[i]);
+            if (updateFitness[i])
+                {
+                if ( fit > coind.fitness.fitness() )
+                    {
+                    ((SimpleFitness)(coind.fitness)).setFitness( state, (float) fit, isOptimal );
+                    coind.context = new CoevolutionaryDoubleVectorIndividual[ind.length];
+                    for(int j = 0; j < ind.length; j++)
+                        {
+                        if (i != j)
+                            coind.context[j] = (CoevolutionaryDoubleVectorIndividual)(ind[j]);
+                        }
+                    }
+                }
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryRosenbrock.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryRosenbrock.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/CoevolutionaryRosenbrock.java	(revision 6152)
@@ -0,0 +1,77 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.coevolve2;
+
+import ec.*;
+import ec.coevolve.*;
+import ec.vector.DoubleVectorIndividual;
+import ec.simple.SimpleFitness;
+
+public class CoevolutionaryRosenbrock extends Problem implements GroupedProblemForm
+    {
+    double rosenbrock( double i, double j )
+        {
+        return - ( 100.0d*(i-j*j)*(i-j*j) + (1.0d-j)*(1.0d-j) );
+        }
+
+    public void preprocessPopulation(final EvolutionState state, Population pop, boolean countVictoriesOnly)
+        {
+        for( int i = 0 ; i < pop.subpops.length ; i++ )
+            for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
+                ((SimpleFitness)(pop.subpops[i].individuals[j].fitness)).setFitness( state, Integer.MIN_VALUE, false );
+        }
+
+    public void postprocessPopulation(final EvolutionState state, Population pop, boolean countVictoriesOnly)
+        {
+        for( int i = 0 ; i < pop.subpops.length ; i++ )
+            for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
+                pop.subpops[i].individuals[j].evaluated = true;
+        }
+
+    public void evaluate(final EvolutionState state,
+        final Individual[] ind,  // the individuals to evaluate together
+        final boolean[] updateFitness,  // should this individuals' fitness be updated?
+        final boolean countVictoriesOnly, // can be neglected in cooperative coevolution
+        int[] subpops,
+        final int threadnum)
+        {
+        if( ind.length != 2 ||
+            ( ! ( ind[0] instanceof CoevolutionaryDoubleVectorIndividual ) ) ||
+            ( ! ( ind[1] instanceof CoevolutionaryDoubleVectorIndividual ) ) )
+            {
+            state.output.error( "There should be two subpopulations, both with CoevolutionaryDoubleVectorIndividual." );
+            }
+
+        CoevolutionaryDoubleVectorIndividual ind1 = (CoevolutionaryDoubleVectorIndividual)(ind[0]);
+        CoevolutionaryDoubleVectorIndividual ind2 = (CoevolutionaryDoubleVectorIndividual)(ind[1]);
+
+        double i = ind1.genome[0];
+        double j = ind2.genome[0];
+        double functionValue = rosenbrock( i, j );
+
+        if( updateFitness[0] )
+            {
+            if( functionValue > ind1.fitness.fitness() )
+                {
+                ((SimpleFitness)(ind1.fitness)).setFitness( state, (float)functionValue, false );
+                ind1.context = new CoevolutionaryDoubleVectorIndividual[2];
+                ind1.context[1] = ind2;
+                }
+            }
+        if( updateFitness[1] )
+            {
+            if( functionValue > ind2.fitness.fitness() )
+                {
+                ((SimpleFitness)(ind2.fitness)).setFitness( state, (float)functionValue, false );
+                ind2.context = new CoevolutionaryDoubleVectorIndividual[2];
+                ind2.context[0] = ind1;
+                }
+            }
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/coevolve2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/coevolve2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/coevolve2.params	(revision 6152)
@@ -0,0 +1,63 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =                              ../../simple/simple.params
+
+generations =				100
+#print-used-params =			true
+quit-on-run-complete =			false
+
+eval =                                  ec.coevolve.MultiPopCoevolutionaryEvaluator
+
+eval.num-current=			4
+eval.num-elites =			1
+eval.num-prev =				2
+eval.select-current =			ec.select.RandomSelection
+eval.select-prev = 			ec.select.RandomSelection
+
+eval.problem =                          ec.app.coevolve2.CoevolutionaryRosenbrock
+
+pop.subpops =                           2
+pop.subpop.0 = 				ec.Subpopulation
+pop.subpop.0.duplicate-retries = 	10
+pop.subpop.0.size = 			16
+pop.subpop.0.species = 			ec.vector.FloatVectorSpecies
+pop.subpop.0.species.crossover-type = 	one
+pop.subpop.0.species.genome-size = 	5
+pop.subpop.0.species.fitness = 		ec.simple.SimpleFitness
+pop.subpop.0.species.ind = 		ec.app.coevolve2.CoevolutionaryDoubleVectorIndividual
+pop.subpop.0.species.min-gene = 	-5.12
+pop.subpop.0.species.max-gene = 	5.12
+pop.subpop.0.species.pipe =             ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.mutation-type =    gauss
+pop.subpop.0.species.mutation-stdev =   0.25
+pop.subpop.0.species.mutation-prob =    0.95
+pop.subpop.0.species.pipe.source.0 = 		ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.size = 	2
+
+pop.subpop.1 = 				ec.Subpopulation
+pop.subpop.1.duplicate-retries = 	10
+pop.subpop.1.size = 			16
+pop.subpop.1.species = 			ec.vector.FloatVectorSpecies
+pop.subpop.1.species.crossover-type = 	one
+pop.subpop.1.species.genome-size = 	5
+pop.subpop.1.species.fitness = 		ec.simple.SimpleFitness
+pop.subpop.1.species.ind = 		ec.app.coevolve2.CoevolutionaryDoubleVectorIndividual
+pop.subpop.1.species.min-gene = 	-5.12
+pop.subpop.1.species.max-gene = 	5.12
+pop.subpop.1.species.pipe =             ec.vector.breed.VectorMutationPipeline
+pop.subpop.1.species.mutation-type =    gauss
+pop.subpop.1.species.mutation-stdev =   0.25
+pop.subpop.1.species.mutation-prob =    0.95
+pop.subpop.1.species.pipe.source.0 = 		ec.select.TournamentSelection
+pop.subpop.1.species.pipe.source.0.size = 	2
+
+stat =                                  ec.simple.SimpleStatistics
+stat.file =				$out.stat
+stat.num-children = 			1
+stat.child.0 = 				ec.simple.SimpleShortStatistics
+stat.child.0.file =			$out2.stat
+
+breed.elite.0 =				1
+breed.elite.1 =				1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/ecsuite.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/ecsuite.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/coevolve2/ecsuite.params	(revision 6152)
@@ -0,0 +1,61 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../ecsuite/ecsuite.params
+
+eval.problem = ec.app.coevolve2.CoevolutionaryECSuite
+eval.problem.type = rosenbrock
+#rastrigin
+
+#
+# optionally your type could be: rosenbrock, sphere, step, noisy-quartic, 
+# or kdj-f1, kdj-f2, kdj-f3, or kdj-f4		(the kdj-foo names
+# are just aliases for other problems, useful for people who might
+# know them as specific problems in the DeJong test suite)
+# ...or booth, griewangk
+#
+
+eval =                                  ec.coevolve.MultiPopCoevolutionaryEvaluator
+
+eval.num-current=                       4
+eval.num-elites =                       1
+eval.num-prev =                         2
+eval.select-current =                   ec.select.RandomSelection
+eval.select-prev =                      ec.select.RandomSelection
+
+pop.subpops =                           2
+pop.subpop.0 =                          ec.Subpopulation
+pop.subpop.0.duplicate-retries =        10
+pop.subpop.0.size =                     16
+pop.subpop.0.species =                  ec.vector.FloatVectorSpecies
+pop.subpop.0.species.crossover-type =   one
+pop.subpop.0.species.genome-size =      5
+pop.subpop.0.species.fitness =          ec.simple.SimpleFitness
+pop.subpop.0.species.ind =              ec.app.coevolve2.CoevolutionaryDoubleVectorIndividual
+pop.subpop.0.species.min-gene =         -5.12
+pop.subpop.0.species.max-gene =         5.12
+pop.subpop.0.species.pipe =             ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.mutation-type =    gauss
+pop.subpop.0.species.mutation-stdev =   0.25
+pop.subpop.0.species.mutation-prob =    0.95
+pop.subpop.0.species.pipe.source.0 =            ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.size =       2
+
+pop.subpop.1 =                          ec.Subpopulation
+pop.subpop.1.duplicate-retries =        10
+pop.subpop.1.size =                     16
+pop.subpop.1.species =                  ec.vector.FloatVectorSpecies
+pop.subpop.1.species.crossover-type =   one
+pop.subpop.1.species.genome-size =      5
+pop.subpop.1.species.fitness =          ec.simple.SimpleFitness
+pop.subpop.1.species.ind =              ec.app.coevolve2.CoevolutionaryDoubleVectorIndividual
+pop.subpop.1.species.min-gene =         -5.12
+pop.subpop.1.species.max-gene =         5.12
+pop.subpop.1.species.pipe =             ec.vector.breed.VectorMutationPipeline
+pop.subpop.1.species.mutation-type =    gauss
+pop.subpop.1.species.mutation-stdev =   0.25
+pop.subpop.1.species.mutation-prob =    0.95
+pop.subpop.1.species.pipe.source.0 =            ec.select.TournamentSelection
+pop.subpop.1.species.pipe.source.0.size =       2
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/ECSuite.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/ECSuite.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/ECSuite.java	(revision 6152)
@@ -0,0 +1,226 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+ 
+package ec.app.ecsuite;
+
+import ec.util.*;
+import ec.*;
+import ec.simple.*;
+import ec.vector.*;
+
+/* 
+ * ECSuite.java
+ * 
+ * Created: Thu MAr 22 16:27:15 2001
+ * By: Liviu Panait and Sean Luke
+ */
+
+/*
+ * @author Liviu Panait and Sean Luke
+ * @version 1.0 
+ */
+
+/**
+   Several standard Evolutionary Computation functions are implemented: Rastrigin, De Jong's test suite
+   F1-F4 problems (Sphere, Rosenbrock, Step, Noisy-Quartic), Booth (from [Schwefel, 1995]), and Griewangk.
+   As the SimpleFitness is used for maximization problems, the mapping f(x) --> -f(x) is used to transform
+   the problems into maximization ones.
+
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>type</tt><br>
+   <font size=-1>String, one of: rosenbrock rastrigin sphere step noisy-quartic kdj-f1 kdj-f2 kdj-f3 kdj-f4 booth median [or] griewangk</font>/td>
+   <td valign=top>(The vector problem to test against.  Some of the types are synonyms: kdj-f1 = sphere, kdj-f2 = rosenbrock, kdj-f3 = step, kdj-f4 = noisy-quartic.  "kdj" stands for "Ken DeJong", and the numbers are the problems in his test suite)</td></tr>
+   </table>
+
+
+*/
+ 
+public class ECSuite extends Problem implements SimpleProblemForm
+    {
+    public static final String P_WHICH_PROBLEM = "type";
+        
+    public static final String V_ROSENBROCK = "rosenbrock";
+    public static final String V_RASTRIGIN = "rastrigin";
+    public static final String V_SPHERE = "sphere";
+    public static final String V_STEP = "step";
+    public static final String V_NOISY_QUARTIC = "noisy-quartic";
+    public static final String V_F1 = "kdj-f1";
+    public static final String V_F2 = "kdj-f2";
+    public static final String V_F3 = "kdj-f3";
+    public static final String V_F4 = "kdj-f4";
+    public static final String V_BOOTH = "booth";
+    public static final String V_GRIEWANGK = "griewangk";
+    public static final String V_MEDIAN = "median";
+
+    public static final int PROB_ROSENBROCK = 0;
+    public static final int PROB_RASTRIGIN = 1;
+    public static final int PROB_SPHERE = 2;
+    public static final int PROB_STEP = 3;
+    public static final int PROB_NOISY_QUARTIC = 4;
+    public static final int PROB_BOOTH = 5;
+    public static final int PROB_GRIEWANGK = 6;
+    public static final int PROB_MEDIAN = 7;
+    
+    public int problemType = PROB_ROSENBROCK;  // defaults on Rosenbrock
+
+    // for RASTRIGIN function
+    public final static float A = 10.0f;
+
+    // nothing....
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+        String wp = state.parameters.getStringWithDefault( base.push( P_WHICH_PROBLEM ), null, "" );
+        if( wp.compareTo( V_ROSENBROCK ) == 0 || wp.compareTo (V_F2)==0 )
+            problemType = PROB_ROSENBROCK;
+        else if ( wp.compareTo( V_RASTRIGIN ) == 0 )
+            problemType = PROB_RASTRIGIN;
+        else if ( wp.compareTo( V_SPHERE ) == 0 || wp.compareTo (V_F1)==0) 
+            problemType = PROB_SPHERE;
+        else if ( wp.compareTo( V_STEP ) == 0 || wp.compareTo (V_F3)==0)
+            problemType = PROB_STEP;
+        else if ( wp.compareTo( V_NOISY_QUARTIC ) == 0 || wp.compareTo (V_F4)==0)
+            problemType = PROB_NOISY_QUARTIC;
+        else if( wp.compareTo( V_BOOTH ) == 0 )
+            problemType = PROB_BOOTH;
+        else if( wp.compareTo( V_GRIEWANGK ) == 0 )
+            problemType = PROB_GRIEWANGK;           
+        else if( wp.compareTo( V_MEDIAN ) == 0 )
+            problemType = PROB_MEDIAN;           
+        else state.output.fatal(
+            "Invalid value for parameter, or parameter not found.\n" +
+            "Acceptable values are:\n" +
+            "  " + V_ROSENBROCK + "(or " + V_F2 + ")\n" +
+            "  " + V_RASTRIGIN + "\n" +
+            "  " + V_SPHERE + "(or " + V_F1 + ")\n" +
+            "  " + V_STEP + "(or " + V_F3 + ")\n" +
+            "  " + V_NOISY_QUARTIC + "(or " + V_F4 + ")\n"+
+            "  " + V_BOOTH + "\n" +
+            "  " + V_GRIEWANGK + "\n" + 
+            "  " + V_MEDIAN + "\n",
+            base.push( P_WHICH_PROBLEM ) );
+        }
+
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if( !( ind instanceof DoubleVectorIndividual ) )
+            state.output.fatal( "The individuals for this problem should be DoubleVectorIndividuals." );
+
+        DoubleVectorIndividual temp = (DoubleVectorIndividual)ind;
+        double[] genome = temp.genome;
+        int len = genome.length;
+
+        // this curious break-out makes it easy to use the isOptimal() and function() methods
+        // for other purposes, such as coevolutionary versions of this class.
+                
+        // compute the fitness on a per-function basis
+        double fit = (function(state, problemType, temp.genome, threadnum));
+                
+        // compute if we're optimal on a per-function basis
+        boolean isOptimal = isOptimal(problemType, fit);
+                
+        // set the fitness appropriately
+        ((SimpleFitness)(ind.fitness)).setFitness( state, (float)fit, isOptimal );
+        ind.evaluated = true;
+        }
+        
+        
+    public boolean isOptimal(int function, double fitness)
+        {
+        switch(problemType)
+            {
+            case PROB_ROSENBROCK:
+            case PROB_RASTRIGIN:
+            case PROB_SPHERE:
+            case PROB_STEP:
+                return fitness == 0.0f;
+
+            case PROB_NOISY_QUARTIC:
+            case PROB_BOOTH:
+            case PROB_GRIEWANGK:
+            case PROB_MEDIAN:
+            default:
+                return false;
+            }
+        }
+
+    public double function(EvolutionState state, int function, double[] genome, int threadnum)
+        {
+        double value = 0;
+        int len = genome.length;
+        switch(function)
+            {
+            case PROB_ROSENBROCK:
+                for( int i = 1 ; i < len ; i++ )
+                    value += 100*(genome[i-1]*genome[i-1]-genome[i])*
+                        (genome[i-1]*genome[i-1]-genome[i]) +
+                        (1-genome[i-1])*(1-genome[i-1]);
+                return -value;
+
+                
+            case PROB_RASTRIGIN:
+                value = len * A;
+                for( int i = 0 ; i < len ; i++ )
+                    value += ( genome[i]*genome[i] - A * Math.cos( 2 * Math.PI * genome[i] ) );
+                return -value;
+
+                
+            case PROB_SPHERE:
+                for( int i = 0 ; i < len ; i++ )
+                    value += genome[i]*genome[i];
+                return -value;
+
+
+            case PROB_STEP:
+                for( int i = 0 ; i < len ; i++ )
+                    value += 6 + Math.floor( genome[i] );
+                return -value;
+
+
+            case PROB_NOISY_QUARTIC:
+                for( int i = 0 ; i < len ; i++ )
+                    value += (i+1)*(genome[i]*genome[i]*genome[i]*genome[i]) + // no longer : Math.pow( genome[i], 4 ) +
+                        state.random[threadnum].nextDouble();
+                return -value;
+
+
+            case PROB_BOOTH:
+                if( len != 2 )
+                    state.output.fatal( "The Booth problem is defined for only two terms, and as a consequence the genome of the DoubleVectorIndividual should have size 2." );
+                value = (genome[0] + 2*genome[1] - 7) * (genome[0] + 2*genome[1] - 7) +
+                    (2*genome[0] + genome[1] - 5) * (2*genome[0] + genome[1] - 5);
+                return -value;
+
+
+            case PROB_GRIEWANGK:
+                value = 1;
+                double prod = 1;
+                for( int i = 0 ; i < len ; i++ )
+                    {
+                    value += (genome[i]*genome[i])/4000.0;
+                    prod *= Math.cos( genome[i] / Math.sqrt(i+1) );
+                    }
+                value -= prod;
+                return -value;
+
+
+            case PROB_MEDIAN:           // FIXME, need to do a better median-finding algorithm, such as http://www.ics.uci.edu/~eppstein/161/960130.html
+                double[] sorted = new double[genome.length];
+                System.arraycopy(genome, 0, sorted, 0, sorted.length);
+                ec.util.QuickSort.qsort(sorted);
+                return sorted[sorted.length / 2];               // note positive
+
+            default:
+                state.output.fatal( "ec.app.ecsuite.ECSuite has an invalid problem -- how on earth did that happen?" );
+                return 0;  // never happens
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/de.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/de.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/de.params	(revision 6152)
@@ -0,0 +1,10 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =				../../de/de.params
+parent.1 =				ecsuite.params
+
+# See ../../de/de.params for various options.
+
+generations = 1000
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/ecsuite.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/ecsuite.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/ecsuite.params	(revision 6152)
@@ -0,0 +1,54 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../ec.params
+
+eval.problem = ec.app.ecsuite.ECSuite
+eval.problem.type = rastrigin
+#
+# optionally your type could be: rosenbrock, sphere, step, noisy-quartic, 
+# or kdj-f1, kdj-f2, kdj-f3, or kdj-f4		(the kdj-foo names
+# are just aliases for other problems, useful for people who might
+# know them as specific problems in the DeJong test suite)
+# ...or booth, griewangk
+#
+
+
+state = 				ec.simple.SimpleEvolutionState
+init = 					ec.simple.SimpleInitializer
+finish = 	        		ec.simple.SimpleFinisher
+exch = 					ec.simple.SimpleExchanger
+breed =					ec.simple.SimpleBreeder
+eval =					ec.simple.SimpleEvaluator
+stat =					ec.simple.SimpleStatistics
+generations =				1000
+quit-on-run-complete =			true
+pop = 					ec.Population
+pop.subpops =				1
+pop.subpop.0 = 				ec.Subpopulation
+pop.subpop.0.duplicate-retries =	2
+pop.subpop.0.species =                  ec.vector.FloatVectorSpecies
+pop.subpop.0.species.pipe = 		ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0 = 	ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same
+
+pop.subpop.0.species.fitness =		ec.simple.SimpleFitness
+pop.subpop.0.species.ind =		ec.vector.DoubleVectorIndividual
+pop.subpop.0.species.mutation-bounded =	true
+
+# you can change these to whatever tickles your fancy
+pop.subpop.0.species.min-gene =	-5.12
+pop.subpop.0.species.max-gene =	5.12
+pop.subpop.0.species.genome-size = 	100
+
+
+select.tournament.size = 		2
+pop.subpop.0.species.mutation-prob = 1.0
+pop.subpop.0.species.crossover-type = one
+pop.subpop.0.species.mutation-type = gauss
+pop.subpop.0.species.mutation-stdev = 0.01
+
+pop.subpop.0.size =			1000
+stat.file				$out.stat
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/es.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/es.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/es.params	(revision 6152)
@@ -0,0 +1,14 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../es/es.params
+parent.1 = ecsuite.params
+
+# es.params defines MuCommaLambdaBreeder at (1, 10).  We also need
+# to state that the pipeline will be just mutation plus ESSelection,
+# which we do below.
+
+pop.subpop.0.species.pipe.source.0 = ec.es.ESSelection
+
+generations = 1000
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/steady.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/steady.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/ecsuite/steady.params	(revision 6152)
@@ -0,0 +1,10 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../steadystate/steadystate.params
+parent.1 = ecsuite.params
+
+# We're doing this in terms of evaluations, but we could have done it by generations of course
+evaluations = 1000000
+# generations = 1000
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/1.params	(revision 6152)
@@ -0,0 +1,71 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+gp.fs.0.size = 10
+gp.fs.0.func.0 = ec.app.edge.func.Double
+gp.fs.0.func.0.nc = nc2
+gp.fs.0.func.1 = ec.app.edge.func.Bud
+gp.fs.0.func.1.nc = nc2
+gp.fs.0.func.2 = ec.app.edge.func.Split
+gp.fs.0.func.2.nc = nc2
+gp.fs.0.func.3 = ec.app.edge.func.Loop
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.edge.func.Reverse
+gp.fs.0.func.4.nc = nc1
+gp.fs.0.func.5 = ec.app.edge.func.Accept
+gp.fs.0.func.5.nc = nc1
+gp.fs.0.func.6 = ec.app.edge.func.Start
+gp.fs.0.func.6.nc = nc1
+gp.fs.0.func.7 = ec.app.edge.func.Zero
+gp.fs.0.func.7.nc = nc0
+gp.fs.0.func.8 = ec.app.edge.func.One
+gp.fs.0.func.8.nc = nc0
+gp.fs.0.func.9 = ec.app.edge.func.Epsilon
+gp.fs.0.func.9.nc = nc0
+
+#
+# Uncomment this to use the additional operations
+#
+
+gp.fs.0.size = 14
+gp.fs.0.func.10 = ec.app.edge.func.BBud
+gp.fs.0.func.10.nc = nc2
+gp.fs.0.func.11= ec.app.edge.func.BLoop
+gp.fs.0.func.11.nc = nc2
+gp.fs.0.func.12 = ec.app.edge.func.BStart
+gp.fs.0.func.12.nc = nc1
+gp.fs.0.func.13 = ec.app.edge.func.BAccept
+gp.fs.0.func.13.nc = nc1
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.edge.Edge
+eval.problem.data = ec.app.edge.EdgeData
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/1.out.gz
+eval.problem.allneg = input/1a.out.gz
+eval.problem.testpos = input/1s.out.gz
+eval.problem.testneg = input/1sa.out.gz
+
+#
+# Uncomment this to test generalization (much slower)
+#
+
+eval.problem.generalize = true
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/2.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 1.params
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/2.out.gz
+eval.problem.allneg = input/2a.out.gz
+eval.problem.testpos = input/2s.out.gz
+eval.problem.testneg = input/2sa.out.gz
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/3.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 1.params
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/3.out.gz
+eval.problem.allneg = input/3a.out.gz
+eval.problem.testpos = input/3s.out.gz
+eval.problem.testneg = input/3sa.out.gz
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/4.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/4.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/4.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 1.params
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/4.out.gz
+eval.problem.allneg = input/4a.out.gz
+eval.problem.testpos = input/4s.out.gz
+eval.problem.testneg = input/4sa.out.gz
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/5.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/5.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/5.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 1.params
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/5.out.gz
+eval.problem.allneg = input/5a.out.gz
+eval.problem.testpos = input/5s.out.gz
+eval.problem.testneg = input/5sa.out.gz
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/6.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/6.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/6.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 1.params
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/6.out.gz
+eval.problem.allneg = input/6a.out.gz
+eval.problem.testpos = input/6s.out.gz
+eval.problem.testneg = input/6sa.out.gz
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/7.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/7.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/7.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 1.params
+
+#
+# Here we specify the particular files to do induction over
+#
+
+eval.problem.allpos = input/7.out.gz
+eval.problem.allneg = input/7a.out.gz
+eval.problem.testpos = input/7s.out.gz
+eval.problem.testneg = input/7sa.out.gz
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/Edge.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/Edge.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/Edge.java	(revision 6152)
@@ -0,0 +1,676 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge;
+import ec.util.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * Edge.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Edge implements the Symbolic Edge problem.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.edge.EdgeData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Edge problem)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Edge extends GPProblem implements SimpleProblemForm
+    {
+    public static final String P_GENERALIZE = "generalize";
+    public static final String P_ALLPOS = "allpos";
+    public static final String P_ALLNEG = "allneg";
+    public static final String P_TESTPOS = "testpos";
+    public static final String P_TESTNEG = "testneg";
+    public static final String P_MAXTEST = "maxtest";
+
+    public static final int MIN_ARRAY_SIZE = 64;
+
+    // reading states (BAD is initial state)
+    public static final int BAD = 0;
+    public static final int READING0 = 1;
+    public static final int READING1 = 2;
+    public static final int EPSILON = 3;
+
+    // we'll need to deep clone this one though.
+    public EdgeData input;
+
+    // building graph
+    public boolean[] start;
+    public boolean[] accept;
+    public int numNodes;
+    public int[] from;
+    public int[] to;
+    public int[] reading;
+    public int numEdges;
+
+    // adjacency lists
+    public int[][] reading1;
+    public int[] reading1_l;
+    public int[][] reading0;
+    public int[] reading0_l;
+    public int[][] epsilon;
+    public int[] epsilon_l;
+
+    // positive test
+    public boolean[][] posT;
+    // negative test
+    public boolean[][] negT;
+    // positive all
+    public boolean[][] posA;
+    // negative all
+    public boolean[][] negA;
+
+    // testing
+    public boolean[] state1;
+    public boolean[] state2;
+
+    // generalize?
+    public boolean generalize;
+
+    public Object clone()
+        {
+        // we don't need to copy any of our arrays, they're null until
+        // we actually start using them.
+
+        Edge myobj = (Edge) (super.clone());
+
+        // we also don't need to clone the positive/negative
+        // examples, since they don't change through the course
+        // of our run (I hope!)  Otherwise we'd need to clone them
+        // here.
+
+        // clone our data object
+        myobj.input = (EdgeData)(input.clone());
+        return myobj;
+        }
+
+    public static String fill(int num, char c)
+        {
+        char[] buf = new char[num];
+        for(int x=0;x<num;x++) buf[x]=c;
+        return new String(buf);
+        }
+
+    public static final int J_LEFT = 0;
+    public static final int J_RIGHT = 1;
+    public static final int J_CENTER = 2;
+    public static String justify(final String s, final int len, final int justification)
+        {
+        int size = len - s.length();
+        if (size<0) size=0;
+        switch(justification)
+            {
+            case J_LEFT:
+                return s + fill(size,' ');
+            case J_RIGHT:
+                return fill(size,' ') + s;
+            default: // (J_CENTER)
+                return fill(size/2,' ') + s + fill(size-(size/2),' ');
+            }
+        }
+
+    public String printCurrentNFA()
+        {
+        int strsize = String.valueOf(numNodes).length();
+        String str = "";
+        for(int x=0;x<numNodes;x++)
+            {
+            str += justify(String.valueOf(x),strsize,J_RIGHT) + " " + 
+                (start[x] ? "S" : " ") + (accept[x] ? "A" : " ") + 
+                " -> ";
+
+            if (reading0_l[x]>0)
+                { 
+                str += "(0:";
+                for(int y=0;y<reading0_l[x];y++)
+                    str += ((y>0 ? "," : "") + String.valueOf(reading0[x][y]));
+                str += ") ";
+                }
+
+            if (reading1_l[x]>0)
+                { 
+                str += "(1:";
+                for(int y=0;y<reading1_l[x];y++)
+                    str += ((y>0 ? "," : "") + String.valueOf(reading1[x][y]));
+                str += ") ";
+                }
+
+            if (epsilon_l[x]>0)
+                { 
+                str += "(e:";
+                for(int y=0;y<epsilon_l[x];y++)
+                    str += ((y>0 ? "," : "") + String.valueOf(epsilon[x][y]));
+                str += ")";
+                }
+            str += "\n";
+            }
+        return str;
+        }
+
+    public boolean[][] restrictToSize(int size, boolean[][]cases, EvolutionState state, int thread)
+        {
+        int csize = cases.length;
+        if (csize < size) return cases;
+
+        Hashtable hash = new Hashtable();
+        for(int x=0;x<size;x++)
+            {
+            while(true)
+                {
+                boolean[] b = cases[state.random[thread].nextInt(csize)];
+                if (!hash.contains(b)) { hash.put(b,b); break; }
+                }
+            }
+        
+        boolean[][] newcases = new boolean[size][];
+        Enumeration e = hash.keys();
+        for(int x=0;x<size;x++)
+            {
+            newcases[x] = (boolean[])(e.nextElement());
+            }
+
+        // sort the cases -- amazing, but hashtable doesn't always
+        // return the same ordering, I guess that's because it does
+        // pointer hashing.  Just want to guarantee replicability!
+
+        // is this correct?
+        java.util.Arrays.sort(newcases,
+            new java.util.Comparator()
+                {
+                public int compare(Object a, Object b)
+                    {
+                    boolean[] aa = (boolean[])a;
+                    boolean[] bb = (boolean[])b;
+                                        
+                    for(int x=0;x<Math.min(aa.length,bb.length);x++)
+                        if (!aa[x] && bb[x]) return -1;
+                        else if (aa[x] && !bb[x]) return 1;
+                    if (aa.length<bb.length) return -1;
+                    if (aa.length>bb.length) return 1;
+                    return 0;
+                    }
+                });
+        return newcases;
+        }
+
+
+
+    public boolean[][] slurp(final File f)
+        throws IOException
+        {
+        LineNumberReader r = new LineNumberReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(f))));
+        String bits;
+
+        Vector v = new Vector();
+        while((bits=r.readLine())!=null)
+            {
+            bits = bits.trim();
+            int len = bits.length();
+            if (len==0) continue; // empty line
+            if (bits.charAt(0)=='#') continue;  // comment
+            if (bits.equalsIgnoreCase("e"))
+                v.addElement(new boolean[0]);
+            else
+                {
+                boolean[] b = new boolean[len];
+                for(int x=0;x<len;x++)
+                    b[x] = (bits.charAt(x)=='1');
+                v.addElement(b);
+                }
+            }
+        r.close();
+        boolean[][] result = new boolean[v.size()][];
+        v.copyInto(result);
+        return result;
+        }
+
+
+    public void printBits(final EvolutionState state, final boolean[][] bits)
+        {
+        StringBuffer s;
+        for(int x=0;x<bits.length;x++)
+            {
+            s = new StringBuffer();
+            for(int y=0;y<bits[x].length;y++)
+                if (bits[x][y]) s.append('1');
+                else s.append('0');
+            if (s.length()==0) state.output.message("(empty)");
+            else state.output.message(s.toString());
+            }
+        }
+
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // do we generalize?
+        generalize = state.parameters.getBoolean(base.push(P_GENERALIZE),null,false);
+
+        // load the test examples here
+
+        File ap = null;
+        File an = null;
+        File tp = null;
+        File tn = null;
+        int restriction;
+
+        if (generalize)
+            {
+            ap = state.parameters.getFile(base.push(P_ALLPOS),null);
+            an = state.parameters.getFile(base.push(P_ALLNEG),null);
+            }
+
+        tp = state.parameters.getFile(base.push(P_TESTPOS),null);
+        tn = state.parameters.getFile(base.push(P_TESTNEG),null);
+
+        if (generalize)
+            {
+            if (ap==null) state.output.error("File doesn't exist", base.push(P_ALLPOS));
+            if (an==null) state.output.error("File doesn't exist", base.push(P_ALLNEG));
+            }
+
+        if (tp==null) state.output.error("File doesn't exist", base.push(P_TESTPOS));
+        if (tn==null) state.output.error("File doesn't exist", base.push(P_TESTNEG));
+        state.output.exitIfErrors();
+
+        if (generalize)
+            {
+            if (!ap.canRead()) state.output.error("File cannot be read", base.push(P_ALLPOS));
+            if (!an.canRead()) state.output.error("File cannot be read", base.push(P_ALLNEG));
+            }
+
+        if (!tp.canRead()) state.output.error("File cannot be read", base.push(P_TESTPOS));
+        if (!tn.canRead()) state.output.error("File cannot be read", base.push(P_TESTNEG));
+        state.output.exitIfErrors();
+
+        if (generalize)
+            {
+            state.output.message("Reading Positive Examples");
+            try { posA = slurp(ap); }
+            catch(IOException e) { state.output.error(
+                    "IOException reading file (here it is)\n" + e, base.push(P_ALLPOS)); }
+            state.output.message("Reading Negative Examples");
+            try { negA = slurp(an); }
+            catch(IOException e) { state.output.error(
+                    "IOException reading file (here it is)\n" + e, base.push(P_ALLNEG)); }
+            }
+
+        state.output.message("Reading Positive Training Examples");
+        try { posT = slurp(tp); }
+        catch(IOException e) { state.output.error(
+                "IOException reading file (here it is)\n" + e, base.push(P_TESTPOS)); }
+        if ((restriction = state.parameters.getInt(
+                    base.push(P_MAXTEST),null,1))>0)
+            {
+            // Need to restrict
+            state.output.message("Restricting to <= " + restriction + " Unique Examples");
+            posT = restrictToSize(restriction,posT,state,0);
+            }
+
+        state.output.message("");
+        printBits(state,posT);
+        state.output.message("");
+
+        state.output.message("Reading Negative Training Examples");
+        try { negT = slurp(tn); }
+        catch(IOException e) { state.output.error(
+                "IOException reading file (here it is)\n" + e, base.push(P_TESTNEG)); }
+        if ((restriction = state.parameters.getInt(
+                    base.push(P_MAXTEST),null,1))>0)
+            {
+            // Need to restrict
+            state.output.message("Restricting to <= " + restriction + " Unique Examples");
+            negT = restrictToSize(restriction,negT,state,0);
+            }
+
+        state.output.message("");
+        printBits(state,negT);
+        state.output.message("");
+
+        state.output.exitIfErrors();
+            
+
+        // set up our input -- don't want to use the default base, it's unsafe
+        input = (EdgeData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA), null, EdgeData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+
+    public boolean test(final boolean[] sample)
+        {
+        final boolean STATE_1 = false;
+//        final boolean STATE_2 = true;
+        boolean st = STATE_1;
+        
+        // set initial state
+        for(int x=0;x<numNodes;x++)
+            state1[x]=start[x];
+
+        // run
+        for(int x=0;x<sample.length;x++)
+            {
+            if (st==STATE_1)
+                {
+                for(int y=0;y<numNodes;y++)
+                    state2[y]=false;
+                for(int y=0;y<numNodes;y++)  // yes, *start*.length
+                    if (state1[y])  // i'm in this state
+                        {
+                        // advance edges
+                        if (sample[x]) // reading a 1
+                            for(int z=0;z<reading1_l[y];z++)
+                                state2[reading1[y][z]] = true;
+                        else  // reading a 0
+                            for(int z=0;z<reading0_l[y];z++)
+                                state2[reading0[y][z]] = true;
+                        }
+
+                
+                // advance along epsilon boundary
+                boolean moreEpsilons = true;
+                while(moreEpsilons)
+                    {
+                    moreEpsilons = false;
+                    for(int y=0;y<numNodes;y++)
+                        if (state2[y])
+                            for(int z=0;z<epsilon_l[y];z++)
+                                {
+                                if (!state2[epsilon[y][z]]) moreEpsilons = true;
+                                state2[epsilon[y][z]] = true;
+                                }
+                    }
+                }
+
+
+            else //if (st==STATE_2)
+                {
+                for(int y=0;y<numNodes;y++)
+                    state1[y]=false;
+                for(int y=0;y<numNodes;y++)  // yes, *start*.length
+                    if (state2[y])  // i'm in this state
+                        {
+                        // advance edges
+                        if (sample[x]) // reading a 1
+                            for(int z=0;z<reading1_l[y];z++)
+                                state1[reading1[y][z]] = true;
+                        else  // reading a 0
+                            for(int z=0;z<reading0_l[y];z++)
+                                state1[reading0[y][z]] = true;
+                        }
+
+                // advance along epsilon boundary
+                boolean moreEpsilons = true;
+                while(moreEpsilons)
+                    {
+                    moreEpsilons = false;
+                    for(int y=0;y<numNodes;y++)
+                        if (state1[y])
+                            for(int z=0;z<epsilon_l[y];z++)
+                                {
+                                if (!state1[epsilon[y][z]]) moreEpsilons = true;
+                                state1[epsilon[y][z]] = true;
+                                }
+                    }
+                }
+
+            st = !st;
+            }
+
+        // am I in an accepting state?
+        if (st==STATE_1)  // just loaded the result into state 1 from state 2
+            {
+            for(int x=0;x<numNodes;x++)
+                if (accept[x] && state1[x]) return true;
+            }
+        else // (st==STATE_2)
+            {
+            for(int x=0;x<numNodes;x++)
+                if (accept[x] && state2[x]) return true;
+            }
+        return false;
+        }
+
+    
+
+
+
+
+    int totpos;
+    int totneg;
+    
+    /** Tests an individual, returning its successful positives
+        in totpos and its successful negatives in totneg. */
+    public void fullTest(final EvolutionState state, 
+        final Individual ind, 
+        final int threadnum,
+        boolean[][] pos,
+        boolean[][] neg)
+        {
+        // reset the graph
+        numNodes = 2;
+        numEdges = 1; from[0]=0; to[0]=1;
+        start[0]=start[1]=accept[0]=accept[1]=false; 
+        ((EdgeData)input).edge = 0;
+        
+        // generate the graph
+        ((GPIndividual)ind).trees[0].child.eval(
+            state,threadnum,input,stack,((GPIndividual)ind),this);
+        
+        // produce the adjacency matrix
+        if (reading1.length < numNodes ||
+            reading1[0].length < numEdges)
+            { 
+            reading1 = new int[numNodes*2][numEdges*2];
+            reading0 = new int[numNodes*2][numEdges*2];
+            epsilon = new int[numNodes*2][numEdges*2];
+            reading1_l = new int[numNodes*2];
+            reading0_l = new int[numNodes*2];
+            epsilon_l = new int[numNodes*2];
+            }
+        
+        for(int y=0;y<numNodes;y++)
+            {
+            reading1_l[y]=0;
+            reading0_l[y]=0;
+            epsilon_l[y]=0;
+            }
+        
+        for(int y=0;y<numEdges;y++)
+            switch(reading[y])
+                {
+                case READING0:
+                    reading0[from[y]][reading0_l[from[y]]++]=to[y];
+                    break;
+                case READING1:
+                    reading1[from[y]][reading1_l[from[y]]++]=to[y];
+                    break;
+                case EPSILON:
+                    epsilon[from[y]][epsilon_l[from[y]]++]=to[y];
+                    break;
+                }
+        
+        // create the states
+        if (state1.length < numNodes)
+            { 
+            state1 = new boolean[numNodes*2];
+            state2 = new boolean[numNodes*2];
+            }
+        
+        // test the graph on our data
+        
+        totpos=0;
+        totneg=0;
+        for(int y=0;y<pos.length;y++)
+            if (test(pos[y])) totpos++;
+        for(int y=0;y<neg.length;y++)
+            if (!test(neg[y])) totneg++;
+        }
+
+
+
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (start==null)
+            {
+            start = new boolean[MIN_ARRAY_SIZE];
+            accept = new boolean[MIN_ARRAY_SIZE];
+            reading = new int[MIN_ARRAY_SIZE];
+            from = new int[MIN_ARRAY_SIZE];
+            to = new int[MIN_ARRAY_SIZE];
+            state1 = new boolean[MIN_ARRAY_SIZE];
+            state2 = new boolean[MIN_ARRAY_SIZE];
+            reading1 = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            reading0 = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            epsilon = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            reading1_l = new int[MIN_ARRAY_SIZE];
+            reading0_l = new int[MIN_ARRAY_SIZE];
+            epsilon_l = new int[MIN_ARRAY_SIZE];
+            }
+
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            fullTest(state,ind,threadnum,posT,negT);
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+
+            // this is an awful fitness metric, but it's the standard
+            // one used for these problems.  :-(
+                
+            f.setStandardizedFitness(state,(float)
+                    (1.0 - ((double)(totpos + totneg)) / 
+                    (posT.length + negT.length)));
+
+            // here are two other more reasonable fitness metrics
+            /*
+              f.setStandardizedFitness(state,(float)
+              (1.0 - Math.min(((double)totpos)/posT.length,
+              ((double)totneg)/negT.length)));
+
+              f.setStandardizedFitness(state,(float)
+              (1.0 - (((double)totpos)/posT.length +
+              ((double)totneg)/negT.length)/2.0));
+            */
+
+            f.hits = totpos + totneg;
+            ind.evaluated = true;
+            }
+        }
+
+    public void describe(
+        final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum,
+        final int log)
+        {
+        if (start==null)
+            {
+            start = new boolean[MIN_ARRAY_SIZE];
+            accept = new boolean[MIN_ARRAY_SIZE];
+            reading = new int[MIN_ARRAY_SIZE];
+            from = new int[MIN_ARRAY_SIZE];
+            to = new int[MIN_ARRAY_SIZE];
+            state1 = new boolean[MIN_ARRAY_SIZE];
+            state2 = new boolean[MIN_ARRAY_SIZE];
+            reading1 = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            reading0 = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            epsilon = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            reading1_l = new int[MIN_ARRAY_SIZE];
+            reading0_l = new int[MIN_ARRAY_SIZE];
+            epsilon_l = new int[MIN_ARRAY_SIZE];
+            }
+
+        if (generalize)
+            fullTest(state,ind,threadnum,posA,negA);
+        else
+            fullTest(state,ind,threadnum,posT,negT);
+        
+        if (generalize)
+            state.output.println("\n\nBest Individual's Generalization Score...\n" +
+                "Pos: " + totpos + "/" + posA.length + 
+                " Neg: " + totneg + "/" + negA.length + 
+                "\n(pos+neg)/(allpos+allneg):     " + 
+                (float)
+                (((double)(totpos+totneg))/(posA.length+negA.length)) +
+                "\n((pos/allpos)+(neg/allneg))/2: " + 
+                (float)
+                (((((double)totpos)/posA.length)+(((double)totneg)/negA.length))/2) +
+                "\nMin(pos/allpos,neg/allneg):    " +
+                (float)Math.min((((double)totpos)/posA.length),(((double)totneg)/negA.length)),
+                log);
+                
+        state.output.println("\nBest Individual's NFA\n=====================\n",
+            log);
+        
+        state.output.println(printCurrentNFA(),log);
+        }
+
+    public String describeShortGeneralized(final Individual ind, 
+        final EvolutionState state, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (start==null)
+            {
+            start = new boolean[MIN_ARRAY_SIZE];
+            accept = new boolean[MIN_ARRAY_SIZE];
+            reading = new int[MIN_ARRAY_SIZE];
+            from = new int[MIN_ARRAY_SIZE];
+            to = new int[MIN_ARRAY_SIZE];
+            state1 = new boolean[MIN_ARRAY_SIZE];
+            state2 = new boolean[MIN_ARRAY_SIZE];
+            reading1 = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            reading0 = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            epsilon = new int[MIN_ARRAY_SIZE][MIN_ARRAY_SIZE];
+            reading1_l = new int[MIN_ARRAY_SIZE];
+            reading0_l = new int[MIN_ARRAY_SIZE];
+            epsilon_l = new int[MIN_ARRAY_SIZE];
+            }
+
+        fullTest(state,ind,threadnum,posA,negA);
+
+        return ": " + 
+            ((double)totpos)/posA.length + " " + 
+            ((double)totneg)/negA.length + " " +
+            (((double)(totpos+totneg))/(posA.length+negA.length)) + " " +
+            (((((double)totpos)/posA.length)+(((double)totneg)/negA.length))/2) + " " +
+            Math.min((((double)totpos)/posA.length),(((double)totneg)/negA.length)) + " : " ;
+        }           
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/EdgeData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/EdgeData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/EdgeData.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge;
+import ec.gp.*;
+
+/* 
+ * EdgeData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class EdgeData extends GPData
+    {
+    // return value
+    public int edge;
+
+    public void copyTo(final GPData gpd)
+        { ((EdgeData)gpd).edge = edge; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/EdgeShortStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/EdgeShortStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/EdgeShortStatistics.java	(revision 6152)
@@ -0,0 +1,38 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge;
+import ec.*;
+import ec.gp.koza.*;
+import ec.util.*;
+
+/* 
+ * EdgeShortStatistics.java
+ * 
+ * Created: Fri Nov  5 16:03:44 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class EdgeShortStatistics extends KozaShortStatistics
+    {
+    public void _postEvaluationStatistics(final EvolutionState state)
+        {
+        // compute and print out the other statistics -- we depend on it!
+        super._postEvaluationStatistics(state);
+
+        // we have only one population, so this is kosher
+        state.output.print(((Edge)(state.evaluator.p_problem.clone())).
+            describeShortGeneralized(best_of_run[0], state, 0, 0), 
+            statisticslog);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Accept.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Accept.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Accept.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Accept.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Accept extends GPNode
+    {
+    public String toString() { return "a"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.accept[prob.to[edge]] = true;
+
+        // pass the edge down
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BAccept.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BAccept.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BAccept.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * BAccept.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class BAccept extends GPNode
+    {
+    public String toString() { return "a2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.accept[prob.from[edge]] = true;
+
+        // pass the edge down
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BBud.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BBud.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BBud.java	(revision 6152)
@@ -0,0 +1,103 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * BBud.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class BBud extends GPNode
+    {
+    public String toString() { return "bud2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        if (prob.from.length==prob.numEdges)  // we're full, need to expand
+            {
+            int[] from_ = new int[prob.numEdges*2];
+            int[] to_ = new int[prob.numEdges*2];
+            int[] reading_ = new int[prob.numEdges*2];
+            System.arraycopy(prob.from,0,from_,0,prob.from.length);
+            System.arraycopy(prob.to,0,to_,0,prob.to.length);
+            System.arraycopy(prob.reading,0,reading_,0,prob.reading.length);
+            prob.from = from_;
+            prob.to = to_;
+            prob.reading = reading_;
+            }
+
+        if (prob.start.length==prob.numNodes)  // we're full, need to expand
+            {
+            boolean[] start_ = new boolean[prob.numNodes*2];
+            boolean[] accept_ = new boolean[prob.numNodes*2];
+            System.arraycopy(prob.start,0,start_,0,prob.start.length);
+            System.arraycopy(prob.accept,0,accept_,0,prob.accept.length);
+            prob.start = start_;
+            prob.accept = accept_;
+            }
+
+        int newedge = prob.numEdges;
+        prob.numEdges++;
+        int newnode = prob.numNodes;
+        prob.numNodes++;
+
+        // set up new node
+        prob.accept[newnode] = false;
+        prob.start[newnode] = false;
+
+        // set up new edge
+        prob.from[newedge] = prob.from[edge];
+        prob.to[newedge] = newnode;
+        prob.reading[newedge] = prob.reading[edge];
+
+        // pass the original edge down the left child
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        // reset input for right child
+        ((EdgeData)(input)).edge = newedge;
+
+        // pass the new edge down the right child
+        
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BLoop.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BLoop.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BLoop.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * BLoop.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class BLoop extends GPNode
+    {
+    public String toString() { return "loop2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        if (prob.from.length==prob.numEdges)  // we're full, need to expand
+            {
+            int[] from_ = new int[prob.numEdges*2];
+            int[] to_ = new int[prob.numEdges*2];
+            int[] reading_ = new int[prob.numEdges*2];
+            System.arraycopy(prob.from,0,from_,0,prob.from.length);
+            System.arraycopy(prob.to,0,to_,0,prob.to.length);
+            System.arraycopy(prob.reading,0,reading_,0,prob.reading.length);
+            prob.from = from_;
+            prob.to = to_;
+            prob.reading = reading_;
+            }
+
+        int newedge = prob.numEdges;
+        prob.numEdges++;
+        prob.from[newedge] = prob.from[edge];
+        prob.to[newedge] = prob.from[edge];  // same
+        prob.reading[newedge] = prob.reading[edge];
+        
+        // pass the original edge down the left child
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        // reset input for right child
+        ((EdgeData)(input)).edge = newedge;
+
+        // pass the new edge down the right child
+        
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BStart.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BStart.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/BStart.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * BStart.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class BStart extends GPNode
+    {
+    public String toString() { return "s2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.start[prob.from[edge]] = true;
+
+        // pass the edge down
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Bud.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Bud.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Bud.java	(revision 6152)
@@ -0,0 +1,103 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Bud.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Bud extends GPNode
+    {
+    public String toString() { return "bud"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        if (prob.from.length==prob.numEdges)  // we're full, need to expand
+            {
+            int[] from_ = new int[prob.numEdges*2];
+            int[] to_ = new int[prob.numEdges*2];
+            int[] reading_ = new int[prob.numEdges*2];
+            System.arraycopy(prob.from,0,from_,0,prob.from.length);
+            System.arraycopy(prob.to,0,to_,0,prob.to.length);
+            System.arraycopy(prob.reading,0,reading_,0,prob.reading.length);
+            prob.from = from_;
+            prob.to = to_;
+            prob.reading = reading_;
+            }
+
+        if (prob.start.length==prob.numNodes)  // we're full, need to expand
+            {
+            boolean[] start_ = new boolean[prob.numNodes*2];
+            boolean[] accept_ = new boolean[prob.numNodes*2];
+            System.arraycopy(prob.start,0,start_,0,prob.start.length);
+            System.arraycopy(prob.accept,0,accept_,0,prob.accept.length);
+            prob.start = start_;
+            prob.accept = accept_;
+            }
+
+        int newedge = prob.numEdges;
+        prob.numEdges++;
+        int newnode = prob.numNodes;
+        prob.numNodes++;
+
+        // set up new node
+        prob.accept[newnode] = false;
+        prob.start[newnode] = false;
+
+        // set up new edge
+        prob.from[newedge] = prob.to[edge];
+        prob.to[newedge] = newnode;
+        prob.reading[newedge] = prob.reading[edge];
+
+        // pass the original edge down the left child
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        // reset input for right child
+        ((EdgeData)(input)).edge = newedge;
+
+        // pass the new edge down the right child
+        
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Double.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Double.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Double.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Double.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Double extends GPNode
+    {
+    public String toString() { return "double"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        if (prob.from.length==prob.numEdges)  // we're full, need to expand
+            {
+            int[] from_ = new int[prob.numEdges*2];
+            int[] to_ = new int[prob.numEdges*2];
+            int[] reading_ = new int[prob.numEdges*2];
+            System.arraycopy(prob.from,0,from_,0,prob.from.length);
+            System.arraycopy(prob.to,0,to_,0,prob.to.length);
+            System.arraycopy(prob.reading,0,reading_,0,prob.reading.length);
+            prob.from = from_;
+            prob.to = to_;
+            prob.reading = reading_;
+            }
+
+        int newedge = prob.numEdges;
+        prob.numEdges++;
+        prob.from[newedge] = prob.from[edge];
+        prob.to[newedge] = prob.to[edge];
+        prob.reading[newedge] = prob.reading[edge];
+        
+        // pass the original edge down the left child
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        // reset input for right child
+        ((EdgeData)(input)).edge = newedge;
+
+        // pass the new edge down the right child
+        
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Epsilon.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Epsilon.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Epsilon.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Epsilon.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Epsilon extends GPNode
+    {
+    public String toString() { return "e"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.reading[edge] = Edge.EPSILON;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Loop.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Loop.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Loop.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Loop.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Loop extends GPNode
+    {
+    public String toString() { return "loop"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        if (prob.from.length==prob.numEdges)  // we're full, need to expand
+            {
+            int[] from_ = new int[prob.numEdges*2];
+            int[] to_ = new int[prob.numEdges*2];
+            int[] reading_ = new int[prob.numEdges*2];
+            System.arraycopy(prob.from,0,from_,0,prob.from.length);
+            System.arraycopy(prob.to,0,to_,0,prob.to.length);
+            System.arraycopy(prob.reading,0,reading_,0,prob.reading.length);
+            prob.from = from_;
+            prob.to = to_;
+            prob.reading = reading_;
+            }
+
+        int newedge = prob.numEdges;
+        prob.numEdges++;
+        prob.from[newedge] = prob.to[edge];
+        prob.to[newedge] = prob.to[edge];  // same
+        prob.reading[newedge] = prob.reading[edge];
+        
+        // pass the original edge down the left child
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        // reset input for right child
+        ((EdgeData)(input)).edge = newedge;
+
+        // pass the new edge down the right child
+        
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/One.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/One.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/One.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * One.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class One extends GPNode
+    {
+    public String toString() { return "1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.reading[edge] = Edge.READING1;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Reverse.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Reverse.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Reverse.java	(revision 6152)
@@ -0,0 +1,63 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Reverse.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Reverse extends GPNode
+    {
+    public String toString() { return "reverse"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        int swap = prob.from[edge];
+        prob.from[edge] = prob.to[edge];
+        prob.to[edge] = swap;
+        
+        // pass the edge down
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Split.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Split.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Split.java	(revision 6152)
@@ -0,0 +1,105 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Split.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Split extends GPNode
+    {
+    public String toString() { return "split"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        if (prob.from.length==prob.numEdges)  // we're full, need to expand
+            {
+            int[] from_ = new int[prob.numEdges*2];
+            int[] to_ = new int[prob.numEdges*2];
+            int[] reading_ = new int[prob.numEdges*2];
+            System.arraycopy(prob.from,0,from_,0,prob.from.length);
+            System.arraycopy(prob.to,0,to_,0,prob.to.length);
+            System.arraycopy(prob.reading,0,reading_,0,prob.reading.length);
+            prob.from = from_;
+            prob.to = to_;
+            prob.reading = reading_;
+            }
+
+        if (prob.start.length==prob.numNodes)  // we're full, need to expand
+            {
+            boolean[] start_ = new boolean[prob.numNodes*2];
+            boolean[] accept_ = new boolean[prob.numNodes*2];
+            System.arraycopy(prob.start,0,start_,0,prob.start.length);
+            System.arraycopy(prob.accept,0,accept_,0,prob.accept.length);
+            prob.start = start_;
+            prob.accept = accept_;
+            }
+
+        int newedge = prob.numEdges;
+        prob.numEdges++;
+        int newnode = prob.numNodes;
+        prob.numNodes++;
+
+        // set up new node
+        prob.accept[newnode] = false;
+        prob.start[newnode] = false;
+
+        // set up new edge
+        prob.from[newedge] = newnode;
+        prob.to[newedge] = prob.to[edge];
+        prob.reading[newedge] = prob.reading[edge];
+        // modify old edge
+        prob.to[edge] = newnode;
+
+        // pass the original edge down the left child
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        // reset input for right child
+        ((EdgeData)(input)).edge = newedge;
+
+        // pass the new edge down the right child
+        
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Start.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Start.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Start.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Start.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Start extends GPNode
+    {
+    public String toString() { return "s"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.start[prob.to[edge]] = true;
+
+        // pass the edge down
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Zero.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Zero.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/edge/func/Zero.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.edge.func;
+import ec.*;
+import ec.app.edge.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Zero.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Zero extends GPNode
+    {
+    public String toString() { return "0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int edge = ((EdgeData)(input)).edge;
+        Edge prob = (Edge)problem;
+
+        prob.reading[edge] = Edge.READING0;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/gui/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/gui/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/gui/README	(revision 6152)
@@ -0,0 +1,9 @@
+These versions of the parameter files, when run in the GUI, additionally chart
+their statistics if you have JFreeChart and iText installed (for printing
+to PDF).
+
+JFreeChart:
+	http://www.jfree.org/jfreechart/
+
+iText:
+	http://www.lowagie.com/iText/
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/gui/SimpleBarChartStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/gui/SimpleBarChartStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/gui/SimpleBarChartStatistics.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 16, 2005 12:36:14 PM
+ * 
+ * By: spaus, Hovden
+ */
+package ec.app.gui;
+
+import ec.display.chart.*;
+import ec.EvolutionState;
+import ec.Fitness;
+import ec.util.Parameter;
+import ec.vector.*;
+
+/**
+ * @author spaus
+ */
+public class SimpleBarChartStatistics extends BarChartStatistics 
+    { //Hovden
+
+    private int[] seriesID;
+    
+    public void setup(EvolutionState state, Parameter base) {
+        super.setup(state, base);
+        int numSubPops = state.parameters.getInt(new Parameter("pop.subpops"),null);
+        
+        seriesID = new int[numSubPops];
+        
+        for (int i = 0; i < numSubPops; ++i) {
+            seriesID[i] = i; //series id identifies each sub pop
+            }
+        }
+    
+    public void postEvaluationStatistics(EvolutionState state) {
+        super.postEvaluationStatistics(state);
+        
+        for (int subPop = 0; subPop < state.population.subpops.length; ++subPop) {
+            Fitness bestFit = state.population.subpops[subPop].individuals[0].fitness;
+            for (int i = 1; i < state.population.subpops[subPop].individuals.length; ++i) {
+                Fitness fit = state.population.subpops[subPop].individuals[i].fitness;
+                if (fit.betterThan(bestFit))
+                    bestFit = fit;
+                
+                //Best individual is found, make a bar graph
+                makeBar(seriesID[subPop], ((DoubleVectorIndividual)state.population.subpops[subPop].individuals[i]).genome);
+                }
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/gui/SimpleXYSeriesChartStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/gui/SimpleXYSeriesChartStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/gui/SimpleXYSeriesChartStatistics.java	(revision 6152)
@@ -0,0 +1,52 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 16, 2005 12:36:14 PM
+ * 
+ * By: spaus
+ */
+package ec.app.gui;
+
+import ec.display.chart.*;
+import ec.EvolutionState;
+import ec.Fitness;
+import ec.util.Parameter;
+
+/**
+ * @author spaus
+ */
+public class SimpleXYSeriesChartStatistics
+    extends XYSeriesChartStatistics {
+
+    private int[] seriesID;
+    
+    public void setup(EvolutionState state, Parameter base) {
+        super.setup(state, base);
+        int numSubPops = state.parameters.getInt(new Parameter("pop.subpops"),null);
+        seriesID = new int[numSubPops];
+        
+        for (int i = 0; i < numSubPops; ++i) {
+            seriesID[i] = addSeries("SubPop "+i);
+            }
+        }
+    
+    public void postEvaluationStatistics(EvolutionState state) {
+        super.postEvaluationStatistics(state);
+        
+        for (int subPop = 0; subPop < state.population.subpops.length; ++subPop) {
+            Fitness bestFit = state.population.subpops[subPop].individuals[0].fitness;
+            for (int i = 1; i < state.population.subpops[subPop].individuals.length; ++i) {
+                Fitness fit = state.population.subpops[subPop].individuals[i].fitness;
+                if (fit.betterThan(bestFit))
+                    bestFit = fit;
+                }
+
+            addDataPoint(seriesID[subPop], state.generation, bestFit.fitness());
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/gui/ant.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/gui/ant.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/gui/ant.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../ant/ant.params
+
+stat.num-children = 1
+stat.child.0 = ec.app.gui.SimpleXYSeriesChartStatistics
+stat.child.0.title = Best of Generation
+stat.child.0.x-axis-label = generation
+stat.child.0.y-axis-label = fitness
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/gui/coevolve2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/gui/coevolve2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/gui/coevolve2.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../coevolve2/coevolve2.params
+
+stat.num-children = 2
+stat.child.0 = ec.app.gui.SimpleXYSeriesChartStatistics
+stat.child.0.title = Best of Generation
+stat.child.0.x-axis-label = generation
+stat.child.0.y-axis-label = value
+
+stat.child.1 = ec.app.gui.SimpleBarChartStatistics
+stat.child.1.title = Best of Generation
+stat.child.1.x-axis-label = generation
+stat.child.1.y-axis-label = value
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/hiff/HIFF.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/hiff/HIFF.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/hiff/HIFF.java	(revision 6152)
@@ -0,0 +1,109 @@
+package ec.app.hiff; 
+
+import ec.*; 
+import ec.util.*; 
+import ec.vector.*;
+import ec.simple.*;
+
+/** 
+    HIFF implements the Hierarchical If-And-Only-If problem developed by Watson, Hornby and Pollack.
+    See <a href="http://www.cs.brandeis.edu/~richardw/hiff.html">The HIFF Generator</a> for more information
+    and papers.
+
+    <p><b>Parameters</b><br>
+    <table>
+    <tr><td valign=top><i>base</i>.<tt>p</tt><br>
+    <font size=-1>int >= 0 </td>
+    <td valign=top>(number of blocks at each level)</td></tr>
+    <tr><td valign=top><i>base</i>.<tt>k</tt><br>
+    <font size=-1>int >= 0 </td>
+    <td valign=top>(number of hierarchical levels)</td></tr>
+    <tr><td valign=top><i>base</i>.<tt>rc</tt><br>
+    <font size=-1>double </td>
+    <td valign=top>(ratio of block contributions)</td></tr>
+    </table>
+
+    @author Keith Sullivan
+    @version 1.0
+*/
+
+public class HIFF extends Problem implements SimpleProblemForm 
+    {
+
+    public static final String P_K = "k";
+    public static final String P_P = "p"; 
+    public static final String P_RC = "rc"; 
+        
+    int K, P, Rc; 
+                
+    public void setup(EvolutionState state, Parameter base) 
+        {
+        super.setup(state, base); 
+                
+        K = state.parameters.getInt(base.push(P_K), null, 0); 
+        if (K < 0) 
+            state.output.fatal("k must be > 0", base.push(P_K)); 
+                
+        P = state.parameters.getInt(base.push(P_P), null, 0); 
+        if (P < 0) 
+            state.output.fatal("p must be > 0", base.push(P_P)); 
+                
+        Rc = state.parameters.getInt(base.push(P_RC), null, 0); 
+        if (Rc < 0) 
+            state.output.fatal("rc must be > 0", base.push(P_RC)); 
+        }
+        
+    public void evaluate(final EvolutionState state, final Individual ind, final int subpopulation, final int threadnum)
+        {
+        BitVectorIndividual ind2 = (BitVectorIndividual) ind; 
+                
+        double genes[] = new double[ind2.genome.length];
+        for (int i=0; i < genes.length; i++) 
+            genes[i] = ((ind2.genome[i]) ? 1 : 0); 
+        double fitness = H(genes); 
+                
+        ((SimpleFitness)(ind2.fitness)).setFitness( state, (float) fitness, false);
+        ind2.evaluated = true; 
+        }
+                
+    double H(double genes[]) 
+        {
+        double bonus=1, F=0; 
+        int last = genes.length;
+                
+        for (int i=0; i < last; i++) 
+            F += f(genes[i]) ; 
+                
+        for (int i=1; i <= P; i++) 
+            { 
+            last /= K; 
+            bonus *= Rc; 
+            for (int j=0; j < last; j++) 
+                { 
+                genes[j] = t(genes, j*K); 
+                F += f(genes[j]) * bonus; 
+                }
+            }
+                
+        return F;
+        }
+        
+    double t(double transform[], int first) 
+        {
+        int s=0; 
+        for (int i=first+1; i < first+K; i++) 
+            { 
+            if (transform[first] == transform[i]) 
+                s++; 
+            }
+        if (s == (K-1)) return transform[first]; 
+                
+        return -1; 
+        }
+        
+    double f(double b) 
+        {
+        if (b != -1) return 1; 
+        return 0;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/hiff/hiff.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/hiff/hiff.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/hiff/hiff.params	(revision 6152)
@@ -0,0 +1,31 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../simple/simple.params
+
+seed.0 = time
+
+pop.subpop.0.species.genome-size = 64 
+
+eval.problem = ec.app.hiff.HIFF
+eval.problem.p = 6 
+eval.problem.k = 2 
+eval.problem.rc = 2
+
+pop.subpop.0.size = 1000 
+generations = 1000 
+
+pop.subpop.0.species = ec.vector.VectorSpecies 
+pop.subpop.0.species.pipe = ec.vector.breed.VectorMutationPipeline 
+pop.subpop.0.species.pipe.source.0 = ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same 
+
+pop.subpop.0.species.ind = ec.vector.BitVectorIndividual
+pop.subpop.0.species.fitness = ec.simple.SimpleFitness
+
+select.tournament.size =                2 
+pop.subpop.0.species.mutation-prob = 0.0
+pop.subpop.0.species.crossover-prob = 0.3
+pop.subpop.0.species.crossover-type =two  
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/Lawnmower.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/Lawnmower.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/Lawnmower.java	(revision 6152)
@@ -0,0 +1,221 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * Lawnmower.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Lawnmower implements the Koza-II Lawnmower problem.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.lawnmower.LawnmowerData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Lawnmower problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>file</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(filename of the .trl file for the Lawnmower problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>turns</tt><br>
+ <font size=-1>int &gt;= 1</td>
+ <td valign=top>(maximal number of moves the lawnmower may make)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Lawnmower extends GPProblem implements SimpleProblemForm
+    {
+    public static final String P_X = "x";
+    public static final String P_Y = "y";
+
+    // map point descriptions
+    public static final int UNMOWED = 0;
+
+    // orientations
+    public static final int O_UP = 0;
+    public static final int O_LEFT = 1;
+    public static final int O_DOWN = 2;
+    public static final int O_RIGHT = 3;
+
+    // We'll deep clone this
+    public LawnmowerData input;
+
+    // our map
+    public int map[][];
+    
+    // map[][]'s bounds
+    public int maxx;
+    public int maxy;
+
+    // our current position
+    public int posx;
+    public int posy;
+
+    // how many points we've gotten
+    public int sum;
+    
+    // our orientation
+    public int orientation;
+
+    // how many moves we've made
+    public int moves;
+
+    // print modulo for doing the abcdefg.... thing at print-time
+    public int pmod;
+
+    public Object clone()
+        {
+        Lawnmower myobj = (Lawnmower) (super.clone());
+        myobj.input = (LawnmowerData)(input.clone());
+        myobj.map = new int[map.length][];
+        for(int x=0;x<map.length;x++)
+            myobj.map[x] = (int[])(map[x].clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // I'm not using the default base for any of this stuff;
+        // it's not safe I think.
+
+        // set up our input
+        input = (LawnmowerData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA),null, LawnmowerData.class);
+        input.setup(state,base.push(P_DATA));
+
+        // load our map coordinates
+        maxx = state.parameters.getInt(base.push(P_X),null,1);
+        if (maxx==0)
+            state.output.error("The width (x dimension) of the lawn must be >0",
+                base.push(P_X));
+        maxy = state.parameters.getInt(base.push(P_Y),null,1);
+        if (maxy==0)
+            state.output.error("The length (y dimension) of the lawn must be >0",
+                base.push(P_Y));
+        state.output.exitIfErrors();
+            
+        // set up the map
+        
+        map = new int[maxx][maxy];
+        for(int x=0;x<maxx;x++)
+            for(int y=0;y<maxy;y++)
+                map[x][y]=UNMOWED;
+        }
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {               
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            sum = 0;
+            moves = 0;
+            posx = maxx/2+1;
+            posy = maxy/2+1;
+            orientation = O_UP;
+
+            // evaluate the individual
+            ((GPIndividual)ind).trees[0].child.eval(
+                state,threadnum,input,stack,((GPIndividual)ind),this);
+                
+            // clean up the map
+            for(int x=0;x<maxx;x++)
+                for(int y=0;y<maxy;y++)
+                    map[x][y]=UNMOWED;
+
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)(maxx*maxy - sum));
+            f.hits = sum;
+            ind.evaluated = true;
+            }
+        }
+
+    public void describe(
+        final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation, 
+        final int threadnum, 
+        final int log)
+        {
+        state.output.println("\n\nBest Individual's Map\n=====================", log);
+        
+        sum = 0;
+        moves = 0;
+        posx = maxx/2+1;
+        posy = maxy/2+1;
+        orientation = O_UP;
+            
+        // evaluate the individual
+        ((GPIndividual)ind).trees[0].child.eval(
+            state,threadnum,input,stack,((GPIndividual)ind),this);
+            
+        // print out the map
+        state.output.println(" Y ->", log);
+        for(int x=0;x<map.length;x++)
+            {
+            if (x==1) state.output.print("v", log);
+            else if (x==0) state.output.print("X",log);
+            else state.output.print(" ",log);
+            state.output.print("+",log);
+            for(int y=0;y<map[x].length;y++)
+                state.output.print("----+",log);
+            state.output.println("",log);
+            if (x==0) state.output.print("|",log);
+            else state.output.print(" ",log);
+            state.output.print("|",log);
+                
+            for(int y=0;y<map[x].length;y++)
+                {
+                if (map[x][y]==UNMOWED)
+                    state.output.print("    ",log);
+                else 
+                    {
+                    String s = "" + (map[x][y]);
+                    while (s.length()<4) s = " " + s;
+                    state.output.print(s + "|",log);
+                    }
+                }
+            state.output.println("",log);
+            }
+        if (map.length==1) state.output.print("v",log);
+        else state.output.print(" ",log);
+        state.output.print("+",log);
+        for(int y=0;y<map[map.length-1].length;y++)
+            state.output.print("----+",log);
+        state.output.println("",log);
+            
+            
+        // clean up the map
+        for(int x=0;x<maxx;x++)
+            for(int y=0;y<maxy;y++)
+                map[x][y]=UNMOWED;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/LawnmowerData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/LawnmowerData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/LawnmowerData.java	(revision 6152)
@@ -0,0 +1,35 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower;
+import ec.gp.*;
+
+/* 
+ * LawnmowerData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class LawnmowerData extends GPData
+    {
+    // return value
+    public int x;
+    public int y;
+
+    public void copyTo(final GPData gpd) 
+        {
+        LawnmowerData d = (LawnmowerData)gpd;
+        d.x = x;
+        d.y = y;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf.params	(revision 6152)
@@ -0,0 +1,150 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+# First, we're gonna change the number of trees in
+# the individual, to accommodate the ADFs
+# Each of our three trees uses a different tree constraints,
+# tc0, tc1, tc2
+
+pop.subpop.0.species.ind.numtrees = 3
+
+# "The result-producing branch" (Koza-II p. 245)
+pop.subpop.0.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.0.tc = tc0
+# "ADF0 body" (Koza-II p. 245)
+pop.subpop.0.species.ind.tree.1 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.1.tc = tc1
+# "ADF1 body" (Koza-II p. 245)
+pop.subpop.0.species.ind.tree.2 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.2.tc = tc2
+
+
+
+# Now, let's define what tc0, tc1, and tc2 are.
+# Each has a different function set, f0, f1, and f2
+
+gp.tc.size = 3
+
+gp.tc.0 = ec.gp.GPTreeConstraints
+gp.tc.0.name = tc0
+gp.tc.0.fset = f0
+gp.tc.0.returns = nil
+gp.tc.0.init = ec.gp.koza.HalfBuilder
+gp.tc.0.init.growp = 0.5
+gp.tc.0.init.min = 2
+gp.tc.0.init.max = 6
+
+gp.tc.1 = ec.gp.GPTreeConstraints
+gp.tc.1.name = tc1
+gp.tc.1.fset = f1
+gp.tc.1.returns = nil
+gp.tc.1.init = ec.gp.koza.HalfBuilder
+gp.tc.1.init.growp = 0.5
+gp.tc.1.init.min = 2
+gp.tc.1.init.max = 6
+
+gp.tc.2 = ec.gp.GPTreeConstraints
+gp.tc.2.name = tc2
+gp.tc.2.fset = f2
+gp.tc.2.returns = nil
+gp.tc.2.init = ec.gp.koza.HalfBuilder
+gp.tc.2.init.growp = 0.5
+gp.tc.2.init.min = 2
+gp.tc.2.init.max = 6
+
+
+
+# Now, let's define the three function sets.
+
+gp.fs.size = 3
+
+gp.fs.0.name = f0
+gp.fs.0.size = 8
+gp.fs.0 = ec.gp.GPFunctionSet
+gp.fs.0.func.0 = ec.app.lawnmower.func.LawnERC
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.lawnmower.func.Left
+gp.fs.0.func.1.nc = nc0
+gp.fs.0.func.2 = ec.app.lawnmower.func.Mow
+gp.fs.0.func.2.nc = nc0
+gp.fs.0.func.3 = ec.app.lawnmower.func.V8a
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.lawnmower.func.Progn2
+gp.fs.0.func.4.nc = nc2
+gp.fs.0.func.5 = ec.app.lawnmower.func.Frog
+gp.fs.0.func.5.nc = nc1
+
+gp.fs.0.func.6 = ec.gp.ADF
+gp.fs.0.func.6.nc = nc0
+# tree 1 (the "ADF0 body")
+gp.fs.0.func.6.tree = 1
+gp.fs.0.func.6.name = ADF0
+
+gp.fs.0.func.7 = ec.gp.ADF
+gp.fs.0.func.7.nc = nc1
+# tree 1 (the "ADF1 body")
+gp.fs.0.func.7.tree = 2
+gp.fs.0.func.7.name = ADF1
+
+
+
+# It's interesting that in the "ADF0 body",
+# FROG is not used, see Koza-II p. 245
+gp.fs.1 = ec.gp.GPFunctionSet
+gp.fs.1.name = f1
+gp.fs.1.size = 5
+gp.fs.1.func.0 = ec.app.lawnmower.func.LawnERC
+gp.fs.1.func.0.nc = nc0
+gp.fs.1.func.1 = ec.app.lawnmower.func.Left
+gp.fs.1.func.1.nc = nc0
+gp.fs.1.func.2 = ec.app.lawnmower.func.Mow
+gp.fs.1.func.2.nc = nc0
+gp.fs.1.func.3 = ec.app.lawnmower.func.V8a
+gp.fs.1.func.3.nc = nc2
+gp.fs.1.func.4 = ec.app.lawnmower.func.Progn2
+gp.fs.1.func.4.nc = nc2
+
+# The "ADF1 body" -- see Koza-II p. 245
+gp.fs.2 = ec.gp.GPFunctionSet
+gp.fs.2.name = f2
+gp.fs.2.size = 8
+gp.fs.2.func.0 = ec.app.lawnmower.func.LawnERC
+gp.fs.2.func.0.nc = nc0
+gp.fs.2.func.1 = ec.app.lawnmower.func.Left
+gp.fs.2.func.1.nc = nc0
+gp.fs.2.func.2 = ec.app.lawnmower.func.Mow
+gp.fs.2.func.2.nc = nc0
+gp.fs.2.func.3 = ec.app.lawnmower.func.V8a
+gp.fs.2.func.3.nc = nc2
+gp.fs.2.func.4 = ec.app.lawnmower.func.Progn2
+gp.fs.2.func.4.nc = nc2
+gp.fs.2.func.5 = ec.app.lawnmower.func.Frog
+gp.fs.2.func.5.nc = nc1
+gp.fs.2.func.6 = ec.gp.ADFArgument
+gp.fs.2.func.6.nc = nc0
+gp.fs.2.func.6.name = ARG0
+# argument 0 of the calling ADF ("ADF1")
+gp.fs.2.func.6.arg = 0
+gp.fs.2.func.7 = ec.gp.ADF
+gp.fs.2.func.7.nc = nc0
+# tree 1 (the "ADF0 body")
+gp.fs.2.func.7.tree = 1
+gp.fs.2.func.7.name = ADF0
+
+
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.lawnmower.Lawnmower
+eval.problem.data = ec.app.lawnmower.LawnmowerData
+eval.problem.x = 8
+eval.problem.y = 8
+
+stat.gather-full = true
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf0.grammar
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf0.grammar	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf0.grammar	(revision 6152)
@@ -0,0 +1,3 @@
+<start> ::= <op>
+<op> ::= (progn2 <op> <op>) | (v8a <op> <op>)
+<op> ::= (mow) | (left) | (ERC)
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf1.grammar
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf1.grammar	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/adf1.grammar	(revision 6152)
@@ -0,0 +1,3 @@
+<start> ::= <op>
+<op> ::= (progn2 <op> <op>) | (v8a <op> <op>)
+<op> ::= (mow) | (left) | (ERC) | (ADF0) | (ARG0)
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Frog.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Frog.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Frog.java	(revision 6152)
@@ -0,0 +1,107 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower.func;
+import ec.*;
+import ec.app.lawnmower.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Frog.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Frog extends GPNode
+    {
+    public String toString() { return "frog"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Lawnmower p = (Lawnmower)problem;
+        LawnmowerData d = (LawnmowerData)input;
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        
+        // we follow the Koza-II example, not the lil-gp example.
+        // that is, we "assume" that in our orientation the X axis
+        // is moving out away from us, and the Y axis is moving
+        // out to the left.  In lil-gp, the assumption is that the Y axis
+        // axis is moving out away from us, and the X axis is moving out
+        // to the right.
+
+        switch (p.orientation)
+            {
+            case Lawnmower.O_UP:
+                // counter-clockwise rotation
+                p.posx -= d.y;
+                p.posy += d.x;
+                break;
+            case Lawnmower.O_LEFT:
+                // flipped orientation
+                p.posx -= d.x;
+                p.posy -= d.y;
+                break;
+            case Lawnmower.O_DOWN:
+                // clockwise rotation
+                p.posx += d.y;
+                p.posy -= d.x;
+                break;
+            case Lawnmower.O_RIGHT:
+                // proper orientation
+                p.posx += d.x;
+                p.posy += d.y;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+
+        // shift back into the lawn frame.
+        // because Java's % on negative numbers preserves the
+        // minus sign, we have to mod twice with an addition.
+        // C has to do this too.
+        p.posx = ((p.posx % p.maxx) + p.maxx ) % p.maxx ; 
+        p.posy = ((p.posy % p.maxy) + p.maxy ) % p.maxy ;
+
+        p.moves++;
+        if (p.map[p.posx][p.posy]==Lawnmower.UNMOWED)
+            {
+            p.sum++;
+            p.map[p.posx][p.posy] = p.moves;
+            }
+
+        // return [x,y] -- to do this, simply don't modify input
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/LawnERC.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/LawnERC.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/LawnERC.java	(revision 6152)
@@ -0,0 +1,150 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower.func;
+import ec.*;
+import ec.app.lawnmower.*;
+import ec.gp.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * LawnERC.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class LawnERC extends ERC
+    {
+    public int maxx;
+    public int maxy;
+
+    public int x;
+    public int y;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        // figure the coordinate base -- this will break if the underlying
+        // base changes, oops
+        Parameter newbase = 
+            new Parameter(EvolutionState.P_EVALUATOR).push(Evaluator.P_PROBLEM);
+
+        // obviously not using the default base for any of this stuff
+
+        // load our map coordinates
+        maxx = state.parameters.getInt(newbase.push(Lawnmower.P_X),null,1);
+        if (maxx==0)
+            state.output.error("The width (x dimension) of the lawn must be >0",
+                newbase.push(Lawnmower.P_X));
+        maxy = state.parameters.getInt(newbase.push(Lawnmower.P_Y),null,1);
+        if (maxy==0)
+            state.output.error("The length (y dimension) of the lawn must be >0",
+                newbase.push(Lawnmower.P_X));
+        state.output.exitIfErrors();      
+        }
+
+    public void resetNode(final EvolutionState state, final int thread)
+        {
+        x = state.random[thread].nextInt(maxx);
+        y = state.random[thread].nextInt(maxy);
+        }
+
+    public int nodeHashCode()
+        {
+        // a reasonable hash code
+        return this.getClass().hashCode() + x*maxy + y;
+        }
+
+    public boolean nodeEquals(final GPNode node)
+        {
+        // check first to see if we're the same kind of ERC -- 
+        // won't work for subclasses; in that case you'll need
+        // to change this to isAssignableTo(...)
+        if (this.getClass() != node.getClass()) return false;
+        // now check to see if the ERCs hold the same value
+        LawnERC n = (LawnERC)node;
+        return (n.x==x && n.y==y);
+        }
+
+    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        x = dataInput.readInt();
+        y = dataInput.readInt();
+        }
+
+    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(x);
+        dataOutput.writeInt(y);
+        }
+
+    public String encode()
+        { return Code.encode(x) + Code.encode(y); }
+
+    public boolean decode(DecodeReturn dret)
+        {
+        // store the position and the string in case they
+        // get modified by Code.java
+        int pos = dret.pos;
+        String data = dret.data;
+
+        // decode
+        Code.decode(dret);
+
+        if (dret.type != DecodeReturn.T_INT) // uh oh!
+            {
+            // restore the position and the string; it was an error
+            dret.data = data;
+            dret.pos = pos;
+            return false;
+            }
+
+        // store the data
+        x = (int)(dret.l);
+
+        // decode
+        Code.decode(dret);
+
+        if (dret.type != DecodeReturn.T_INT) // uh oh!
+            {
+            // restore the position and the string; it was an error
+            dret.data = data;
+            dret.pos = pos;
+            return false;
+            }
+
+        // store the data
+        y = (int)(dret.l);
+
+        return true;
+        }
+
+    public String toStringForHumans()
+        { return "[" + x + "," + y + "]"; }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        LawnmowerData rd = ((LawnmowerData)(input));
+        rd.x = x;
+        rd.y = y;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Left.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Left.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Left.java	(revision 6152)
@@ -0,0 +1,79 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower.func;
+import ec.*;
+import ec.app.lawnmower.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Left.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Left extends GPNode
+    {
+    public String toString() { return "left"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Lawnmower p = (Lawnmower)problem;
+        LawnmowerData d = (LawnmowerData)input;
+
+        switch (p.orientation)
+            {
+            case Lawnmower.O_UP:
+                p.orientation = Lawnmower.O_LEFT; 
+                break;
+            case Lawnmower.O_LEFT:
+                p.orientation = Lawnmower.O_DOWN;
+                break;
+            case Lawnmower.O_DOWN:
+                p.orientation = Lawnmower.O_RIGHT;
+                break;
+            case Lawnmower.O_RIGHT:
+                p.orientation = Lawnmower.O_UP;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+        //p.moves++;
+
+        // return [0,0]
+        d.x = 0;
+        d.y = 0;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Mow.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Mow.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Mow.java	(revision 6152)
@@ -0,0 +1,89 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower.func;
+import ec.*;
+import ec.app.lawnmower.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Mow.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Mow extends GPNode
+    {
+    public String toString() { return "mow"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        Lawnmower p = (Lawnmower)problem;
+        LawnmowerData d = (LawnmowerData)input;
+
+        switch (p.orientation)
+            {
+            case Lawnmower.O_UP:
+                p.posy--;
+                if (p.posy<0) p.posy = p.maxy-1;
+                break;
+            case Lawnmower.O_LEFT:
+                p.posx--;
+                if (p.posx<0) p.posx = p.maxx-1;
+                break;
+            case Lawnmower.O_DOWN:
+                p.posy++;
+                if (p.posy>=p.maxy) p.posy=0;
+                break;
+            case Lawnmower.O_RIGHT:
+                p.posx++;
+                if (p.posx>=p.maxx) p.posx=0;
+                break;
+            default:  // whoa!
+                state.output.fatal("Whoa, somehow I got a bad orientation! (" + p.orientation + ")");
+                break;
+            }
+
+        p.moves++;
+        if (p.map[p.posx][p.posy]==Lawnmower.UNMOWED)
+            {
+            p.sum++;
+            p.map[p.posx][p.posy] = p.moves;
+            }
+
+        // return [0,0]
+        d.x = 0;
+        d.y = 0;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Progn2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Progn2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/Progn2.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower.func;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Progn2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Progn2 extends GPNode
+    {
+    public String toString() { return "progn2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // Evaluate both children.  Return the second one (done automagically).
+        children[0].eval(state,thread,input,stack,individual,problem);
+        children[1].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/V8a.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/V8a.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/func/V8a.java	(revision 6152)
@@ -0,0 +1,67 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.lawnmower.func;
+import ec.*;
+import ec.app.lawnmower.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * V8a.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class V8a extends GPNode
+    {
+    public final static int MODULO = 8;  // odd that it doesn't change with map size
+
+    public String toString() { return "v8a"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        int resultx;
+        int resulty;
+
+        LawnmowerData rd = ((LawnmowerData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        resultx = rd.x;
+        resulty = rd.y;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = (resultx + rd.x) % MODULO;
+        rd.y = (resulty + rd.y) % MODULO;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/ge.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/ge.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/ge.params	(revision 6152)
@@ -0,0 +1,28 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/ge/ge.params
+parent.1 = adf.params
+
+ge.species.file.0 = lawnmower.grammar
+ge.species.file.1 = adf0.grammar
+ge.species.file.2 = adf1.grammar
+
+eval.problem.problem = ec.app.lawnmower.Lawnmower
+eval.problem.problem.data = ec.app.lawnmower.LawnmowerData
+eval.problem.problem.x = 8
+eval.problem.problem.y = 8
+
+# ec/gp/ge/ge.params defines a dummy individual as only having one tree.
+# This overrides adf.params above, so we need to reset that.
+pop.subpop.0.species.gp-species.ind.numtrees = 3
+
+# Also in GE the trees are in species.gp-species...,
+# So we need to define this as well
+pop.subpop.0.species.gp-species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.gp-species.ind.tree.0.tc = tc0
+pop.subpop.0.species.gp-species.ind.tree.1 = ec.gp.GPTree
+pop.subpop.0.species.gp-species.ind.tree.1.tc = tc1
+pop.subpop.0.species.gp-species.ind.tree.2 = ec.gp.GPTree
+pop.subpop.0.species.gp-species.ind.tree.2.tc = tc2
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/lawnmower.grammar
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/lawnmower.grammar	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/lawnmower.grammar	(revision 6152)
@@ -0,0 +1,3 @@
+<start> ::= <op>
+<op> ::= (progn2 <op> <op>) | (v8a <op> <op>) | (frog <op>)
+<op> ::= (mow) | (left) | (ERC) | (ADF0) | (ADF1 <op>)
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/noadf.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/noadf.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/lawnmower/noadf.params	(revision 6152)
@@ -0,0 +1,38 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+gp.fs.0.size = 6
+gp.fs.0.func.0 = ec.app.lawnmower.func.LawnERC
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.lawnmower.func.Left
+gp.fs.0.func.1.nc = nc0
+gp.fs.0.func.2 = ec.app.lawnmower.func.Mow
+gp.fs.0.func.2.nc = nc0
+gp.fs.0.func.3 = ec.app.lawnmower.func.V8a
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.lawnmower.func.Progn2
+gp.fs.0.func.4.nc = nc2
+gp.fs.0.func.5 = ec.app.lawnmower.func.Frog
+gp.fs.0.func.5.nc = nc1
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.lawnmower.Lawnmower
+eval.problem.data = ec.app.lawnmower.LawnmowerData
+eval.problem.x = 8
+eval.problem.y = 8
+
+stat.gather-full = true
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/MooSuite.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/MooSuite.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/MooSuite.java	(revision 6152)
@@ -0,0 +1,321 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.moosuite;
+
+import ec.util.*;
+import ec.*;
+import ec.multiobjective.MultiObjectiveFitness;
+import ec.simple.*;
+import ec.vector.*;
+
+/**
+   Several standard Multi-objective benchmarks are implemented: 
+   <ul>
+   <li>ZDT1: Zitzler, Deb & Thiele
+   <li>ZDT2: Zitzler, Deb & Thiele 
+   <li>ZDT3: Zitzler, Deb & Thiele 
+   <li>ZDT4: Zitzler, Deb & Thiele 
+   <li>ZDT6: Zitzler, Deb & Thiele 
+   <li>SPHERE: ftp.tik.ee.ethz.ch/pub/people/zitzler/ZLT2001a.pdf 
+   <li>SCH: (Schaffer), (a.k.a. F1 in Srinivas & Deb); requires exactly 1 decision variables (genes)
+   <li>F2: (Schaffer), (Srinivas & Deb),  (Coello Coello & Cortes); requires exactly 1 decision variables (genes)
+   <li>unconstrained F3: Schaffer, Srinivas & Deb  (Chankong & Haimes); requires exactly 2 decision variables (genes)
+   <li>QV: Quagliarella & Vicini
+   <li>FON: Fonseca & Fleming; requires exactly 3 decision variables (genes)
+   <li>POL: Poloni; requires exactly 2 decision variables (genes)
+   <li>KUR: Kursawe from the Errata of Zitzler's TIK-Report 103: "SPEA2: Improving the Strength Pareto Evolutionary Algorithm"
+   (note that many different versions are described in the literature).
+   </ul>   
+
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>type</tt><br>
+   <font size=-1>String, one of: zdt1, zdt2, zdt3, zdt4, zdt6, sphere, sch, fon, qv, pol, kur, f1, f2, unconstrained-f3</font></td>
+   <td valign=top>The multi-objective optimization problem to test against. </td></tr>
+   </table>
+   @author Gabriel Catalin Balan 
+*/
+ 
+public class MooSuite extends Problem implements SimpleProblemForm
+    {
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+    public static final String P_WHICH_PROBLEM = "type";
+    public static final String P_ZDT1 = "zdt1";
+    public static final String P_ZDT2 = "zdt2";
+    public static final String P_ZDT3 = "zdt3";
+    public static final String P_ZDT4 = "zdt4";
+    public static final String P_ZDT6 = "zdt6";
+    public static final String P_SPHERE = "sphere";
+    public static final String P_SCH = "sch";
+    public static final String P_FON = "fon";
+    public static final String P_QV = "qv";
+    public static final String P_POL = "pol";
+    public static final String P_KUR_NSGA2 = "kur-nsga2";
+    public static final String P_KUR_SPEA2 = "kur-spea2";
+    public static final String P_F1 = "f1";    
+    public static final String P_F2 = "f2";
+    public static final String P_F3 = "unconstrained-f3";
+
+    //Some of the following problems requires an exact number of decision variables (genes). This is mentioned in comment preceding the problem.
+
+    public static final int PROB_SPHERE = 0;
+    public static final int PROB_ZDT1 = 1;
+    public static final int PROB_ZDT2 = 2;
+    public static final int PROB_ZDT3 = 3;
+    public static final int PROB_ZDT4 = 4;
+    public static final int PROB_ZDT6 = 6;
+    public static final int PROB_FON = 7;
+    public static final int PROB_POL = 8;
+    public static final int PROB_KUR_NSGA2 = 9;
+    public static final int PROB_KUR_SPEA2 = 10;
+    public static final int PROB_QV = 11;
+    public static final int PROB_SCH = 12;
+    public static final int PROB_F2 = 13;
+    public static final int PROB_F3 = 14;
+
+    public int problemType = PROB_ZDT1;  // defaults on zdt1
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+        String wp = state.parameters.getStringWithDefault( base.push( P_WHICH_PROBLEM ), null, "" );
+        if( wp.compareTo( P_ZDT1) == 0 )
+            problemType = PROB_ZDT1;
+        else if ( wp.compareTo( P_ZDT2) == 0 )
+            problemType = PROB_ZDT2;
+        else if ( wp.compareTo( P_ZDT3) == 0 )
+            problemType = PROB_ZDT3;
+        else if ( wp.compareTo( P_ZDT4) == 0 )
+            problemType = PROB_ZDT4;
+        else if ( wp.compareTo( P_ZDT6) == 0 )
+            problemType = PROB_ZDT6;
+        else if ( wp.compareTo( P_FON) == 0 )
+            problemType = PROB_FON;
+        else if ( wp.compareTo( P_POL) == 0 )
+            problemType = PROB_POL;
+        else if ( wp.compareTo( P_QV) == 0 )
+            problemType = PROB_QV;
+        else if ( wp.compareTo( P_KUR_NSGA2) == 0 )
+            problemType = PROB_KUR_NSGA2;
+        else if ( wp.compareTo( P_KUR_SPEA2) == 0 )
+            problemType = PROB_KUR_SPEA2;
+        else if( wp.compareTo( P_SPHERE) == 0)
+            problemType = PROB_SPHERE;         
+        else if( wp.compareTo( P_F2) == 0)
+            problemType = PROB_F2;
+        else if( wp.compareTo( P_F3) == 0)
+            problemType = PROB_F3;
+        else if( wp.compareTo( P_SCH) == 0 || wp.compareTo( P_F1) == 0 )
+            problemType = PROB_SCH;         
+        else state.output.fatal(
+            "Invalid value for parameter, or parameter not found.\n" +
+            "Acceptable values are:\n" +
+            "  " + P_ZDT1 + "\n" +
+            "  " + P_ZDT2 + "\n" +
+            "  " + P_ZDT3 + "\n" +
+            "  " + P_ZDT4 + "\n" +
+            "  " + P_ZDT6 + "\n" +
+            "  " + P_POL + "\n" +
+            "  " + P_FON + "\n" +
+            "  " + P_KUR_NSGA2 + "\n" +
+            "  " + P_KUR_SPEA2 + "\n" +
+            "  " + P_SPHERE + "\n" +
+            "  " + P_SCH + "(or " + P_F1 + ")\n"+
+            "  " + P_F2 + "\n",
+            base.push( P_WHICH_PROBLEM ) );
+        }
+    private static final double TWO_PI = Math.PI*2;//QV uses it.
+    private static final double TEN_PI = Math.PI*10;//ZDT3 uses it.
+    private static final double FOUR_PI = Math.PI*4;//ZDT4 uses it.
+    private static final double SIX_PI = Math.PI*6;//ZDT6 uses it.
+    private static final double ONE_OVER_SQRT_3 = 1d/Math.sqrt(3);//FON uses it.
+    private static final double A1 = 0.5*Math.sin(1) - 2*Math.cos(1) +    Math.sin(2)- 1.5*Math.cos(2);//POL uses it
+    private static final double A2 = 1.5*Math.sin(1) -   Math.cos(1) + 2* Math.sin(2)- 0.5*Math.cos(2);//POL uses it
+
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if( !( ind instanceof DoubleVectorIndividual ) )
+            state.output.fatal( "The individuals for this problem should be DoubleVectorIndividuals." );
+
+        DoubleVectorIndividual temp = (DoubleVectorIndividual)ind;
+        double[] genome = temp.genome;
+        int numDecisionVars = genome.length;
+
+        float[] objectives = ((MultiObjectiveFitness)ind.fitness).getObjectives();
+
+        double f, g, h, sum;
+                
+        switch(problemType)
+            {
+            case PROB_ZDT1:
+                f = genome[0];
+                objectives[0] = (float)f;
+                sum = 0;
+                for(int i = 1; i< numDecisionVars; ++i)
+                    sum += genome[i];
+                g = 1d+9d*sum/(numDecisionVars-1);
+                h = 1d-Math.sqrt(f/g);
+                objectives[1] = (float)(g*h);
+                break;
+                
+            case PROB_ZDT2:
+                f = genome[0];
+                objectives[0] = (float)f;
+                sum = 0;
+                for(int i = 1; i< numDecisionVars; i++)
+                    sum += genome[i];
+                g = 1.0+9.0*sum/(float)(numDecisionVars-1);
+                h = 1.0-(f/g)*(f/g);
+                objectives[1] = (float)(g*h);
+                break;
+                        
+            case PROB_ZDT3:     
+                f = genome[0];
+                objectives[0] = (float)f;
+                sum = 0;
+                for(int i = 1; i< numDecisionVars; i++)
+                    sum += genome[i];
+                g = 1.0+9.0*sum/(numDecisionVars-1);
+                double foverg = f/g;
+                h = 1.0-Math.sqrt(foverg) - foverg * Math.sin(TEN_PI * f);
+                objectives[1] = (float)(g*h);
+                break;
+            case PROB_ZDT4:
+                f = genome[0];
+                objectives[0] = (float)f;
+                sum = 0;
+                for(int i = 1; i< numDecisionVars; ++i)
+                    sum += genome[i]*genome[i]- 10*Math.cos(FOUR_PI * genome[i]);
+                                
+                g = 1+10*(numDecisionVars-1)+sum;
+                h = 1-Math.sqrt(f/g);
+                objectives[1] = (float)(g*h);
+                break;                
+            case PROB_ZDT6:
+                f = 1 - (Math.exp(-4 * genome[0]) * Math.pow(Math.sin(SIX_PI * genome[0]), 6));
+                objectives[0] = (float)f;
+                sum = 0;
+                for (int i = 1; i < numDecisionVars; ++i)
+                    sum += genome[i];
+                g = 1d + 9 * Math.pow(sum / (numDecisionVars - 1), 0.25);
+                h = 1d - Math.pow(f / g, 2);
+                objectives[1] = (float) (g * h);
+                break; 
+            case PROB_SPHERE:
+                int numObjectives = objectives.length;
+                for(int j=0; j<numObjectives; ++j)
+                    {
+                    sum = (genome[j]-1)*(genome[j]-1);
+                    for(int i=0; i<numDecisionVars; ++i)
+                        if (i!=j)
+                            sum += genome[i]*genome[i];
+                    objectives[j] = (float)sum;
+                    }
+                break;
+            case PROB_SCH:
+                if(numDecisionVars!=1) throw new RuntimeException("SCH needs exactly 1 decision variable (gene).");
+                double x = genome[0];
+                objectives[0]=(float)(x*x);
+                objectives[1]=(float)((x-2)*(x-2));
+                break;
+            case PROB_F2:
+                if(numDecisionVars!=1) throw new RuntimeException("F2 needs exactly 1 decision variable (gene).");
+                x = genome[0];
+                objectives[0]=(float)( x<=1? -x: (x<=3? x-2:(x<=4? 4-x: x-4)));
+                objectives[1]=(float)((x-5)*(x-5));
+                break;
+            case PROB_F3:
+                if(numDecisionVars!=2) throw new RuntimeException("F3 needs exactly 2 decision variable (gene).");
+                double x1 = genome[0];
+                double x2 = genome[1];
+                objectives[0]=(float)((x1-2)*(x1-2)+(x2-1)*(x2-1)+2);
+                objectives[1]=(float)(9*x1-(x2-1)*(x2-1));
+                break;
+            case PROB_FON:
+                if(numDecisionVars!=3) throw new RuntimeException("FON needs exactly 3 decision variables (genes).");
+                double sum1 = 0, sum2=0;
+                for(int i = 0; i< numDecisionVars; i++)
+                    {
+                    double xi = genome[i];
+                    double d = xi-ONE_OVER_SQRT_3;
+                    double s = xi+ONE_OVER_SQRT_3;
+                    sum1+=d*d;
+                    sum2+=s*s;
+                    }
+                objectives[0] = 1 - (float)Math.exp(-sum1);
+                objectives[1] = 1 - (float)Math.exp(-sum2);
+                break;
+            case PROB_POL:
+                if(numDecisionVars!=2) throw new RuntimeException("POL needs exactly 2 decision variables (genes).");
+                x1= genome[0];
+                x2 = genome[1];
+                double b1 = 0.5*Math.sin(x1) - 2*Math.cos(x1) +    Math.sin(x2)- 1.5*Math.cos(x2);
+                double b2 = 1.5*Math.sin(x1) -   Math.cos(x1) + 2* Math.sin(x2)- 0.5*Math.cos(x2);
+                objectives[0] = (float)(1+(A1-b1)*(A1-b1)+(A2-b2)*(A2-b2));
+                objectives[1] = (float)((x1+3)*(x1+3)+(x2+1)*(x2+1));
+                break;
+            case PROB_QV:
+                sum=0;
+                for(int i=0;i<numDecisionVars;i++)
+                    {
+                    double xi=genome[i];
+                    sum+=xi*xi-10*Math.cos(TWO_PI*xi)+10;
+                    }
+                objectives[0] = (float)Math.pow(sum/numDecisionVars, 0.25);
+                sum=0;
+                for(int i=0;i<numDecisionVars;i++)
+                    {
+                    double xi=genome[i]-1.5;
+                    sum+=xi*xi-10*Math.cos(TWO_PI*xi)+10;
+                    }
+                objectives[1] = (float)Math.pow(sum/numDecisionVars, 0.25);
+                break;
+            case PROB_KUR_NSGA2:
+                double nextSquared, thisSquared;
+                thisSquared = genome[0]*genome[0];
+                sum=0;
+                for(int i = 0; i< numDecisionVars-1; ++i)
+                    {
+                    nextSquared = genome[i+1]*genome[i+1];
+                    //sum += 1d-Math.exp(-0.2*Math.sqrt(thisSquared + nextSquared));
+                    sum += -10-Math.exp(-0.2*Math.sqrt(thisSquared + nextSquared));
+                    thisSquared = nextSquared;
+                    }
+                //objectives[1] = (float)sum;
+                objectives[0] = (float)sum;
+                sum= 0;
+                for(int i = 0; i< numDecisionVars; ++i)
+                    {
+                    //double sin_xi = Math.sin(genome[i]);          
+                    //double t1 = Math.pow(Math.abs(genome[i]), .8);
+                    //double t2 = 5*sin_xi*sin_xi*sin_xi;
+                    //sum +=t1+t2+ 3.5828;
+                    double xi3 = Math.pow(genome[i], 3);
+                    double t1 = Math.pow(Math.abs(genome[i]), .8);
+                    double t2 = 5*Math.sin(xi3);
+                    sum +=t1+t2;
+                    }
+                //objectives[0] = (float)sum;
+                objectives[1] = (float)sum;
+                break;
+
+            default:
+                state.output.fatal( "ec.app.ecsuite.ECSuite has an invalid problem -- how on earth did that happen?" );
+                break;
+            }
+
+        ((MultiObjectiveFitness)ind.fitness).setObjectives(state, objectives);
+        ind.evaluated = true;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/f2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/f2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/f2.params	(revision 6152)
@@ -0,0 +1,13 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = f2
+# Carlos Coello Coello & Nareli Cruz Cortes, 2002
+
+pop.subpop.0.species.min-gene = -5
+pop.subpop.0.species.max-gene = 10
+pop.subpop.0.species.genome-size = 1
+pop.subpop.0.species.mutation-prob = 1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/fon.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/fon.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/fon.params	(revision 6152)
@@ -0,0 +1,13 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = fon
+pop.subpop.0.species.fitness.maximize = false
+
+pop.subpop.0.species.min-gene = -4
+pop.subpop.0.species.max-gene = 4
+pop.subpop.0.species.genome-size = 3
+pop.subpop.0.species.mutation-prob = 0.3333
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/kur-nsga2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/kur-nsga2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/kur-nsga2.params	(revision 6152)
@@ -0,0 +1,14 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = kur-nsga2
+#Kursawe from 
+#
+#Note that many different versions are described in the literature!
+pop.subpop.0.species.min-gene = -5
+pop.subpop.0.species.max-gene = 5
+pop.subpop.0.species.genome-size = 3
+pop.subpop.0.species.mutation-prob = 0.3333
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/kur-spea2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/kur-spea2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/kur-spea2.params	(revision 6152)
@@ -0,0 +1,15 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = kur-spea2
+#Kursawe from the Errata of Zitzler's TIK-Report 103: 
+#"SPEA2: Improving the Strength Pareto Evolutionary Algorithm"
+#
+#Note that many different versions are described in the literature!
+pop.subpop.0.species.min-gene = -5
+pop.subpop.0.species.max-gene = 5
+pop.subpop.0.species.genome-size = 3
+pop.subpop.0.species.mutation-prob = 0.3333
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/moosuite.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/moosuite.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/moosuite.params	(revision 6152)
@@ -0,0 +1,44 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+#uncomment the desired multiobjective algorithm
+#parent.0 = spea2.params
+parent.0 = nsga2.params
+
+eval.problem = ec.app.moosuite.MooSuite
+
+#
+# optionally your type could be: zdt1, zdt2, zdt3, zdt4, zdt6, sphere
+#
+# Different problems has different default settings, so we suggest 
+# using the appropriate params file for each benchmark.
+
+pop.subpop.0.species = ec.vector.FloatVectorSpecies
+pop.subpop.0.species.ind = ec.vector.DoubleVectorIndividual
+pop.subpop.0.species.fitness.num-objectives = 2
+pop.subpop.0.species.fitness.maximize = false
+seed.0 = time
+
+
+# Uncomment this if you'd like to force reevaluation of all archive
+# members each generation.
+#
+# breed.reevaluate-elites.0 = true
+
+
+# The multiobjective optimization routines here can use any crossover
+# and mutation pipeline you like, but the literature tends to stick with
+# SBX for crossover and Polynomial Mutation.  And with good reason: our
+# tests indicate that Polynomial Mutation is much better than Gaussian of
+# any setting for these problems.  And for SPEA2 at least, SBX seems to
+# outperform most other crossover operators.  Note that we're using the
+# "bounded" Polynomial Mutation variant, which seems to do a bit better.
+
+pop.subpop.0.species.crossover-type = sbx
+pop.subpop.0.species.crossover-distribution-index = 20
+
+pop.subpop.0.species.mutation-type = polynomial
+pop.subpop.0.species.mutation-distribution-index = 20
+pop.subpop.0.species.mutation-bounded = true
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/nsga2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/nsga2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/nsga2.params	(revision 6152)
@@ -0,0 +1,33 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../multiobjective/nsga2/nsga2.params
+
+
+# NSGA-II wil use a population size of 100.  Its archive will be another 100 
+# on top of that.  Since we're not reevaluating elites, only the 100 new
+# individuals will be bred and evaluated each generation.
+#
+# For more discussion about how to get SPEA2 and NSGA-II to have "equivalent"
+# numbers of evaluations in ECJ, see the README files for the SPEA2 and NSGA-II
+# packages.
+#
+# constants from  "Zitzler, E., Deb, K., and Thiele, L., 2000,
+# Comparison of Multiobjective Evolutionary Algorithms: Empirical Results,
+# Evolutionary Computation, Vol. 8, No. 2, pp173-195."
+#
+pop.subpop.0.size =                     100
+generations =                           250
+
+
+# NSGA2's pipeline
+
+pop.subpop.0.species.pipe		     	= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.likelihood        	= 1.0
+pop.subpop.0.species.pipe.source.0		= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.likelihood 	= 0.9
+pop.subpop.0.species.pipe.source.0.source.0 	= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 	= same
+select.tournament.size 				= 2
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/pol.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/pol.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/pol.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = pol
+pop.subpop.0.species.min-gene = -3.141592653589793
+pop.subpop.0.species.max-gene = 3.141592653589793
+pop.subpop.0.species.genome-size = 2
+pop.subpop.0.species.mutation-prob = 0.5
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/qv.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/qv.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/qv.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = qv
+pop.subpop.0.species.min-gene = -5
+pop.subpop.0.species.max-gene = 5
+pop.subpop.0.species.genome-size = 100
+pop.subpop.0.species.mutation-prob = 0.01
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/sch.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/sch.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/sch.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = sch
+pop.subpop.0.species.min-gene = -1000
+pop.subpop.0.species.max-gene = 1000
+pop.subpop.0.species.genome-size = 1
+pop.subpop.0.species.mutation-prob = 1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/spea2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/spea2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/spea2.params	(revision 6152)
@@ -0,0 +1,34 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../multiobjective/spea2/spea2.params
+
+
+# SPEA2 varies in its archive size, and in ECJ the archive size is part of the
+# population, as opposed to NSGA-II, which temporarily builds its own archive
+# that is EXTERNAL to the population.  This means that in order to generate
+# an equivalent number of individuals to NSGA-II, we'll need to have a larger
+# population size in SPEA2.  Specifically, the population size should be
+# the NSGA-II size plus the desired archive size (number of elites).
+#
+# For more information, see discussion in the README files in the SPEA2 and
+# NSGA-II packages
+#
+# constants from  "Zitzler, E., Deb, K., and Thiele, L., 2000,
+# Comparison of Multiobjective Evolutionary Algorithms: Empirical Results,
+# Evolutionary Computation, Vol. 8, No. 2, pp173-195."
+#
+pop.subpop.0.size =                     150
+breed.elite.0 =				50
+generations =                           250
+
+# SPEA2's pipeline:
+pop.subpop.0.species.pipe                   	= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.likelihood        	= 1.0
+pop.subpop.0.species.pipe.source.0          	= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.likelihood 	= 0.9
+pop.subpop.0.species.pipe.source.0.source.0 	= ec.multiobjective.spea2.SPEA2TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 	= same
+select.tournament.size 				= 2
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/sphere.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/sphere.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/sphere.params	(revision 6152)
@@ -0,0 +1,19 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = sphere
+pop.subpop.0.species.min-gene = -1000
+pop.subpop.0.species.max-gene = 1000
+#for greater genome-size, 100 generations will not suffice.
+#e.g. for genome-size = 10, try generations >= 1000
+pop.subpop.0.species.genome-size = 2
+pop.subpop.0.species.mutation-prob = 0.2
+pop.supbop.0.species.bounded = true
+
+# www.tik.ee.ethz.ch/sop/publicationListFiles/zlt2001a.pdf uses both 2 and 3 objectives
+#
+pop.subpop.0.species.fitness.num-objectives = 2
+#pop.subpop.0.species.fitness.num-objectives = 3
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/unconstrained-f3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/unconstrained-f3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/unconstrained-f3.params	(revision 6152)
@@ -0,0 +1,13 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = unconstrained-f3
+pop.subpop.0.species.min-gene = -20
+pop.subpop.0.species.max-gene = 20
+pop.subpop.0.species.genome-size = 2
+pop.subpop.0.species.mutation-prob = 0.5
+
+#Srinivas & Deb uses a bit string representation with 15 bits per variable (30bit genome).
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt1.params	(revision 6152)
@@ -0,0 +1,12 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = zdt1
+pop.subpop.0.species.fitness.maximize = false
+pop.subpop.0.species.min-gene = 0
+pop.subpop.0.species.max-gene = 1
+pop.subpop.0.species.genome-size = 30
+pop.subpop.0.species.mutation-prob = 0.0333
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt2.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = zdt2
+pop.subpop.0.species.min-gene = 0
+pop.subpop.0.species.max-gene = 1
+pop.subpop.0.species.genome-size = 30
+pop.subpop.0.species.mutation-prob = 0.0333
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt3.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = zdt3
+pop.subpop.0.species.min-gene = 0
+pop.subpop.0.species.max-gene = 1
+pop.subpop.0.species.genome-size = 30
+pop.subpop.0.species.mutation-prob = 0.0333
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt4.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt4.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt4.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = zdt4
+# first gene in [0,1]
+pop.subpop.0.species.min-gene.0 = 0	
+pop.subpop.0.species.max-gene.0 = 1
+
+# the rest in [-5,5]
+pop.subpop.0.species.min-gene = -5	
+pop.subpop.0.species.max-gene = 5
+
+pop.subpop.0.species.genome-size = 10
+pop.subpop.0.species.mutation-prob = 0.1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt6.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt6.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/moosuite/zdt6.params	(revision 6152)
@@ -0,0 +1,12 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = moosuite.params
+
+eval.problem.type = zdt6
+pop.subpop.0.species.min-gene = 0
+pop.subpop.0.species.max-gene = 1
+
+pop.subpop.0.species.genome-size = 10
+pop.subpop.0.species.mutation-prob = 0.1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/11.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/11.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/11.params	(revision 6152)
@@ -0,0 +1,64 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+
+### The functions, carefully ordered :-)  (See below)
+
+gp.fs.0.func.0 = ec.app.multiplexer.func.And
+gp.fs.0.func.0.nc = nc2
+gp.fs.0.func.1 = ec.app.multiplexer.func.Or
+gp.fs.0.func.1.nc = nc2
+gp.fs.0.func.2 = ec.app.multiplexer.func.Not
+gp.fs.0.func.2.nc = nc1
+gp.fs.0.func.3 = ec.app.multiplexer.func.A0
+gp.fs.0.func.3.nc = nc0
+gp.fs.0.func.4 = ec.app.multiplexer.func.D0
+gp.fs.0.func.4.nc = nc0
+gp.fs.0.func.5 = ec.app.multiplexer.func.D1
+gp.fs.0.func.5.nc = nc0
+gp.fs.0.func.6 = ec.app.multiplexer.func.If
+gp.fs.0.func.6.nc = nc3
+gp.fs.0.func.7 = ec.app.multiplexer.func.A1
+gp.fs.0.func.7.nc = nc0
+gp.fs.0.func.8 = ec.app.multiplexer.func.D2
+gp.fs.0.func.8.nc = nc0
+gp.fs.0.func.9 = ec.app.multiplexer.func.D3
+gp.fs.0.func.9.nc = nc0
+gp.fs.0.func.10 = ec.app.multiplexer.func.A2
+gp.fs.0.func.10.nc = nc0
+gp.fs.0.func.11 = ec.app.multiplexer.func.D4
+gp.fs.0.func.11.nc = nc0
+gp.fs.0.func.12 = ec.app.multiplexer.func.D5
+gp.fs.0.func.12.nc = nc0
+gp.fs.0.func.13 = ec.app.multiplexer.func.D6
+gp.fs.0.func.13.nc = nc0
+gp.fs.0.func.14 = ec.app.multiplexer.func.D7
+gp.fs.0.func.14.nc = nc0
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.multiplexer.Multiplexer
+eval.problem.data = ec.app.multiplexer.MultiplexerData
+
+
+# Here we determine what kind of Multiplexer we're doing:
+
+# 11-Multiplexer with IF
+eval.problem.bits = 3
+gp.fs.0.size = 15
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/3.params	(revision 6152)
@@ -0,0 +1,10 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 11.params
+
+# 3-Multiplexer without IF
+eval.problem.bits = 1
+gp.fs.0.size = 6
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/6.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/6.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/6.params	(revision 6152)
@@ -0,0 +1,10 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 11.params
+
+
+# 6-Multiplexer with IF
+eval.problem.bits = 2
+gp.fs.0.size = 10
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/Fast.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/Fast.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/Fast.java	(revision 6152)
@@ -0,0 +1,86 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer;
+
+/* 
+ * Fast.java
+ * 
+ * Created: Tue Mar 21 18:53:53 2000
+ * By: Sean Luke
+ */
+
+/**
+ * Fast contains lots of magic numbers for speeding up Multiplexer,
+ * basically arrays of bitfields representing the various on/off bit
+ * values for all of the scoreboard permutations of 3, 6, and 11-multiplexer.
+ * Do not bother yourselves with the man behind the curtain!
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Fast  
+    {
+    /** 3-Multiplexer has 3 boolean variables (A0, D0, D1) */
+    public static final int M_3_OUTPUT = 3;
+    /** 3-Multiplexer has 8 permutations of its 3 boolean variables */
+    public static final int M_3_SIZE = 8;
+    /** 3-Multiplexer bitfield values for the 3 boolean variables and 1 output variable, stored as bytes (8 bits used) */
+    public static final byte M_3 [/*4*/] = 
+        { 85, 51, 15, 39 };
+    /** 3-Multiplexer names for the 3 boolean variables and 1 output variable */
+    public static final String M_3_NAMES[/*4*/] =
+        { "A0", "D0", "D1", "Output" };
+
+    /** 6-Multiplexer has 6 boolean variables (A0, A1, D0, D1, D2, D3) */
+    public static final int M_6_OUTPUT = 6;
+    /** 6-Multiplexer has 64 permutations of its 6 boolean variables */
+    public static final int M_6_SIZE = 64;
+    /** 6-Multiplexer bitfield values for the 6 boolean variables and 1 output variable, stored as longs (64 bits used) */
+    public static final long M_6[/*7*/] =
+        { 6148914691236517205L, 3689348814741910323L, 1085102592571150095L, 71777214294589695L, 281470681808895L, 4294967295L, 597899502893742975L };
+    /** 6-Multiplexer names for the 6 boolean variables and 1 output variable */
+    public static final String M_6_NAMES[/*7*/] =
+        { "A0", "A1", "D0", "D1", "D2", "D3", "Output" };
+
+    /** 11-Multiplexer has 11 boolean variables (A0, A1, A2, D0, D1, D2, D3, D4, D5, D6, D7) */
+    public static final int M_11_OUTPUT = 11;
+    /** 11-Multiplexer has 2048 permutations of its 11 boolean variables */
+    public static final int M_11_SIZE = 2048;
+    /** 11-Multiplexer bitfield values for the 11 boolean variables and 1 output variable, where each of the 12 variable slots is an array of 32 longs (32 x 64 bits = 2048) which together comprise the big long 2048-bit permutation vector for that variable. */
+    public static final long M_11[/*12*/][/*32*/] =
+        {
+        { 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L, 6148914691236517205L },
+        
+            { 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L, 3689348814741910323L },
+        
+            { 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L, 1085102592571150095L },
+        
+            { 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L, 71777214294589695L }, 
+
+            { 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L, 281470681808895L },
+
+            { 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L, 4294967295L },
+
+            { 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L, 0L, -1L },
+
+            { 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L, 0L, 0L, -1L, -1L },
+        
+            { 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L, 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L, 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L, 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L }, 
+        
+            { 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L },
+
+            { 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L, -1L },
+
+            { 36099990944243936L, 1193542756353470704L, 614821373648857320L, 1772264139058084088L, 325460682296550628L, 1482903447705777396L, 904182065001164012L, 2061624830410390780L, 180780336620397282L, 1338223102029624050L, 759501719325010666L, 1916944484734237434L, 470141027972703974L, 1627583793381930742L, 1048862410677317358L, 2206305176086544126L, 108440163782320609L, 1265882929191547377L, 687161546486933993L, 1844604311896160761L, 397800855134627301L, 1555243620543854069L, 976522237839240685L, 2133965003248467453L, 253120509458473955L, 1410563274867700723L, 831841892163087339L, 1989284657572314107L, 542481200810780647L, 1699923966220007415L, 1121202583515394031L, 2278645348924620799L }
+
+        };
+
+    /** 11-Multiplexer names for the 11 boolean variables and 1 output variable */    public static final String M_11_NAMES[/*12*/] =
+        { "A0", "A1", "A2", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "Output" };
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/Multiplexer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/Multiplexer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/Multiplexer.java	(revision 6152)
@@ -0,0 +1,157 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * Multiplexer.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Multiplexer implements the family of <i>n</i>-Multiplexer problems.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.multiplexer.MultiplexerData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Multiplexer problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>bits</tt><br>
+ <font size=-1>1, 2, or 3</font></td>
+ <td valign=top>(The number of address bits (1 == 3-multiplexer, 2 == 6-multiplexer, 3==11-multiplexer)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Multiplexer extends GPProblem implements SimpleProblemForm
+    {
+    public static final int NUMINPUTS = 20;
+    public static final String P_NUMBITS = "bits";
+
+    public int bits;  // number of bits in the data
+
+    // we'll need to deep clone this one though.
+    public MultiplexerData input;
+
+    public Object clone()
+        {
+        Multiplexer myobj = (Multiplexer) (super.clone());
+        myobj.input = (MultiplexerData)(input.clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // not using any default base -- it's not safe
+
+        // I figure 3 bits is plenty -- otherwise we'd be dealing with
+        // REALLY big arrays!
+        bits = state.parameters.getIntWithMax(base.push(P_NUMBITS),null,1,3);
+        if (bits<1)
+            state.output.fatal("The number of bits for Multiplexer must be between 1 and 3 inclusive");
+        
+        // set up our input
+        input = (MultiplexerData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA),null, MultiplexerData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        input.status = (byte)bits;
+
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            int sum = 0;
+                
+            ((GPIndividual)ind).trees[0].child.eval(
+                state,threadnum,input,stack,((GPIndividual)ind),this);
+                
+            if (bits==1)
+                {
+                byte item1 = input.dat_3;
+                byte item2 = Fast.M_3[Fast.M_3_OUTPUT];
+                for(int y=0;y<MultiplexerData.MULTI_3_BITLENGTH;y++)
+                    {
+                    // if the first bit matches, grab it as:
+                    // sum += 1 and not(item1 xor item2)
+                    // that is, if item1 and item2 are the SAME at bit 1
+                    // then we increase
+                    sum += ( 1 & ((item1 ^ item2) ^ (-1)));
+                    // shift to the next bit
+                    item1 = (byte)(item1 >>> 1);
+                    item2 = (byte)(item2 >>> 1);
+                    }
+                }
+            else if (bits==2)
+                {
+                long item1 = input.dat_6;
+                long item2 = Fast.M_6[Fast.M_6_OUTPUT];
+                for(int y=0;y<MultiplexerData.MULTI_6_BITLENGTH;y++)
+                    {
+                    // if the first bit matches, grab it
+                    sum += ( 1L & ((item1 ^ item2) ^(-1L)));
+                    // shift to the next bit
+                    item1 = item1 >>> 1;
+                    item2 = item2 >>> 1;
+                    }
+                }
+            else // bits==3
+                {
+                long item1, item2;
+                for(int y=0;y<MultiplexerData.MULTI_11_NUM_BITSTRINGS; y++)
+                    {
+                    item1 = input.dat_11[y];
+                    item2 = Fast.M_11[Fast.M_11_OUTPUT][y];
+                    //System.out.println("" + y + " ### " + item1 + " " + item2);
+                    for(int z=0;z<MultiplexerData.MULTI_11_BITLENGTH;z++)
+                        {
+                        // if the first bit matches, grab it
+                        sum += ( 1L & ((item1 ^ item2) ^(-1L)));
+                        // shift to the next bit
+                        item1 = item1 >>> 1;
+                        item2 = item2 >>> 1;
+                        }
+                    }
+                }
+                
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            if (bits==1)
+                f.setStandardizedFitness(state,(float)(Fast.M_3_SIZE - sum));
+            else if (bits==2)
+                f.setStandardizedFitness(state,(float)(Fast.M_6_SIZE - sum));
+            else // (bits==3)
+                f.setStandardizedFitness(state,(float)(Fast.M_11_SIZE - sum));
+            f.hits = sum;
+            ind.evaluated = true;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/MultiplexerData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/MultiplexerData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/MultiplexerData.java	(revision 6152)
@@ -0,0 +1,94 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer;
+import java.util.*;
+import ec.gp.*;
+
+/* 
+ * MultiplexerData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * This is ugly and complicated because it needs to hold a variety
+ * of different-length bitstrings, including temporary ones held
+ * while computing subtrees.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MultiplexerData extends GPData
+    {
+    /** A stack of available long arrays for popDat11/pushDat11 */
+    public Stack tmp;
+
+    /** The number of Dn in Multiplexer-3 */
+    public static final byte STATUS_3 = 1;
+    /** The number of Dn in Multiplexer-6 */
+    public static final byte STATUS_6 = 2;
+    /** The number of Dn in Multiplexer-11 */
+    public static final byte STATUS_11 = 3;
+    /** The length of an atomic data element in Multiplexer-3 (a byte) */
+    public static final int MULTI_3_BITLENGTH = 8;
+    /** The length of an atomic data element in Multiplexer-6 (a long) */
+    public static final int MULTI_6_BITLENGTH = 64;
+    /** The length of an atomic data element in Multiplexer-11 (a long) */
+    public static final int MULTI_11_BITLENGTH = 64;
+    /** The number of atomic elements in Multiplexer-11 comprising one string (32) */
+    public static final int MULTI_11_NUM_BITSTRINGS = 32;
+
+    /** An array of 32 longs for Multiplexer-11 data */
+    public long[] dat_11;
+    /** A long for Multiplexer-6 data */
+    public long dat_6;
+    /** A byte for Multiplexer-3 data */
+    public byte dat_3;
+    /** A byte indicating the number of Dn in this problem */
+    public byte status;
+
+    /** Pops a dat_11 off of the stack; if the stack is empty, creates a new dat_11 and returns that. */
+    public long[] popDat11()
+        {
+        if (tmp.empty())
+            return new long[MULTI_11_NUM_BITSTRINGS];
+        else return (long[])(tmp.pop());
+        }
+
+    /** Pushes a dat_11 onto the stack */
+    public void pushDat11(long[] l)
+        {
+        tmp.push(l);
+        }
+
+    public MultiplexerData() 
+        { 
+        dat_11 = new long[MULTI_11_NUM_BITSTRINGS]; 
+        tmp = new Stack();
+        }
+
+    public Object clone()
+        {
+        MultiplexerData dat = (MultiplexerData)(super.clone());
+        dat.dat_11 = new long[MULTI_11_NUM_BITSTRINGS];
+        System.arraycopy(dat_11,0,dat.dat_11,0,MULTI_11_NUM_BITSTRINGS);
+        dat.tmp = new Stack();
+        return dat;
+        }
+
+    public void copyTo(final GPData gpd)
+        { 
+        MultiplexerData md = ((MultiplexerData)gpd);
+        for(int x=0;x<MULTI_11_NUM_BITSTRINGS;x++)
+            md.dat_11[x] = dat_11[x];
+        md.dat_6 = dat_6;
+        md.status = status;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/README	(revision 6152)
@@ -0,0 +1,4 @@
+This is the new form of Multiplexer, 10 times the speed of the old form,
+but much more complex.  If you want to just use Multiplexer as an example
+template from which to write new application domains, you might want to
+use the old "slow" form instead.
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A0.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * A0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class A0 extends GPNode
+    {
+    final static int bitpos = 0;  /* A0 */
+
+    public String toString() { return "a0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A1.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * A1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class A1 extends GPNode
+    {
+    final static int bitpos = 1;  /* A1 */
+
+    public String toString() { return "a1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/A2.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * A2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class A2 extends GPNode
+    {
+    final static int bitpos = 2;  /* A2 */
+
+    public String toString() { return "a2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/And.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/And.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/And.java	(revision 6152)
@@ -0,0 +1,87 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * And.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class And extends GPNode
+    {
+    public String toString() { return "and"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+        long[] dat_11=null;  // quiets compiler complaints
+        long dat_6=0L;
+        byte dat_3=0;
+
+        // No shortcuts for now
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (md.status == MultiplexerData.STATUS_3)
+            dat_3 = md.dat_3;
+        else if (md.status == MultiplexerData.STATUS_6)
+            dat_6 = md.dat_6;
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            dat_11 = md.popDat11();
+            System.arraycopy(md.dat_11,0,
+                dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+            }
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+
+        // modify
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 &= dat_3;
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 &= dat_6;
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            for(int x=0;x<MultiplexerData.MULTI_11_NUM_BITSTRINGS;x++)
+                md.dat_11[x] &= dat_11[x];
+            md.pushDat11(dat_11);
+            }
+        }
+    }
+    
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D0.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D0 extends GPNode
+    {
+    final static int bitpos = 0;  /* D0 */
+
+    public String toString() { return "d0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D1.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D1 extends GPNode
+    {
+    final static int bitpos = 1;  /* D1 */
+
+    public String toString() { return "d1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D2.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D2 extends GPNode
+    {
+    final static int bitpos = 2;  /* D2 */
+
+    public String toString() { return "d2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D3.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D3.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D3.java	(revision 6152)
@@ -0,0 +1,66 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D3.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D3 extends GPNode
+    {
+    final static int bitpos = 3;  /* D3 */
+
+    public String toString() { return "d3"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D4.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D4.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D4.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D4.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D4 extends GPNode
+    {
+    final static int bitpos = 4;  /* D4 */
+
+    public String toString() { return "d4"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D5.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D5.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D5.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D5.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D5 extends GPNode
+    {
+    final static int bitpos = 5;  /* D5 */
+
+    public String toString() { return "d5"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D6.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D6.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D6.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D6.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D6 extends GPNode
+    {
+    final static int bitpos = 6;  /* D6 */
+
+    public String toString() { return "d6"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D7.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D7.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/D7.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D7.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D7 extends GPNode
+    {
+    final static int bitpos = 7;  /* D7 */
+
+    public String toString() { return "d7"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = Fast.M_3[bitpos + MultiplexerData.STATUS_3];
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = Fast.M_6[bitpos + MultiplexerData.STATUS_6];
+        else // md.status == MultiplexerData.STATUS_11
+            System.arraycopy(Fast.M_11[bitpos + MultiplexerData.STATUS_11],0,
+                md.dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/If.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/If.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/If.java	(revision 6152)
@@ -0,0 +1,116 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * If.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class If extends GPNode
+    {
+    public String toString() { return "if"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=3)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+        long[] dat_11_1=null;  // quiets compiler complaints
+        long[] dat_11_2=null;  // quiets compiler complaints
+        long dat_6_1=0L;
+        long dat_6_2=0L;
+        byte dat_3_1=0;
+        byte dat_3_2=0;
+
+        // No shortcuts for now
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (md.status == MultiplexerData.STATUS_3)
+            dat_3_1 = md.dat_3;
+        else if (md.status == MultiplexerData.STATUS_6)
+            dat_6_1 = md.dat_6;
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            dat_11_1 = md.popDat11();
+            System.arraycopy(md.dat_11,0,
+                dat_11_1,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+            }
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+
+        if (md.status == MultiplexerData.STATUS_3)
+            dat_3_2 = md.dat_3;
+        else if (md.status == MultiplexerData.STATUS_6)
+            dat_6_2  = md.dat_6;
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            dat_11_2 = md.popDat11();
+            System.arraycopy(md.dat_11,0,
+                dat_11_2,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+            }
+
+        // tweak -- if a then b else c is equivalent to
+        // (a -> b) ^ (~a -> c) which is equivalent to
+        // (~a v b) ^ (a v c).  In Java, ^ (-1) is the same
+        // is bitwise not.
+
+        children[2].eval(state,thread,input,stack,individual,problem);
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 = (byte)(
+                ((dat_3_1 ^ (byte)(-1)) | dat_3_2 ) &
+                ((dat_3_1 | md.dat_3)));
+
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 = 
+                ((dat_6_1 ^ (-1L)) | dat_6_2 ) &
+                ((dat_6_1 | md.dat_6));
+
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            for(int x=0;x<MultiplexerData.MULTI_11_NUM_BITSTRINGS;x++)
+                md.dat_11[x] = 
+                    ((dat_11_1[x] ^ (-1L)) | dat_11_2[x] ) &
+                    ((dat_11_1[x] | md.dat_11[x]));
+            md.pushDat11(dat_11_2);
+            md.pushDat11(dat_11_1);
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/Not.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/Not.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/Not.java	(revision 6152)
@@ -0,0 +1,63 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Not.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Not extends GPNode
+    {
+    public String toString() { return "not"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 ^= -1;
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 ^= -1L;
+        else // md.status == MultiplexerData.STATUS_11
+            for(int x=0;x<MultiplexerData.MULTI_11_NUM_BITSTRINGS;x++)
+                md.dat_11[x] ^= -1L;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/Or.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/Or.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexer/func/Or.java	(revision 6152)
@@ -0,0 +1,87 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexer.func;
+import ec.*;
+import ec.app.multiplexer.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Or.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Or extends GPNode
+    {
+    public String toString() { return "or"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        MultiplexerData md = (MultiplexerData)input;
+        long[] dat_11=null;  // quiets compiler complaints
+        long dat_6=0L;
+        byte dat_3=0;
+
+        // No shortcuts for now
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (md.status == MultiplexerData.STATUS_3)
+            dat_3 = md.dat_3;
+        else if (md.status == MultiplexerData.STATUS_6)
+            dat_6 = md.dat_6;
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            dat_11 = md.popDat11();
+            System.arraycopy(md.dat_11,0,
+                dat_11,0,
+                MultiplexerData.MULTI_11_NUM_BITSTRINGS);
+            }
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+
+        // modify
+
+        if (md.status == MultiplexerData.STATUS_3)
+            md.dat_3 |= dat_3;
+        else if (md.status == MultiplexerData.STATUS_6)
+            md.dat_6 |= dat_6;
+        else // md.status == MultiplexerData.STATUS_11
+            {
+            for(int x=0;x<MultiplexerData.MULTI_11_NUM_BITSTRINGS;x++)
+                md.dat_11[x] |= dat_11[x];
+            md.pushDat11(dat_11);
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/11.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/11.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/11.params	(revision 6152)
@@ -0,0 +1,64 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+
+### The functions, carefully ordered :-)  (See below)
+
+gp.fs.0.func.0 = ec.app.multiplexerslow.func.And
+gp.fs.0.func.0.nc = nc2
+gp.fs.0.func.1 = ec.app.multiplexerslow.func.Or
+gp.fs.0.func.1.nc = nc2
+gp.fs.0.func.2 = ec.app.multiplexerslow.func.Not
+gp.fs.0.func.2.nc = nc1
+gp.fs.0.func.3 = ec.app.multiplexerslow.func.A0
+gp.fs.0.func.3.nc = nc0
+gp.fs.0.func.4 = ec.app.multiplexerslow.func.D0
+gp.fs.0.func.4.nc = nc0
+gp.fs.0.func.5 = ec.app.multiplexerslow.func.D1
+gp.fs.0.func.5.nc = nc0
+gp.fs.0.func.6 = ec.app.multiplexerslow.func.If
+gp.fs.0.func.6.nc = nc3
+gp.fs.0.func.7 = ec.app.multiplexerslow.func.A1
+gp.fs.0.func.7.nc = nc0
+gp.fs.0.func.8 = ec.app.multiplexerslow.func.D2
+gp.fs.0.func.8.nc = nc0
+gp.fs.0.func.9 = ec.app.multiplexerslow.func.D3
+gp.fs.0.func.9.nc = nc0
+gp.fs.0.func.10 = ec.app.multiplexerslow.func.A2
+gp.fs.0.func.10.nc = nc0
+gp.fs.0.func.11 = ec.app.multiplexerslow.func.D4
+gp.fs.0.func.11.nc = nc0
+gp.fs.0.func.12 = ec.app.multiplexerslow.func.D5
+gp.fs.0.func.12.nc = nc0
+gp.fs.0.func.13 = ec.app.multiplexerslow.func.D6
+gp.fs.0.func.13.nc = nc0
+gp.fs.0.func.14 = ec.app.multiplexerslow.func.D7
+gp.fs.0.func.14.nc = nc0
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.multiplexerslow.Multiplexer
+eval.problem.data = ec.app.multiplexerslow.MultiplexerData
+
+
+# Here we determine what kind of Multiplexer we're doing:
+
+# 11-Multiplexer with IF
+eval.problem.bits = 3
+gp.fs.0.size = 15
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/3.params	(revision 6152)
@@ -0,0 +1,10 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 11.params
+
+# 3-Multiplexer without IF
+eval.problem.bits = 1
+gp.fs.0.size = 6
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/6.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/6.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/6.params	(revision 6152)
@@ -0,0 +1,10 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = 11.params
+
+
+# 6-Multiplexer with IF
+eval.problem.bits = 2
+gp.fs.0.size = 10
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/Multiplexer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/Multiplexer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/Multiplexer.java	(revision 6152)
@@ -0,0 +1,125 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * Multiplexer.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Multiplexer implements the family of <i>n</i>-Multiplexer problems.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.multiplexer.MultiplexerData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Multiplexer problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>bits</tt><br>
+ <font size=-1>1, 2, or 3</font></td>
+ <td valign=top>(The number of address bits (1 == 3-multiplexer, 2 == 6-multiplexer, 3==11-multiplexer)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Multiplexer extends GPProblem implements SimpleProblemForm
+    {
+    public static final int NUMINPUTS = 20;
+    public static final String P_NUMBITS = "bits";
+
+    public int bits;  // number of bits in the data
+    public int amax; // maximum address value
+    public int dmax; // maximum data value
+    public int addressPart;  // the current address part
+    public int dataPart;     // the current data part
+
+    // we'll need to deep clone this one though.
+    public MultiplexerData input;
+
+    public Object clone()
+        {
+        Multiplexer myobj = (Multiplexer) (super.clone());
+        myobj.input = (MultiplexerData)(input.clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // not using any default base -- it's not safe
+
+        // I figure 3 bits is plenty -- otherwise we'd be dealing with
+        // REALLY big arrays!
+        bits = state.parameters.getIntWithMax(base.push(P_NUMBITS),null,1,3);
+        if (bits<1)
+            state.output.fatal("The number of bits for Multiplexer must be between 1 and 3 inclusive");
+        
+        amax=1;
+        for(int x=0;x<bits;x++) amax *=2;   // safer than Math.pow(...)
+
+        dmax=1;
+        for(int x=0;x<amax;x++) dmax *=2;   // safer than Math.pow(...)
+        
+        // set up our input
+        input = (MultiplexerData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA),null, MultiplexerData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            int sum = 0;
+                
+            for(addressPart = 0; addressPart < amax; addressPart++)
+                for(dataPart = 0; dataPart < dmax; dataPart++)
+                    {
+                    ((GPIndividual)ind).trees[0].child.eval(
+                        state,threadnum,input,stack,((GPIndividual)ind),this);
+                    sum += 1- (                  /* "Not" */
+                        ((dataPart >>> addressPart) & 1) /* extracts the address-th 
+                                                            bit in data and moves 
+                                                            it to position 0, 
+                                                            clearing out all 
+                                                            other bits */
+                        ^                   /* "Is Different from" */
+                        (input.x & 1));      /* A 1 if input.x is 
+                                                non-zero, else 0. */
+                    }
+                
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)(amax*dmax - sum));
+            f.hits = sum;
+            ind.evaluated = true;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/MultiplexerData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/MultiplexerData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/MultiplexerData.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow;
+import ec.gp.*;
+
+/* 
+ * MultiplexerData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MultiplexerData extends GPData
+    {
+    // return value -- should ALWAYS be either 1 or 0
+    public int x;
+
+    public void copyTo(final GPData gpd) 
+        { ((MultiplexerData)gpd).x = x; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/README	(revision 6152)
@@ -0,0 +1,2 @@
+This is the original ECJ form of Multiplexer, easy to read and understand,
+but 1/10 the speed of the new form.
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A0.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * A0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class A0 extends GPNode
+    {
+    public String toString() { return "a0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x =
+            ((((Multiplexer)problem).addressPart >>> 0 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A1.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * A1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class A1 extends GPNode
+    {
+    public String toString() { return "a1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).addressPart >>> 1 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/A2.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * A2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class A2 extends GPNode
+    {
+    public String toString() { return "a2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).addressPart >>> 2 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/And.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/And.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/And.java	(revision 6152)
@@ -0,0 +1,59 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * And.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class And extends GPNode
+    {
+    public String toString() { return "and"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // shortcutting AND
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (((MultiplexerData)input).x == 1 )  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+        // else return the first item (already there)
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D0.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D0 extends GPNode
+    {
+    public String toString() { return "d0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 0 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D1.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D1 extends GPNode
+    {
+    public String toString() { return "d1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 1 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D2.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D2 extends GPNode
+    {
+    public String toString() { return "d2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 2 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D3.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D3.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D3.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D3.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D3 extends GPNode
+    {
+    public String toString() { return "d3"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 3 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D4.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D4.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D4.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D4.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D4 extends GPNode
+    {
+    public String toString() { return "d4"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 4 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D5.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D5.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D5.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D5.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D5 extends GPNode
+    {
+    public String toString() { return "d5"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 5 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D6.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D6.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D6.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D6.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D6 extends GPNode
+    {
+    public String toString() { return "d6"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 6 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D7.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D7.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/D7.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D7.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D7 extends GPNode
+    {
+    public String toString() { return "d7"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((MultiplexerData)input).x = 
+            ((((Multiplexer)problem).dataPart >>> 7 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/If.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/If.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/If.java	(revision 6152)
@@ -0,0 +1,59 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * If.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class If extends GPNode
+    {
+    public String toString() { return "if"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=3)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (((MultiplexerData)input).x == 1 )  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+        else // return the third item.
+            children[2].eval(state,thread,input,stack,individual,problem);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/Not.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/Not.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/Not.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Not.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Not extends GPNode
+    {
+    public String toString() { return "not"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        children[0].eval(state,thread,input,stack,individual,problem);
+        ((MultiplexerData)input).x ^= 1;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/Or.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/Or.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/multiplexerslow/func/Or.java	(revision 6152)
@@ -0,0 +1,59 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.multiplexerslow.func;
+import ec.*;
+import ec.app.multiplexerslow.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Or.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Or extends GPNode
+    {
+    public String toString() { return "or"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // shortcutting OR
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (((MultiplexerData)input).x == 0 )  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+        // else return the first item (already there)
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/nk/NK.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/nk/NK.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/nk/NK.java	(revision 6152)
@@ -0,0 +1,102 @@
+package ec.app.nk; 
+
+import ec.*; 
+import ec.simple.*; 
+import ec.vector.*; 
+import ec.util.*;
+import java.util.*;
+
+/**
+   NK implmements the NK-landscape developed by Stuart Kauffman (in the book <i>The Origins of
+   Order: Self-Organization and Selection in Evolution</a>).  In the NK model, the fitness 
+   contribution of each allele depends on how that allele interacts with K other alleles.  Based on 
+   this interaction, each gene contributes a random number between 0 and 1.  The individual's 
+   fitness is the average of these N random numbers.  
+
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>k</tt><br>
+   <font size=-1>int >= 0 && < 31</td>
+   <td valign=top>(number of interacting alleles)</td></tr>
+   <tr><td valign=top><i>base</i>.<tt>adjacent</tt><br> 
+   <font size=-1>boolean</font></td>
+   <td valign=top>(should interacting alleles be adjacent to the given allele)</td></tr> 
+   </table>
+ 
+   @author Keith Sullivan
+   @version 1.0
+*/
+
+
+public class NK extends Problem implements SimpleProblemForm 
+    { 
+    public static final String P_N = "n"; 
+    public static final String P_K = "k"; 
+    public static final String P_ADJACENT="adjacent"; 
+        
+    int k; 
+    boolean adjacentNeighborhoods;
+    HashMap oldValues; 
+        
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        super.setup(state, base); 
+                
+        k = state.parameters.getInt(base.push(P_K), null, 1); 
+        if ((k < 0) || (k > 31))
+            state.output.fatal("Value of k must be between 0 and 31", base.push(P_K)); 
+                
+        adjacentNeighborhoods = state.parameters.getBoolean(base.push(P_ADJACENT), null, true); 
+        oldValues = new HashMap(); 
+        }
+        
+    public void evaluate(final EvolutionState state, final Individual ind, final int subpopulation, final int threadnum)
+        {
+        BitVectorIndividual ind2 = (BitVectorIndividual) ind; 
+        double fitness =0; 
+        int n = ind2.genome.length; 
+                
+        for (int i=0; i < n; i++) 
+            { 
+            boolean tmpInd[] = new boolean[k+1]; 
+            tmpInd[0] = ind2.genome[i];
+                        
+            double val=0;
+            if (adjacentNeighborhoods) 
+                { 
+                int offset = n - k/2; 
+                for (int j=0; j < k; j++) 
+                    {
+                    tmpInd[j+1] = ind2.genome[(j+i + offset) % n]; 
+                    }
+                }
+            else 
+                { 
+                int j;
+                for (int l=0; l < k; l++) 
+                    { 
+                    while ((j = state.random[0].nextInt(k)) == i);
+                    tmpInd[l+1] = ind2.genome[j]; 
+                    }
+                }
+                        
+            if (oldValues.containsKey(tmpInd))
+                val = ((Double)oldValues.get(tmpInd)).doubleValue(); 
+            else 
+                { 
+                double tmp=0; 
+                for (int j=0; j < tmpInd.length; j++)  
+                    if (tmpInd[j]) tmp += 1 << j; 
+                val = tmp /  Integer.MAX_VALUE; 
+                                                                
+                oldValues.put(tmpInd, new Double(val)); 
+                }
+                        
+            fitness += val; 
+            }
+                                
+        fitness /= n;
+        ((SimpleFitness)(ind2.fitness)).setFitness( state, (float) fitness, false);
+        ind2.evaluated = true; 
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/nk/nk.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/nk/nk.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/nk/nk.params	(revision 6152)
@@ -0,0 +1,31 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../simple/simple.params
+
+seed.0 = time
+
+pop.subpop.0.species.genome-size = 20 
+
+eval.problem = ec.app.nk.NK
+eval.problem.n = 20 
+eval.problem.k = 5 
+eval.problem.adjacent = true 
+
+pop.subpop.0.size = 1000 
+generations = 100 
+
+pop.subpop.0.species = ec.vector.VectorSpecies 
+pop.subpop.0.species.pipe = ec.vector.breed.VectorMutationPipeline 
+pop.subpop.0.species.pipe.source.0 = ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same 
+
+pop.subpop.0.species.ind = ec.vector.BitVectorIndividual
+pop.subpop.0.species.fitness = ec.simple.SimpleFitness
+
+select.tournament.size =                2 
+pop.subpop.0.species.mutation-prob = 0.05
+pop.subpop.0.species.crossover-type =two  
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/Parity.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/Parity.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/Parity.java	(revision 6152)
@@ -0,0 +1,134 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * Parity.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Parity implements the family of <i>n</i>-[even|odd]-Parity problems up 
+ * to 32-parity.  Read the README file in this package for information on
+ * how to set up the parameter files to your liking -- it's a big family.
+ *
+ * <p>The Parity family evolves a boolean function on <i>n</i> sets of bits,
+ * which returns true if the number of 1's is even (for even-parity) or odd
+ * (for odd-parity), false otherwise. 
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.parity.ParityData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Parity problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>even</tt><br>
+ <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ <td valign=top>(is this even-parity (as opposed to odd-parity)?)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>bits</tt><br>
+ <font size=-1> 2 &gt;= int &lt;= 31</font></td>
+ <td valign=top>(The number of data bits)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Parity extends GPProblem implements SimpleProblemForm
+    {
+    public static final String P_NUMBITS = "bits";
+    public static final String P_EVEN = "even";
+
+    public boolean doEven;
+    public int numBits;
+    public int totalSize;
+
+    public int bits;  // data bits
+
+    // we'll need to deep clone this one though.
+    public ParityData input;
+
+    public Object clone()
+        {
+        Parity myobj = (Parity) (super.clone());
+        myobj.input = (ParityData)(input.clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // not using a default base here
+
+        // can't use all 32 bits -- Java is signed.  Must use 31 bits.
+        
+        numBits = state.parameters.getIntWithMax(base.push(P_NUMBITS),null,2,31);
+        if (numBits<2)
+            state.output.fatal("The number of bits for Parity must be between 2 and 31 inclusive",base.push(P_NUMBITS));
+        
+        totalSize = 1;
+        for(int x=0;x<numBits;x++)
+            totalSize *=2;   // safer than Math.pow()
+
+        doEven = state.parameters.getBoolean(base.push(P_EVEN),null,true);
+
+        // set up our input
+        input = (ParityData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA),null, ParityData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            int sum = 0;
+                
+            for(bits=0;bits<totalSize;bits++)
+                {
+                int tb = 0;
+                // first, is #bits even or odd?
+                for(int b=0;b<numBits;b++)
+                    tb += (bits >>> b) & 1;
+                tb &= 1;  // now tb is 1 if we're odd, 0 if we're even
+
+                ((GPIndividual)ind).trees[0].child.eval(
+                    state,threadnum,input,stack,((GPIndividual)ind),this);
+
+                if ((doEven && ((input.x & 1) != tb)) ||
+                    ((!doEven) && ((input.x & 1) == tb)))
+                    sum++;
+                }
+                
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)(totalSize - sum));
+            f.hits = sum;
+            ind.evaluated = true;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/ParityData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/ParityData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/ParityData.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity;
+import ec.gp.*;
+
+/* 
+ * ParityData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ParityData extends GPData
+    {
+    // return value -- should ALWAYS be either 1 or 0
+    public int x;
+
+    public void copyTo(final GPData gpd) 
+        { ((ParityData)gpd).x = x; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/adf.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/adf.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/adf.params	(revision 6152)
@@ -0,0 +1,365 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+# THIS IS A LONG FILE -- GO TO THE END IF YOU JUST
+# WANT TO CHANGE THE "N" IN "N"-PARITY
+
+# First, we're gonna change the number of trees in
+# the individual, to accommodate the ADFs
+# Each of our three trees uses a different tree constraints,
+# tc0, tc1, tc2
+
+pop.subpop.0.species.ind.numtrees = 3
+
+# "The result-producing branch" (the "third" tree in Koza-I p. 538)
+pop.subpop.0.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.0.tc = tc0
+# "ADF0 body" (the "first" tree in Koza-I p. 538)
+pop.subpop.0.species.ind.tree.1 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.1.tc = tc1
+# "ADF1 body" (the "second" tree in Koza-I p. 538)
+pop.subpop.0.species.ind.tree.2 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.2.tc = tc2
+
+
+
+# Now, let's define what tc0, tc1, and tc2 are.
+# Each has a different function set, f0, f1, and f2
+
+gp.tc.size = 3
+
+gp.tc.0 = ec.gp.GPTreeConstraints
+gp.tc.0.name = tc0
+gp.tc.0.fset = f0
+gp.tc.0.returns = nil
+gp.tc.0.init = ec.gp.koza.GrowBuilder
+gp.tc.0.init.growp = 0.5
+gp.tc.0.init.min = 2
+gp.tc.0.init.max = 6
+
+gp.tc.1 = ec.gp.GPTreeConstraints
+gp.tc.1.name = tc1
+gp.tc.1.fset = f1
+gp.tc.1.returns = nil
+gp.tc.1.init = ec.gp.koza.GrowBuilder
+gp.tc.1.init.growp = 0.5
+gp.tc.1.init.min = 2
+gp.tc.1.init.max = 6
+
+gp.tc.2 = ec.gp.GPTreeConstraints
+gp.tc.2.name = tc2
+gp.tc.2.fset = f2
+gp.tc.2.returns = nil
+gp.tc.2.init = ec.gp.koza.GrowBuilder
+gp.tc.2.init.growp = 0.5
+gp.tc.2.init.min = 2
+gp.tc.2.init.max = 6
+
+
+
+# Now we define the three function sets
+
+gp.fs.size = 3
+
+
+gp.fs.0.name = f0
+
+### The functions, carefully ordered :-)  (See below)
+gp.fs.0.func.0 = ec.app.parity.func.And
+gp.fs.0.func.0.nc = nc2
+gp.fs.0.func.1 = ec.app.parity.func.Or
+gp.fs.0.func.1.nc = nc2
+gp.fs.0.func.2 = ec.app.parity.func.Nand
+gp.fs.0.func.2.nc = nc2
+gp.fs.0.func.3 = ec.app.parity.func.Nor
+gp.fs.0.func.3.nc = nc2
+# ADF0 (2 arguments, tree 1)
+gp.fs.0.func.4 = ec.gp.ADF
+gp.fs.0.func.4.nc = nc2
+gp.fs.0.func.4.tree = 1
+gp.fs.0.func.4.name = ADF0
+
+# ADF1 (3 arguments, tree 2)
+gp.fs.0.func.5 = ec.gp.ADF
+gp.fs.0.func.5.nc = nc3
+gp.fs.0.func.5.tree = 2
+gp.fs.0.func.5.name = ADF1
+
+gp.fs.0.func.6 = ec.app.parity.func.D0
+gp.fs.0.func.6.nc = nc0
+gp.fs.0.func.7 = ec.app.parity.func.D1
+gp.fs.0.func.7.nc = nc0
+gp.fs.0.func.8 = ec.app.parity.func.D2
+gp.fs.0.func.8.nc = nc0
+gp.fs.0.func.9 = ec.app.parity.func.D3
+gp.fs.0.func.9.nc = nc0
+gp.fs.0.func.10 = ec.app.parity.func.D4
+gp.fs.0.func.10.nc = nc0
+gp.fs.0.func.11 = ec.app.parity.func.D5
+gp.fs.0.func.11.nc = nc0
+gp.fs.0.func.12 = ec.app.parity.func.D6
+gp.fs.0.func.12.nc = nc0
+gp.fs.0.func.13 = ec.app.parity.func.D7
+gp.fs.0.func.13.nc = nc0
+gp.fs.0.func.14 = ec.app.parity.func.D8
+gp.fs.0.func.14.nc = nc0
+gp.fs.0.func.15 = ec.app.parity.func.D9
+gp.fs.0.func.16.nc = nc0
+gp.fs.0.func.16 = ec.app.parity.func.D10
+gp.fs.0.func.16.nc = nc0
+gp.fs.0.func.17 = ec.app.parity.func.D11
+gp.fs.0.func.17.nc = nc0
+gp.fs.0.func.18 = ec.app.parity.func.D12
+gp.fs.0.func.18.nc = nc0
+gp.fs.0.func.19 = ec.app.parity.func.D13
+gp.fs.0.func.19.nc = nc0
+gp.fs.0.func.20 = ec.app.parity.func.D14
+gp.fs.0.func.20.nc = nc0
+gp.fs.0.func.21 = ec.app.parity.func.D15
+gp.fs.0.func.21.nc = nc0
+gp.fs.0.func.22 = ec.app.parity.func.D16
+gp.fs.0.func.22.nc = nc0
+gp.fs.0.func.23 = ec.app.parity.func.D17
+gp.fs.0.func.23.nc = nc0
+gp.fs.0.func.24 = ec.app.parity.func.D18
+gp.fs.0.func.24.nc = nc0
+gp.fs.0.func.25 = ec.app.parity.func.D19
+gp.fs.0.func.25.nc = nc0
+gp.fs.0.func.26 = ec.app.parity.func.D20
+gp.fs.0.func.26.nc = nc0
+gp.fs.0.func.27 = ec.app.parity.func.D21
+gp.fs.0.func.27.nc = nc0
+gp.fs.0.func.28 = ec.app.parity.func.D22
+gp.fs.0.func.28.nc = nc0
+gp.fs.0.func.29 = ec.app.parity.func.D23
+gp.fs.0.func.29.nc = nc0
+gp.fs.0.func.30 = ec.app.parity.func.D24
+gp.fs.0.func.30.nc = nc0
+gp.fs.0.func.31 = ec.app.parity.func.D25
+gp.fs.0.func.31.nc = nc0
+gp.fs.0.func.32 = ec.app.parity.func.D26
+gp.fs.0.func.32.nc = nc0
+gp.fs.0.func.33 = ec.app.parity.func.D27
+gp.fs.0.func.33.nc = nc0
+gp.fs.0.func.34 = ec.app.parity.func.D28
+gp.fs.0.func.34.nc = nc0
+gp.fs.0.func.35 = ec.app.parity.func.D29
+gp.fs.0.func.35.nc = nc0
+gp.fs.0.func.36 = ec.app.parity.func.D30
+gp.fs.0.func.36.nc = nc0
+gp.fs.0.func.37 = ec.app.parity.func.D31
+gp.fs.0.func.37.nc = nc0
+
+
+
+# ADF1's tree
+gp.fs.1.name = f1
+gp.fs.1 = ec.gp.GPFunctionSet
+
+### The functions, carefully ordered :-)  (See below)
+gp.fs.1.func.0 = ec.app.parity.func.And
+gp.fs.1.func.0.nc = nc2
+gp.fs.1.func.1 = ec.app.parity.func.Or
+gp.fs.1.func.1.nc = nc2
+gp.fs.1.func.2 = ec.app.parity.func.Nand
+gp.fs.1.func.2.nc = nc2
+gp.fs.1.func.3 = ec.app.parity.func.Nor
+gp.fs.1.func.3.nc = nc2
+# ARG0
+gp.fs.1.func.4 = ec.gp.ADFArgument
+gp.fs.1.func.4.nc = nc0
+gp.fs.1.func.4.arg = 0
+gp.fs.1.func.4.name = ARG0
+
+# ARG1
+gp.fs.1.func.5 = ec.gp.ADFArgument
+gp.fs.1.func.5.nc = nc0
+gp.fs.1.func.5.arg = 1
+gp.fs.1.func.5.name = ARG1
+
+gp.fs.1.func.6 = ec.app.parity.func.D0
+gp.fs.1.func.6.nc = nc0
+gp.fs.1.func.7 = ec.app.parity.func.D1
+gp.fs.1.func.7.nc = nc0
+gp.fs.1.func.8 = ec.app.parity.func.D2
+gp.fs.1.func.8.nc = nc0
+gp.fs.1.func.9 = ec.app.parity.func.D3
+gp.fs.1.func.9.nc = nc0
+gp.fs.1.func.10 = ec.app.parity.func.D4
+gp.fs.1.func.10.nc = nc0
+gp.fs.1.func.11 = ec.app.parity.func.D5
+gp.fs.1.func.11.nc = nc0
+gp.fs.1.func.12 = ec.app.parity.func.D6
+gp.fs.1.func.12.nc = nc0
+gp.fs.1.func.13 = ec.app.parity.func.D7
+gp.fs.1.func.13.nc = nc0
+gp.fs.1.func.14 = ec.app.parity.func.D8
+gp.fs.1.func.14.nc = nc0
+gp.fs.1.func.15 = ec.app.parity.func.D9
+gp.fs.1.func.16.nc = nc0
+gp.fs.1.func.16 = ec.app.parity.func.D10
+gp.fs.1.func.16.nc = nc0
+gp.fs.1.func.17 = ec.app.parity.func.D11
+gp.fs.1.func.17.nc = nc0
+gp.fs.1.func.18 = ec.app.parity.func.D12
+gp.fs.1.func.18.nc = nc0
+gp.fs.1.func.19 = ec.app.parity.func.D13
+gp.fs.1.func.19.nc = nc0
+gp.fs.1.func.20 = ec.app.parity.func.D14
+gp.fs.1.func.20.nc = nc0
+gp.fs.1.func.21 = ec.app.parity.func.D15
+gp.fs.1.func.21.nc = nc0
+gp.fs.1.func.22 = ec.app.parity.func.D16
+gp.fs.1.func.22.nc = nc0
+gp.fs.1.func.23 = ec.app.parity.func.D17
+gp.fs.1.func.23.nc = nc0
+gp.fs.1.func.24 = ec.app.parity.func.D18
+gp.fs.1.func.24.nc = nc0
+gp.fs.1.func.25 = ec.app.parity.func.D19
+gp.fs.1.func.25.nc = nc0
+gp.fs.1.func.26 = ec.app.parity.func.D20
+gp.fs.1.func.26.nc = nc0
+gp.fs.1.func.27 = ec.app.parity.func.D21
+gp.fs.1.func.27.nc = nc0
+gp.fs.1.func.28 = ec.app.parity.func.D22
+gp.fs.1.func.28.nc = nc0
+gp.fs.1.func.29 = ec.app.parity.func.D23
+gp.fs.1.func.29.nc = nc0
+gp.fs.1.func.30 = ec.app.parity.func.D24
+gp.fs.1.func.30.nc = nc0
+gp.fs.1.func.31 = ec.app.parity.func.D25
+gp.fs.1.func.31.nc = nc0
+gp.fs.1.func.32 = ec.app.parity.func.D26
+gp.fs.1.func.32.nc = nc0
+gp.fs.1.func.33 = ec.app.parity.func.D27
+gp.fs.1.func.33.nc = nc0
+gp.fs.1.func.34 = ec.app.parity.func.D28
+gp.fs.1.func.34.nc = nc0
+gp.fs.1.func.35 = ec.app.parity.func.D29
+gp.fs.1.func.35.nc = nc0
+gp.fs.1.func.36 = ec.app.parity.func.D30
+gp.fs.1.func.36.nc = nc0
+gp.fs.1.func.37 = ec.app.parity.func.D31
+gp.fs.1.func.37.nc = nc0
+
+
+
+
+
+## ADF0's tree
+gp.fs.2.name = f2
+gp.fs.2 = ec.gp.GPFunctionSet
+
+### The functions, carefully ordered :-)  (See below)
+gp.fs.2.func.0 = ec.app.parity.func.And
+gp.fs.2.func.0.nc = nc2
+gp.fs.2.func.1 = ec.app.parity.func.Or
+gp.fs.2.func.1.nc = nc2
+gp.fs.2.func.2 = ec.app.parity.func.Nand
+gp.fs.2.func.2.nc = nc2
+gp.fs.2.func.3 = ec.app.parity.func.Nor
+gp.fs.2.func.3.nc = nc2
+# ARG0
+gp.fs.2.func.4 = ec.gp.ADFArgument
+gp.fs.2.func.4.nc = nc0
+gp.fs.2.func.4.arg = 0
+gp.fs.2.func.4.name = ARG0
+
+# ARG1
+gp.fs.2.func.5 = ec.gp.ADFArgument
+gp.fs.2.func.5.nc = nc0
+gp.fs.2.func.5.arg = 1
+gp.fs.2.func.5.name = ARG1
+
+# ARG2
+gp.fs.2.func.6 = ec.gp.ADFArgument
+gp.fs.2.func.6.nc = nc0
+gp.fs.2.func.6.arg = 2
+gp.fs.2.func.6.name = ARG2
+
+gp.fs.2.func.7 = ec.app.parity.func.D0
+gp.fs.2.func.7.nc = nc0
+gp.fs.2.func.8 = ec.app.parity.func.D1
+gp.fs.2.func.8.nc = nc0
+gp.fs.2.func.9 = ec.app.parity.func.D2
+gp.fs.2.func.9.nc = nc0
+gp.fs.2.func.10 = ec.app.parity.func.D3
+gp.fs.2.func.10.nc = nc0
+gp.fs.2.func.11 = ec.app.parity.func.D4
+gp.fs.2.func.11.nc = nc0
+gp.fs.2.func.12 = ec.app.parity.func.D5
+gp.fs.2.func.12.nc = nc0
+gp.fs.2.func.13 = ec.app.parity.func.D6
+gp.fs.2.func.13.nc = nc0
+gp.fs.2.func.14 = ec.app.parity.func.D7
+gp.fs.2.func.14.nc = nc0
+gp.fs.2.func.15 = ec.app.parity.func.D8
+gp.fs.2.func.16.nc = nc0
+gp.fs.2.func.16 = ec.app.parity.func.D9
+gp.fs.2.func.16.nc = nc0
+gp.fs.2.func.17 = ec.app.parity.func.D10
+gp.fs.2.func.17.nc = nc0
+gp.fs.2.func.18 = ec.app.parity.func.D11
+gp.fs.2.func.18.nc = nc0
+gp.fs.2.func.19 = ec.app.parity.func.D12
+gp.fs.2.func.19.nc = nc0
+gp.fs.2.func.20 = ec.app.parity.func.D13
+gp.fs.2.func.20.nc = nc0
+gp.fs.2.func.21 = ec.app.parity.func.D14
+gp.fs.2.func.21.nc = nc0
+gp.fs.2.func.22 = ec.app.parity.func.D15
+gp.fs.2.func.22.nc = nc0
+gp.fs.2.func.23 = ec.app.parity.func.D16
+gp.fs.2.func.23.nc = nc0
+gp.fs.2.func.24 = ec.app.parity.func.D17
+gp.fs.2.func.24.nc = nc0
+gp.fs.2.func.25 = ec.app.parity.func.D18
+gp.fs.2.func.25.nc = nc0
+gp.fs.2.func.26 = ec.app.parity.func.D19
+gp.fs.2.func.26.nc = nc0
+gp.fs.2.func.27 = ec.app.parity.func.D20
+gp.fs.2.func.27.nc = nc0
+gp.fs.2.func.28 = ec.app.parity.func.D21
+gp.fs.2.func.28.nc = nc0
+gp.fs.2.func.29 = ec.app.parity.func.D22
+gp.fs.2.func.29.nc = nc0
+gp.fs.2.func.30 = ec.app.parity.func.D23
+gp.fs.2.func.30.nc = nc0
+gp.fs.2.func.31 = ec.app.parity.func.D24
+gp.fs.2.func.31.nc = nc0
+gp.fs.2.func.32 = ec.app.parity.func.D25
+gp.fs.2.func.32.nc = nc0
+gp.fs.2.func.33 = ec.app.parity.func.D26
+gp.fs.2.func.33.nc = nc0
+gp.fs.2.func.34 = ec.app.parity.func.D27
+gp.fs.2.func.34.nc = nc0
+gp.fs.2.func.35 = ec.app.parity.func.D28
+gp.fs.2.func.35.nc = nc0
+gp.fs.2.func.36 = ec.app.parity.func.D29
+gp.fs.2.func.36.nc = nc0
+gp.fs.2.func.37 = ec.app.parity.func.D30
+gp.fs.2.func.37.nc = nc0
+gp.fs.2.func.38 = ec.app.parity.func.D31
+gp.fs.2.func.38.nc = nc0
+
+
+# We specify our problem here
+#
+
+eval.problem = ec.app.parity.Parity
+eval.problem.data = ec.app.parity.ParityData
+
+
+# Here we determine what kind of Parity we're doing:
+eval.problem.bits = 4 
+eval.problem.even = true
+
+# this value must always be set to *6* more than eval.problem.bits
+gp.fs.0.size = 10 
+# this value must always be set to *6* more than eval.problem.bits
+gp.fs.1.size = 10
+# this value must always be set to *7* more than eval.problem.bits
+gp.fs.2.size = 11
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/And.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/And.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/And.java	(revision 6152)
@@ -0,0 +1,59 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * And.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class And extends GPNode
+    {
+    public String toString() { return "and"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // shortcutting AND
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (((ParityData)input).x == 1 )  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+        // else return the first item (already there)
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D0.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D0 extends GPNode
+    {
+    public String toString() { return "D0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 0 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D1.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D1 extends GPNode
+    {
+    public String toString() { return "D1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 1 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D10.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D10.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D10.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D10.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D10 extends GPNode
+    {
+    public String toString() { return "D10"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 10 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D11.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D11.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D11.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D11.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D11 extends GPNode
+    {
+    public String toString() { return "D11"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 11 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D12.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D12.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D12.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D12.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D12 extends GPNode
+    {
+    public String toString() { return "D12"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 12 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D13.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D13.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D13.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D13.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D13 extends GPNode
+    {
+    public String toString() { return "D13"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 13 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D14.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D14.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D14.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D14.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D14 extends GPNode
+    {
+    public String toString() { return "D14"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 14 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D15.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D15.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D15.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D15.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D15 extends GPNode
+    {
+    public String toString() { return "D15"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 15 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D16.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D16.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D16.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D16.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D16 extends GPNode
+    {
+    public String toString() { return "D16"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 16 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D17.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D17.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D17.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D17.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D17 extends GPNode
+    {
+    public String toString() { return "D17"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 17 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D18.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D18.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D18.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D18.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D18 extends GPNode
+    {
+    public String toString() { return "D18"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 18 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D19.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D19.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D19.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D19.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D19 extends GPNode
+    {
+    public String toString() { return "D19"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 19 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D2.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D2.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D2 extends GPNode
+    {
+    public String toString() { return "D2"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 2 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D20.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D20.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D20.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D20.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D20 extends GPNode
+    {
+    public String toString() { return "D20"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 20 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D21.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D21.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D21.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D21.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D21 extends GPNode
+    {
+    public String toString() { return "D21"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 21 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D22.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D22.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D22.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D22.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D22 extends GPNode
+    {
+    public String toString() { return "D22"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 22 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D23.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D23.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D23.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D23.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D23 extends GPNode
+    {
+    public String toString() { return "D23"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 23 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D24.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D24.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D24.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D24.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D24 extends GPNode
+    {
+    public String toString() { return "D24"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 24 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D25.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D25.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D25.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D25.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D25 extends GPNode
+    {
+    public String toString() { return "D25"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 25 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D26.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D26.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D26.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D26.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D26 extends GPNode
+    {
+    public String toString() { return "D26"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 26 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D27.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D27.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D27.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D27.java
+ * 
+ * Created: Wed Nov  3 18:27:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D27 extends GPNode
+    {
+    public String toString() { return "D27"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 27 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D28.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D28.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D28.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D28.java
+ * 
+ * Created: Wed Nov  3 18:28:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D28 extends GPNode
+    {
+    public String toString() { return "D28"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 28 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D29.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D29.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D29.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D29.java
+ * 
+ * Created: Wed Nov  3 18:29:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D29 extends GPNode
+    {
+    public String toString() { return "D29"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 29 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D3.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D3.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D3.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D3.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D3 extends GPNode
+    {
+    public String toString() { return "D3"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 3 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D30.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D30.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D30.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D30.java
+ * 
+ * Created: Wed Nov  3 18:30:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D30 extends GPNode
+    {
+    public String toString() { return "D30"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 30 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D31.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D31.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D31.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D31.java
+ * 
+ * Created: Wed Nov  3 18:31:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D31 extends GPNode
+    {
+    public String toString() { return "D31"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 31 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D4.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D4.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D4.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D4.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D4 extends GPNode
+    {
+    public String toString() { return "D4"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 4 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D5.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D5.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D5.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D5.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D5 extends GPNode
+    {
+    public String toString() { return "D5"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 5 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D6.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D6.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D6.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D6.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D6 extends GPNode
+    {
+    public String toString() { return "D6"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 6 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D7.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D7.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D7.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D7.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D7 extends GPNode
+    {
+    public String toString() { return "D7"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 7 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D8.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D8.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D8.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D8.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D8 extends GPNode
+    {
+    public String toString() { return "D8"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 8 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D9.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D9.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/D9.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * D9.java
+ * 
+ * Created: Wed Nov  3 18:26:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class D9 extends GPNode
+    {
+    public String toString() { return "D9"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ((ParityData)input).x = 
+            ((((Parity)problem).bits >>> 9 ) & 1);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Nand.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Nand.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Nand.java	(revision 6152)
@@ -0,0 +1,62 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Nand.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Nand extends GPNode
+    {
+    public String toString() { return "nand"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ParityData d = ((ParityData)input);
+        // shortcutting NAND
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (d.x == 1)  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+
+        // invert
+        d.x ^= 1;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Nor.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Nor.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Nor.java	(revision 6152)
@@ -0,0 +1,62 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Nor.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Nor extends GPNode
+    {
+    public String toString() { return "nor"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        ParityData d = ((ParityData)input);
+        // shortcutting NOR
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (d.x == 0 )  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+
+        // invert
+        d.x ^= 1;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Or.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Or.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/func/Or.java	(revision 6152)
@@ -0,0 +1,59 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.parity.func;
+import ec.*;
+import ec.app.parity.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Or.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Or extends GPNode
+    {
+    public String toString() { return "or"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // shortcutting OR
+        children[0].eval(state,thread,input,stack,individual,problem);
+
+        if (((ParityData)input).x == 0 )  // return the second item
+            children[1].eval(state,thread,input,stack,individual,problem);
+        // else return the first item (already there)
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/params-README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/params-README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/params-README	(revision 6152)
@@ -0,0 +1,19 @@
+This defines the [even/odd]-[2...31]-parity problem family, with
+or without adfs.  Because there are so many possible functions
+necessary to do, for example, even-31-parity (!), the parameter
+files are big and hairy.  But here's what you need to know to change
+the values.
+
+The parameter which determines even/odd is:
+
+	eval.problem.even
+
+The parameter which determines the value from 2...31 is:
+
+	eval.problem.bits
+
+However, after you change eval.problem bits, you need to
+change the gp.fs.0.size (and for adfs, the gp.fs.1.size
+and gp.fs.2.size) parameter immediately after it as it
+describes.  This determines the function set used.
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/parity/parity.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/parity/parity.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/parity/parity.params	(revision 6152)
@@ -0,0 +1,107 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+
+### The functions, carefully ordered :-)  (See below)
+
+gp.fs.0.func.0 = ec.app.parity.func.And
+gp.fs.0.func.0.nc = nc2
+gp.fs.0.func.1 = ec.app.parity.func.Or
+gp.fs.0.func.1.nc = nc2
+gp.fs.0.func.2 = ec.app.parity.func.Nand
+gp.fs.0.func.2.nc = nc2
+gp.fs.0.func.3 = ec.app.parity.func.Nor
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.parity.func.D0
+gp.fs.0.func.4.nc = nc0
+gp.fs.0.func.5 = ec.app.parity.func.D1
+gp.fs.0.func.5.nc = nc0
+gp.fs.0.func.6 = ec.app.parity.func.D2
+gp.fs.0.func.6.nc = nc0
+gp.fs.0.func.7 = ec.app.parity.func.D3
+gp.fs.0.func.7.nc = nc0
+gp.fs.0.func.8 = ec.app.parity.func.D4
+gp.fs.0.func.8.nc = nc0
+gp.fs.0.func.9 = ec.app.parity.func.D5
+gp.fs.0.func.9.nc = nc0
+gp.fs.0.func.10 = ec.app.parity.func.D6
+gp.fs.0.func.10.nc = nc0
+gp.fs.0.func.11 = ec.app.parity.func.D7
+gp.fs.0.func.11.nc = nc0
+gp.fs.0.func.12 = ec.app.parity.func.D8
+gp.fs.0.func.12.nc = nc0
+gp.fs.0.func.13 = ec.app.parity.func.D9
+gp.fs.0.func.13.nc = nc0
+gp.fs.0.func.14 = ec.app.parity.func.D10
+gp.fs.0.func.14.nc = nc0
+gp.fs.0.func.15 = ec.app.parity.func.D11
+gp.fs.0.func.15.nc = nc0
+gp.fs.0.func.16 = ec.app.parity.func.D12
+gp.fs.0.func.16.nc = nc0
+gp.fs.0.func.17 = ec.app.parity.func.D13
+gp.fs.0.func.17.nc = nc0
+gp.fs.0.func.18 = ec.app.parity.func.D14
+gp.fs.0.func.18.nc = nc0
+gp.fs.0.func.19 = ec.app.parity.func.D15
+gp.fs.0.func.19.nc = nc0
+gp.fs.0.func.20 = ec.app.parity.func.D16
+gp.fs.0.func.20.nc = nc0
+gp.fs.0.func.21 = ec.app.parity.func.D17
+gp.fs.0.func.21.nc = nc0
+gp.fs.0.func.22 = ec.app.parity.func.D18
+gp.fs.0.func.22.nc = nc0
+gp.fs.0.func.23 = ec.app.parity.func.D19
+gp.fs.0.func.23.nc = nc0
+gp.fs.0.func.24 = ec.app.parity.func.D20
+gp.fs.0.func.24.nc = nc0
+gp.fs.0.func.25 = ec.app.parity.func.D21
+gp.fs.0.func.25.nc = nc0
+gp.fs.0.func.26 = ec.app.parity.func.D22
+gp.fs.0.func.26.nc = nc0
+gp.fs.0.func.27 = ec.app.parity.func.D23
+gp.fs.0.func.27.nc = nc0
+gp.fs.0.func.28 = ec.app.parity.func.D24
+gp.fs.0.func.28.nc = nc0
+gp.fs.0.func.29 = ec.app.parity.func.D25
+gp.fs.0.func.29.nc = nc0
+gp.fs.0.func.30 = ec.app.parity.func.D26
+gp.fs.0.func.30.nc = nc0
+gp.fs.0.func.31 = ec.app.parity.func.D27
+gp.fs.0.func.31.nc = nc0
+gp.fs.0.func.32 = ec.app.parity.func.D28
+gp.fs.0.func.32.nc = nc0
+gp.fs.0.func.33 = ec.app.parity.func.D29
+gp.fs.0.func.33.nc = nc0
+gp.fs.0.func.34 = ec.app.parity.func.D30
+gp.fs.0.func.34.nc = nc0
+gp.fs.0.func.35 = ec.app.parity.func.D31
+gp.fs.0.func.35.nc = nc0
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.parity.Parity
+eval.problem.data = ec.app.parity.ParityData
+
+
+# Here we determine what kind of Parity we're doing:
+eval.problem.bits = 12
+eval.problem.even = true
+
+# this value must always be set to *4* more than eval.problem.bits
+gp.fs.0.size = 16
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Quintic.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Quintic.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Quintic.java	(revision 6152)
@@ -0,0 +1,28 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression;
+
+/* 
+ * Quintic.java
+ * 
+ * Created: Fri Nov 30 21:38:13 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * Quintic implements a Symbolic Regression problem.
+ *
+ * <p>The equation to be regressed is y = x^5 - 2x^3 + x, {x in [-1,1]}
+ * <p>This equation was introduced in J. R. Koza, GP II, 1994.
+ *
+ */
+public class Quintic extends Regression
+    {
+    public double func(double x)
+        { return x*x*x*x*x - 2.0*x*x*x + x; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Regression.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Regression.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Regression.java	(revision 6152)
@@ -0,0 +1,157 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * Regression.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Regression implements the Koza (quartic) Symbolic Regression problem.
+ *
+ * <p>The equation to be regressed is y = x^4 + x^3 + x^2 + x, {x in [-1,1]}
+ * <p>This equation was introduced in J. R. Koza, GP II, 1994.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.regression.RegressionData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the Regression problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>(the size of the training set)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Regression extends GPProblem implements SimpleProblemForm
+    {
+    public static final String P_SIZE = "size";
+
+    public double currentValue;
+    public int trainingSetSize;
+    
+    // these are read-only during evaluation-time, so
+    // they can be just light-cloned and not deep cloned.
+    // cool, huh?
+    
+    public double inputs[];
+    public double outputs[];
+
+    // we'll need to deep clone this one though.
+    public RegressionData input;
+
+    public double func(double x)
+        { return x*x*x*x + x*x*x + x*x + x; }
+
+    public Object clone()
+        {
+        // don't bother copying the inputs and outputs; they're read-only :-)
+        // don't bother copying the currentValue; it's transitory
+        // but we need to copy our regression data
+        Regression myobj = (Regression) (super.clone());
+
+        myobj.input = (RegressionData)(input.clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        trainingSetSize = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (trainingSetSize<1) state.output.fatal("Training Set Size must be an integer greater than 0", base.push(P_SIZE)); 
+
+        // Compute our inputs so they can be copied with clone later
+        
+        inputs = new double[trainingSetSize];
+        outputs = new double[trainingSetSize];
+        
+        for(int x=0;x<trainingSetSize;x++)
+            {
+            inputs[x] = state.random[0].nextDouble() * 2.0 - 1.0;
+            outputs[x] = func(inputs[x]);
+            state.output.message("{" + inputs[x] + "," + outputs[x] + "},");
+            }
+
+        // set up our input -- don't want to use the default base, it's unsafe
+        input = (RegressionData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA), null, RegressionData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            int hits = 0;
+            double sum = 0.0;
+            double result;
+            for (int y=0;y<trainingSetSize;y++)
+                {
+                currentValue = inputs[y];
+                ((GPIndividual)ind).trees[0].child.eval(
+                    state,threadnum,input,stack,((GPIndividual)ind),this);
+
+                // It's possible to get NaN because cos(infinity) and
+                // sin(infinity) are undefined (hence cos(exp(3000)) zings ya!)
+                // So since NaN is NOT =,<,>,etc. any other number, including
+                // NaN, we're CAREFULLY wording our cutoff to include NaN.
+                // Interesting that this has never been reported before to
+                // my knowledge.
+
+                final double HIT_LEVEL = 0.01;
+                final double PROBABLY_ZERO = 1.11E-15;
+                final double BIG_NUMBER = 1.0e15;  // the same as lilgp uses
+
+                result = Math.abs(outputs[y] - input.x);
+
+                if (! (result < BIG_NUMBER ) )   // *NOT* (input.x >= BIG_NUMBER)
+                    result = BIG_NUMBER;
+
+                // very slight math errors can creep in when evaluating
+                // two equivalent by differently-ordered functions, like
+                // x * (x*x*x + x*x)  vs. x*x*x*x + x*x
+
+                else if (result<PROBABLY_ZERO)  // slightly off
+                    result = 0.0;
+                    
+                if (result <= HIT_LEVEL) hits++;  // whatever!
+
+                sum += result;              }
+                
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)sum);
+            f.hits = hits;
+            ind.evaluated = true;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/RegressionData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/RegressionData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/RegressionData.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression;
+import ec.gp.*;
+
+/* 
+ * RegressionData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class RegressionData extends GPData
+    {
+    // return value
+    public double x;
+
+    public void copyTo(final GPData gpd) 
+        { ((RegressionData)gpd).x = x; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Sextic.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Sextic.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/Sextic.java	(revision 6152)
@@ -0,0 +1,28 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression;
+
+/* 
+ * Sextic.java
+ * 
+ * Created: Fri Nov 30 21:38:13 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * Sextic implements a Symbolic Regression problem.
+ *
+ * <p>The equation to be regressed is y = x^6 - 2x^4 + x^2, {x in [-1,1]}
+ * <p>This equation was introduced in J. R. Koza, GP II, 1994.
+ *
+ */
+public class Sextic extends Regression
+    {
+    public double func(double x)
+        { return x*x*x*x*x*x - 2.0*x*x*x*x + x*x; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/convertToMathematica.lisp
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/convertToMathematica.lisp	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/convertToMathematica.lisp	(revision 6152)
@@ -0,0 +1,38 @@
+;;;
+;;; CLTL2 lisp script, prints out a Mathematica equivalent to a GP tree,
+;;; for testing purposes (Show[f[x],{x,-1,1} is useful)
+;;;
+
+(defun conv (exp)
+  (cond 
+   ((not (listp exp)) "x")
+   ((equal (first exp) '+)
+    (concatenate 'string "Plus[" (conv (second exp)) "," (conv (third exp)) "]"))
+   ((equal (first exp) '-) 
+    (concatenate 'string "Subtract[" (conv (second exp)) "," (conv (third exp)) "]"))
+   ((equal (first exp) '*) 
+    (concatenate 'string "Times[" (conv (second exp)) "," (conv (third exp)) "]"))
+   ((equal (first exp) '%) 
+    (concatenate 'string "PDivide[" (conv (second exp)) "," (conv (third exp)) "]"))
+   ((equal (first exp) 'exp) 
+    (concatenate 'string "Exp[" (conv (second exp)) "]"))
+   ((equal (first exp) 'sin) 
+    (concatenate 'string "Sin[" (conv (second exp))"]"))
+   ((equal (first exp) 'cos) 
+    (concatenate 'string "Cos[" (conv (second exp))"]"))
+   ((equal (first exp) 'rlog) 
+    (concatenate 'string "RLog[" (conv (second exp))"]"))))
+
+(print "PDivide[x_,y_] := If[y==0,1,x/y]")
+(print "RLog[x_] := If[x==0,1,Log[x]]")
+
+(princ (conv '(+ (sin (sin (+ (+ x x) (+ x x)))) (% (rlog
+     (* (* x x) (exp x))) (% (* (exp x) (rlog
+     x)) (sin (+ x x)))))))
+
+(conv '(+ x x))
+(conv '(sin x))
+
+(conv ' (+ (sin x) (* (+ (* (* (cos (rlog x)) x)
+     (+ (* (cos (rlog x)) x) (% x (cos (rlog x)))))
+     (% x (% x x))) x)))
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/erc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/erc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/erc.params	(revision 6152)
@@ -0,0 +1,47 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+gp.fs.0.size = 10
+gp.fs.0.func.0 = ec.app.regression.func.X
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.regression.func.Add
+gp.fs.0.func.1.nc = nc2
+gp.fs.0.func.2 = ec.app.regression.func.Mul
+gp.fs.0.func.2.nc = nc2
+gp.fs.0.func.3 = ec.app.regression.func.Sub
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.regression.func.Div
+gp.fs.0.func.4.nc = nc2
+gp.fs.0.func.5 = ec.app.regression.func.Sin
+gp.fs.0.func.5.nc = nc1
+gp.fs.0.func.6 = ec.app.regression.func.Cos
+gp.fs.0.func.6.nc = nc1
+gp.fs.0.func.7 = ec.app.regression.func.Exp
+gp.fs.0.func.7.nc = nc1
+gp.fs.0.func.8 = ec.app.regression.func.Log
+gp.fs.0.func.8.nc = nc1
+# placed here at the bottom so noerc.params can skip it
+gp.fs.0.func.9 = ec.app.regression.func.RegERC
+gp.fs.0.func.9.nc = nc0
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.regression.Regression
+eval.problem.data = ec.app.regression.RegressionData
+
+# The size of our training set, by default, is 20
+eval.problem.size = 20
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Add.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Add.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Add.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Add.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Add extends GPNode
+    {
+    public String toString() { return "+"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result + rd.x;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Cos.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Cos.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Cos.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Cos.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Cos extends GPNode
+    {
+    public String toString() { return "cos"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        rd.x = /*Strict*/Math.cos(rd.x);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Div.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Div.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Div.java	(revision 6152)
@@ -0,0 +1,68 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Div.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Div extends GPNode
+    {
+    public String toString() { return "%"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+
+        // evaluate children[1] first to determine if the demoniator is 0
+        children[1].eval(state,thread,input,stack,individual,problem);
+        if (rd.x==0.0) 
+            // the answer is 1.0 since the denominator was 0.0
+            rd.x = 1.0;
+        else
+            {
+            double result;
+            result = rd.x;
+            
+            children[0].eval(state,thread,input,stack,individual,problem);
+            rd.x = rd.x / result;
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Exp.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Exp.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Exp.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Exp.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Exp extends GPNode
+    {
+    public String toString() { return "exp"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        rd.x = /*Strict*/Math.exp(rd.x);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Log.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Log.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Log.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Log.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Log extends GPNode
+    {
+    public String toString() { return "rlog"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        rd.x = (rd.x == 0.0 ? 0.0 : /*Strict*/Math.log(/*Strict*/Math.abs(rd.x)));
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Mul.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Mul.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Mul.java	(revision 6152)
@@ -0,0 +1,63 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Mul.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Mul extends GPNode
+    {
+    public String toString() { return "*"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        // can't shortcut because of NaN or +-Infinity
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result * rd.x;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/RegERC.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/RegERC.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/RegERC.java	(revision 6152)
@@ -0,0 +1,109 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+import java.io.*;
+
+
+/* 
+ * RegERC.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class RegERC extends ERC
+    {
+    public double value;
+
+    // making sure that we don't have any children is already
+    // done in ERC.checkConstraints(), so we don't need to implement that.
+
+    // this will produce numbers from [-1.0, 1.0), which is probably
+    // okay but you might want to modify it if you don't like seeing
+    // -1.0's occasionally showing up very rarely.
+    public void resetNode(final EvolutionState state, final int thread)
+        { value = state.random[thread].nextDouble() * 2 - 1.0; }
+
+    public int nodeHashCode()
+        {
+        // a reasonable hash code
+        return this.getClass().hashCode() + Float.floatToIntBits((float)value);
+        }
+
+    public boolean nodeEquals(final GPNode node)
+        {
+        // check first to see if we're the same kind of ERC -- 
+        // won't work for subclasses; in that case you'll need
+        // to change this to isAssignableTo(...)
+        if (this.getClass() != node.getClass()) return false;
+        // now check to see if the ERCs hold the same value
+        return (((RegERC)node).value == value);
+        }
+
+    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        value = dataInput.readDouble();
+        }
+
+    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeDouble(value);
+        }
+
+    public String encode()
+        { return Code.encode(value); }
+
+    public boolean decode(DecodeReturn dret)
+        {
+        // store the position and the string in case they
+        // get modified by Code.java
+        int pos = dret.pos;
+        String data = dret.data;
+
+        // decode
+        Code.decode(dret);
+
+        if (dret.type != DecodeReturn.T_DOUBLE) // uh oh!
+            {
+            // restore the position and the string; it was an error
+            dret.data = data;
+            dret.pos = pos;
+            return false;
+            }
+
+        // store the data
+        value = dret.d;
+        return true;
+        }
+
+    public String toStringForHumans()
+        { return "" + (float)value; }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+        rd.x = value;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Sin.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Sin.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Sin.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Sin.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Sin extends GPNode
+    {
+    public String toString() { return "sin"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=1)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        rd.x = /*Strict*/Math.sin(rd.x);
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Sub.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Sub.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/Sub.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Sub.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Sub extends GPNode
+    {
+    public String toString() { return "-"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        RegressionData rd = ((RegressionData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result - rd.x;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/X.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/X.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/func/X.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.regression.func;
+import ec.*;
+import ec.app.regression.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * X.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class X extends GPNode
+    {
+    public String toString() { return "x"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        RegressionData rd = ((RegressionData)(input));
+        rd.x = ((Regression)problem).currentValue;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/ge.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/ge.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/ge.params	(revision 6152)
@@ -0,0 +1,12 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/ge/ge.params
+parent.1 = erc.params
+
+ge.species.file.0 = regression.grammar
+eval.problem.problem = ec.app.regression.Regression
+eval.problem.problem.data = ec.app.regression.RegressionData
+eval.problem.problem.size = 20
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/noerc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/noerc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/noerc.params	(revision 6152)
@@ -0,0 +1,7 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ./erc.params
+
+gp.fs.0.size = 9
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/noerc2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/noerc2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/noerc2.params	(revision 6152)
@@ -0,0 +1,74 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+###### example params file, goes in ec/app/regression
+parent.0 = ./noerc.params
+
+# To require that the root of a tree be a given node, you
+# simply need to set up the typing so that that node is
+# the only node which is compatable with the tree's return
+# type.  The way to do this is to make not one but two
+# atomic types (in the example below, nil and root).  nil
+# is the default type used by our GP nodes.  root will be
+# the return type of the tree.  Then we create a set type
+# which is compatable with both of them called nil-and-root,
+# and set it up so the return type of our desired node
+# (in this case, 'div'), returns nil-and-root.  Thus 'div'
+# is legal to hang as root (and is the only such node), AND
+# 'div' is still perfectly compatable as a child of other
+# nodes as before.
+
+# The gotcha: many GP node builders require that for every
+# reachable type used by nodes in the function set there
+# must exist at least one terminal (and ideally one nonterminal)
+# in the function set which returns that type.  This is
+# because many GP node builder algorithms insist on being
+# able to emit a terminal whenever they so desire, regardless
+# of what the current type situation is where the terminal
+# has to be hung.  The notable exception to this is Uniform.
+
+# Ordinarily this would be a problem for us as we use
+# Ramped Half-and-Half as our builder, and it has this 
+# requirement.  However since we are telling Ramped Half-and-Half
+# to generate only trees of sizes 2 and up (NOT 1 and up), 
+# it will never attempt to select a terminal for the root
+# and this gotcha will not occur.  The issue would also come
+# up if we use tree mutation as an operator rather than solely
+# crossover.  But we're not doing that.
+
+# Okay, here we go.
+
+# Add an atomic type (root) and a set type
+# (nil-and-root) which is compatible with both
+# nil and root
+gp.type.a.size = 2
+gp.type.a.0.name = nil
+gp.type.a.1.name = root
+gp.type.s.size = 1
+gp.type.s.0.name = nil-and-root
+gp.type.s.0.size = 2
+gp.type.s.0.member.0 = nil
+gp.type.s.0.member.1 = root
+
+# make a new contraints form for div which returns
+# things of type nil-and-root.  This is compatable
+# with all elements that accept nil (which will be
+# all other functions), so div will still fit right in.
+gp.nc.size = 8
+gp.nc.7 = ec.gp.GPNodeConstraints
+gp.nc.7.name = nc-returning-nil-and-root
+gp.nc.7.returns = nil-and-root
+gp.nc.7.size = 2
+gp.nc.7.child.0 = nil
+gp.nc.7.child.1 = nil
+
+# redefine div to return things of type nil-and-root.
+gp.fs.0.func.4.nc = nc-returning-nil-and-root
+
+# define the tree so that it only accepts items that
+# are compatible with root.  div will be the only
+# such item.
+gp.tc.0.returns = root
+
+###### end example
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/quinticerc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/quinticerc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/quinticerc.params	(revision 6152)
@@ -0,0 +1,6 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = erc.params
+eval.problem = ec.app.regression.Quintic
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/quinticnoerc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/quinticnoerc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/quinticnoerc.params	(revision 6152)
@@ -0,0 +1,6 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = noerc.params
+eval.problem = ec.app.regression.Quintic
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/regression.grammar
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/regression.grammar	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/regression.grammar	(revision 6152)
@@ -0,0 +1,5 @@
+# grammar of the regression problem including ERCs
+<start> ::= <op>
+<op> ::= (+ <op><op>)|(-<op><op>) |(* <op> <op>) | (% <op> <op>) 
+<op>::=(sin <op>) | (cos <op>) | (exp <op>) | (rlog <op>)
+<op>::=(x) | (   ERC     )
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/sexticerc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/sexticerc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/sexticerc.params	(revision 6152)
@@ -0,0 +1,6 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = erc.params
+eval.problem = ec.app.regression.Sextic
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/sexticnoerc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/sexticnoerc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/sexticnoerc.params	(revision 6152)
@@ -0,0 +1,6 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = noerc.params
+eval.problem = ec.app.regression.Sextic
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/regression/steadynoerc.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/regression/steadynoerc.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/regression/steadynoerc.params	(revision 6152)
@@ -0,0 +1,70 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../steadystate/steadystate.params
+parent.1 = ./noerc.params
+
+breed.reproduce.source.0 = ec.steadystate.MyDoubleTournamentSelection
+gp.koza.xover.source.0 = ec.steadystate.MyDoubleTournamentSelection
+select.my-double-tournament.do-length-first = true
+select.my-double-tournament.size = 1.4
+select.my-double-tournament.size2 = 7
+
+# 0. By default, the "deselector" (the selection operator
+# responsible for determining who in the population will
+# die) is tournament selection of size 1 -- that is,
+# random selection.  Let's say you'd like it to be more 
+# aggressive, say, tournament selection of size 2, picking 
+# the worse individual.  You can do that like this:
+#
+# steady.deselector.0.size =    2
+#
+# Or much more aggressive:
+#
+# steady.deselector.0.size =    7
+#
+# You can change the deselector entirely but it needs
+# to be of SteadyStateBreedingSourceForm, and the most
+# obvous choice (the classic for Steady State GA's,
+# BestSelection set to pick-worst) is actually not of
+# this form because it's expensive to scan through the
+# whole population each time.
+
+# 1. By default, the steady-state evolution runs for some
+# number of *generations*, where a generation is defined
+# as the time in which N individuals are evaluated, where
+# N is the size of subpopulation 0.  The first generation
+# is of course special as all the individuals are
+# evaluated together.  Subsequent "generations" are just
+# however long it takes for N more individuals to be
+# evaluated.  You can change the run-length from being
+# based on generations to being based on number of
+# evaluations if you want something more precise.  To do
+# that you'd set:
+#
+# evaluations =         ...
+#
+# Which says how many evaluations you want.  Obviously
+# this must be larger than the initial population size...
+
+# 2. When you run in its current form, this parameter
+# file will cause the system to complain that you didn't
+# provide a SteadyStateStatistics object.  This is okay,
+# but you may not get the statistics you expect.  For
+# more information, see SteadyStateEvolutionState
+
+# statistics =          ...
+
+# 3. You want to specify whether or not to allow any
+# children to enter the population if they are identical
+# to some existing member of the population.  Disallowing
+# duplicates in this way is the traditional approach to
+# steady-state evolution.  At present, each time we 
+# need to make an individual, we try up to 100 times to
+# create one that's not a duplicate.  You can change
+# the number of times to retry (or set to 0 to not
+# retry) by changing this parameter:
+
+# steady.duplicate-retries =            ...
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sat/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sat/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sat/README	(revision 6152)
@@ -0,0 +1,15 @@
+The boolean satisfiability problem can have widly different levels of
+difficulty.  To that end, this directory contains three different
+problems.  All the problems are 3CNF, and were generated using the Mkcnf
+program from ftp://dimacs.rutgers.edu/pub/challenge/satisfiability/contributed/UCSC/instances/Cnfgen.tar.Z. 
+See the README file in that package for instructions on buliding and
+usage.
+
+The three problems included here have 10, 215, and 1000 clauses, and are
+known to be satisfiable.  So, the maximum fitness is 10, 215, and 1000. 
+All problems have 50 variables (so a genome length of 50). 
+
+Note that the problem file is assumed to be in DIMACS format.  See
+http://www.satlib.org/Benchmarks/SAT/satformat.ps for more information. 
+Mkcnf can generate arbitrary, satisfiable CNF formulas in DIMACS format. 
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sat/SAT.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sat/SAT.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sat/SAT.java	(revision 6152)
@@ -0,0 +1,121 @@
+package ec.app.sat; 
+
+import ec.*; 
+import ec.simple.*; 
+import ec.vector.*; 
+import ec.util.*; 
+import java.io.*; 
+import java.util.*; 
+
+/**
+   SAT implements the boolean satisfiability problem. 
+  
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>sat-filename</tt><br>
+   <font size=-1>String</td>
+   <td valign=top>(Filename containing boolean satisfiability formula in Dimacs CNF format)</td></tr>
+   </table>
+ 
+   @author Keith Sullivan
+   @version 1.0
+*/
+
+public class SAT extends Problem implements SimpleProblemForm 
+    { 
+        
+    public static final String P_FILENAME = "sat-filename"; 
+        
+    Clause formula[];
+        
+    public void setup(EvolutionState state, Parameter base) 
+        {
+        super.setup(state, base); 
+        String fileName = state.parameters.getString(base.push(P_FILENAME), null); 
+                
+        try 
+            { 
+            BufferedReader inFile = new BufferedReader(new FileReader(new File(fileName))); 
+            String line=""; 
+            int cnt=0;
+            boolean start = false; 
+            while ((line = inFile.readLine()) != null) 
+                { 
+                if (start) 
+                    { 
+                    formula[cnt++] = new Clause(line);
+                    continue; 
+                    }
+                                
+                if (line.startsWith("p")) 
+                    { 
+                    start = true;
+                    line.trim(); 
+                    int index = line.lastIndexOf(" "); 
+                    formula = new Clause[Integer.parseInt(line.substring(index+1))]; 
+                    }
+                }
+            inFile.close();
+            } 
+        catch (IOException e) 
+            { 
+            state.output.fatal("Error in SAT setup, while loading from file " + fileName +
+                "\nFrom parameter " + base.push(P_FILENAME) + "\nError:\n" + e);  
+            }
+        }
+        
+    /** 
+        Evalutes the individual using the MAXSAT fitness function.
+    */
+    public void evaluate(final EvolutionState state, final Individual ind, final int subpopulation, final int threadnum)
+        {
+        BitVectorIndividual ind2 = (BitVectorIndividual) ind; 
+        double fitness=0; 
+                
+        for (int i=0; i < formula.length; i++)                  
+            fitness += formula[i].eval(ind2); 
+                
+        ((SimpleFitness)(ind2.fitness)).setFitness( state, (float) fitness, false);
+        ind2.evaluated = true; 
+        }
+        
+        
+    /**
+       Private helper class holding a single clause in the boolean formula. Each clause 
+       is a disjunction of boolean variables (or their negation).
+    */
+    public class Clause 
+        { 
+                
+        int[] variables; 
+        public Clause(String c) 
+            {
+            StringTokenizer st = new StringTokenizer(c); 
+            variables = new int[st.countTokens()-1]; 
+            for (int i=0; i < variables.length; i++) 
+                {
+                variables[i] = Integer.parseInt(st.nextToken()); 
+                }
+            }
+                
+        /** 
+            Evaluates the individual with the clause.  Returns 1 is clase is satisfiabile, 0 otherwise.
+        */
+        public int eval(BitVectorIndividual ind)
+            {
+            boolean tmp; 
+            int x; 
+            for (int i=0; i < variables.length; i++) 
+                {                              
+                x = variables[i]; 
+                if (x < 0) 
+                    tmp = !ind.genome[-x-1]; 
+                else 
+                    tmp =  ind.genome[x-1]; 
+                                
+                if (tmp) return 1; 
+                }
+            return 0;
+            }
+        };      
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-10.cnf
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-10.cnf	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-10.cnf	(revision 6152)
@@ -0,0 +1,14 @@
+c mkcnf random cnf with seed 77141, max clause length 3
+c FORCED SATISFIABLE
+c 
+p cnf 50  10
+16  19  -30  0
+33  12  -40  0
+-12  -16  21  0
+-40  3  14  0
+6  -21  -27  0
+-50  -28  11  0
+26  36  -29  0
+9  38  14  0
+-49  6  37  0
+-23  45  33  0
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-1000.cnf
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-1000.cnf	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-1000.cnf	(revision 6152)
@@ -0,0 +1,1004 @@
+c mkcnf random cnf with seed 55651, max clause length 3
+c FORCED SATISFIABLE
+c 
+p cnf 50  1000
+24  31  -5  0
+16  -44  21  0
+30  -24  -32  0
+-19  -9  -44  0
+-32  -15  12  0
+-13  27  -3  0
+18  25  1  0
+5  -21  27  0
+-10  -33  -7  0
+-41  -39  31  0
+8  37  -14  0
+29  6  -47  0
+15  25  21  0
+-6  -5  -4  0
+31  3  -4  0
+-33  -18  7  0
+-28  21  -16  0
+7  17  2  0
+-48  2  -41  0
+-48  -13  -35  0
+-35  -19  49  0
+-43  34  38  0
+45  11  30  0
+-2  -8  23  0
+-2  37  3  0
+-24  -21  8  0
+32  14  -35  0
+30  -26  46  0
+-42  -21  -48  0
+8  37  5  0
+-5  -15  34  0
+36  21  -17  0
+-49  23  6  0
+13  21  12  0
+15  -34  40  0
+48  29  41  0
+28  16  -25  0
+-20  12  2  0
+19  -39  -49  0
+-14  48  41  0
+-50  40  -19  0
+49  34  4  0
+-18  -4  -29  0
+-5  24  -28  0
+31  47  40  0
+50  -34  -26  0
+-14  6  45  0
+-17  -38  46  0
+-17  27  34  0
+-45  13  -11  0
+-40  -37  46  0
+40  -45  3  0
+24  35  13  0
+-26  -10  -32  0
+12  37  18  0
+21  -19  50  0
+1  8  2  0
+-33  -40  -27  0
+-15  1  -48  0
+1  -20  -12  0
+-50  -5  11  0
+45  -43  -22  0
+12  -15  28  0
+-40  -2  23  0
+43  3  27  0
+-32  3  22  0
+11  -20  -34  0
+23  40  -24  0
+9  12  41  0
+-19  -2  36  0
+20  28  37  0
+44  42  -39  0
+-2  -35  5  0
+-35  -3  -10  0
+37  11  26  0
+-40  7  -20  0
+-38  -46  7  0
+28  27  -40  0
+-28  15  -5  0
+48  -45  -49  0
+-23  42  25  0
+11  -42  38  0
+-3  42  46  0
+-41  -19  -33  0
+20  33  -26  0
+-49  -40  12  0
+-36  -7  9  0
+43  -39  -30  0
+34  3  24  0
+-4  31  6  0
+-3  39  -31  0
+43  46  -39  0
+-31  -9  30  0
+32  -7  -28  0
+14  -31  29  0
+-37  15  -32  0
+27  9  -40  0
+-14  -5  -3  0
+2  24  37  0
+-39  -37  -21  0
+17  43  -8  0
+-12  30  -20  0
+13  -21  -7  0
+-23  -6  -36  0
+-7  1  -21  0
+8  27  18  0
+-35  -44  -40  0
+14  -12  25  0
+30  21  34  0
+11  24  -1  0
+-48  2  -31  0
+-1  42  37  0
+18  -38  -12  0
+25  8  3  0
+-42  12  43  0
+14  -32  -9  0
+42  44  50  0
+28  -7  -20  0
+-46  -16  40  0
+31  -4  44  0
+34  1  -16  0
+-46  -26  -33  0
+33  -18  -40  0
+19  47  43  0
+41  -27  -30  0
+-40  -43  -8  0
+33  -6  -40  0
+-16  49  35  0
+24  49  -41  0
+-43  -23  26  0
+20  11  -5  0
+26  14  37  0
+49  -23  -34  0
+28  25  -47  0
+9  -26  2  0
+-43  -5  34  0
+15  24  -12  0
+39  -31  -45  0
+47  -15  -2  0
+36  -39  13  0
+-39  -11  9  0
+30  -6  -4  0
+41  24  25  0
+50  20  -32  0
+43  -12  9  0
+24  34  35  0
+46  -11  -47  0
+26  -6  4  0
+39  -20  25  0
+-45  33  29  0
+-31  2  50  0
+1  -31  18  0
+44  -49  -41  0
+-2  -6  29  0
+-16  -26  38  0
+19  11  42  0
+-8  2  -33  0
+-20  50  26  0
+-14  -7  -25  0
+-9  48  -30  0
+-25  40  28  0
+39  16  17  0
+9  -26  19  0
+10  -9  -18  0
+5  -1  -30  0
+37  11  -1  0
+-25  4  27  0
+17  9  49  0
+-16  41  -27  0
+-18  -23  -20  0
+47  -21  -23  0
+-50  26  49  0
+-6  36  -35  0
+-20  38  -11  0
+38  14  26  0
+35  -4  -33  0
+-3  35  11  0
+43  3  -45  0
+43  3  -18  0
+40  -49  32  0
+1  33  2  0
+-47  40  15  0
+-14  42  37  0
+29  44  -27  0
+10  -37  28  0
+2  -28  -16  0
+22  -35  -10  0
+-24  -19  16  0
+-18  -44  3  0
+-32  33  21  0
+3  29  19  0
+27  26  30  0
+-15  38  42  0
+40  -24  17  0
+-47  44  -33  0
+8  44  37  0
+-16  22  -48  0
+43  -46  -40  0
+19  -33  32  0
+-18  -40  13  0
+8  6  10  0
+-46  -48  -4  0
+-30  36  -47  0
+5  33  -45  0
+17  -23  47  0
+-23  -34  5  0
+-35  -14  38  0
+48  38  -26  0
+-24  -35  -48  0
+20  -38  -17  0
+-33  -8  -13  0
+30  38  39  0
+-44  2  -39  0
+27  -1  10  0
+-29  -34  47  0
+21  -44  -31  0
+6  -28  46  0
+-6  24  46  0
+10  40  21  0
+39  -27  -1  0
+17  16  31  0
+44  -18  50  0
+11  -33  -39  0
+-39  1  3  0
+-11  48  31  0
+41  -21  12  0
+-15  -18  12  0
+-12  36  -8  0
+-19  -10  50  0
+-4  -25  -17  0
+3  -44  -29  0
+43  -12  47  0
+25  16  -17  0
+-20  -47  -45  0
+-2  -34  7  0
+-38  -16  -4  0
+29  -8  5  0
+40  20  -3  0
+-24  -12  -25  0
+47  29  -18  0
+-22  -3  -29  0
+-50  -37  20  0
+20  -12  -37  0
+-8  -49  -46  0
+33  20  -21  0
+-39  50  -23  0
+1  -48  -33  0
+-48  -44  29  0
+16  -43  13  0
+-17  -27  -33  0
+-20  34  48  0
+-17  -25  26  0
+44  47  13  0
+-35  -12  -46  0
+-21  -50  14  0
+-14  -25  -50  0
+-19  42  44  0
+-48  -17  11  0
+1  -33  42  0
+3  -22  48  0
+28  38  26  0
+-4  21  49  0
+-23  44  32  0
+-42  49  32  0
+-8  -41  7  0
+27  1  -50  0
+2  -7  -38  0
+26  -23  -33  0
+23  26  30  0
+-3  14  41  0
+3  -8  48  0
+-12  -5  23  0
+44  -42  -17  0
+44  31  19  0
+-44  42  -14  0
+8  31  30  0
+29  43  9  0
+48  6  -1  0
+17  46  23  0
+46  30  42  0
+-20  -3  6  0
+18  -36  -19  0
+11  -2  31  0
+32  2  -1  0
+-16  -11  -8  0
+13  -50  30  0
+-19  50  -37  0
+-42  -29  25  0
+14  29  -3  0
+-38  -28  44  0
+-46  5  -44  0
+-26  34  -23  0
+20  -25  5  0
+-29  44  8  0
+27  42  29  0
+27  8  6  0
+46  -43  -7  0
+-44  -9  -26  0
+-8  -27  -9  0
+3  -25  2  0
+-22  -36  9  0
+-4  46  -22  0
+-31  -4  -6  0
+-45  -12  8  0
+-20  -10  28  0
+-2  44  23  0
+-28  -7  -22  0
+43  17  -13  0
+44  -34  -37  0
+-34  10  47  0
+8  9  21  0
+22  3  27  0
+8  -19  46  0
+-11  27  -26  0
+20  -30  -8  0
+20  -8  6  0
+-28  -34  -12  0
+24  40  21  0
+-22  -27  -34  0
+7  -28  37  0
+-27  -36  30  0
+-18  -7  33  0
+-9  -4  -8  0
+9  -13  37  0
+-5  44  7  0
+-33  -32  -26  0
+17  -19  3  0
+-10  -12  35  0
+50  23  -8  0
+43  -13  38  0
+11  -15  40  0
+19  22  -18  0
+20  7  37  0
+-14  24  12  0
+35  -25  5  0
+-29  47  -27  0
+9  24  21  0
+-40  12  7  0
+50  -10  -44  0
+-45  29  -5  0
+41  13  -21  0
+31  -4  -40  0
+-49  8  -12  0
+-20  -12  25  0
+20  -16  19  0
+-5  -3  -17  0
+35  42  11  0
+-47  9  -48  0
+-18  -45  -28  0
+-32  35  -29  0
+28  -41  18  0
+30  -5  19  0
+-22  12  8  0
+27  -1  43  0
+35  17  23  0
+-28  26  20  0
+-3  -35  -27  0
+26  43  25  0
+-31  38  41  0
+29  -16  -10  0
+31  9  -5  0
+36  -41  22  0
+-18  -26  44  0
+40  -12  -39  0
+15  -40  -21  0
+32  -35  1  0
+4  -45  -22  0
+2  -9  -50  0
+-40  -1  19  0
+46  -41  -31  0
+10  39  47  0
+-23  -40  36  0
+40  14  41  0
+-50  -12  -30  0
+38  -39  -4  0
+-19  -28  -5  0
+15  5  43  0
+-2  9  -25  0
+-31  45  -29  0
+18  12  17  0
+-25  -26  10  0
+40  -6  -25  0
+16  -35  2  0
+40  46  22  0
+-26  -50  -6  0
+5  -30  46  0
+-17  42  38  0
+16  23  -1  0
+37  -6  44  0
+-18  25  -14  0
+47  -4  -21  0
+-31  40  26  0
+-21  18  13  0
+-1  -18  25  0
+-3  -37  -44  0
+-34  11  -2  0
+43  -41  -14  0
+-45  5  50  0
+-24  -7  31  0
+-47  -50  36  0
+16  -46  -47  0
+-46  -48  20  0
+2  -38  -22  0
+9  -47  16  0
+-24  16  13  0
+-7  31  46  0
+38  24  -1  0
+-45  37  -34  0
+-13  -23  41  0
+-33  -44  10  0
+-32  10  -8  0
+-8  -5  11  0
+3  -13  -50  0
+2  28  -48  0
+44  40  -45  0
+-46  -13  -39  0
+-22  4  -35  0
+-37  -19  50  0
+-20  23  48  0
+-17  -8  19  0
+-6  34  39  0
+28  6  -36  0
+39  -2  1  0
+24  -43  -41  0
+47  48  14  0
+2  17  8  0
+13  -17  23  0
+2  3  -15  0
+13  20  -6  0
+-11  5  -16  0
+28  -9  42  0
+-13  -23  -28  0
+16  -3  44  0
+-4  -36  11  0
+-17  -4  -42  0
+14  -27  4  0
+10  -26  21  0
+46  6  32  0
+-22  11  -35  0
+22  -24  50  0
+8  42  -7  0
+-42  31  -16  0
+-33  39  -28  0
+-2  -31  18  0
+-39  9  44  0
+35  10  4  0
+27  -40  -45  0
+-39  41  15  0
+19  7  42  0
+39  -11  6  0
+16  46  22  0
+17  27  -38  0
+-26  -11  33  0
+37  -49  -27  0
+-48  -40  8  0
+-33  -24  44  0
+-47  27  -19  0
+45  25  13  0
+32  8  -21  0
+38  39  -21  0
+14  34  -11  0
+-35  -36  -11  0
+-42  12  11  0
+10  -2  -23  0
+-39  -25  7  0
+-35  -31  -22  0
+-14  11  -35  0
+-41  -42  1  0
+3  -16  44  0
+6  -48  34  0
+18  -50  6  0
+34  20  7  0
+-25  -47  46  0
+39  23  -2  0
+45  -29  -5  0
+25  -10  15  0
+40  -21  -15  0
+-10  17  27  0
+-3  -47  16  0
+26  12  14  0
+48  42  34  0
+26  -34  48  0
+-7  34  -5  0
+-5  -20  6  0
+27  40  45  0
+17  46  -3  0
+13  12  -14  0
+-39  -8  -5  0
+15  -23  -26  0
+-38  -34  -7  0
+-39  -12  -26  0
+-28  -46  -20  0
+43  -14  -18  0
+-20  -36  -9  0
+-43  -5  13  0
+-50  23  9  0
+6  -48  24  0
+5  -8  -13  0
+-46  -39  5  0
+-12  9  -39  0
+44  -36  -2  0
+-45  36  -21  0
+4  -41  -1  0
+32  -50  44  0
+13  38  -42  0
+-40  7  -41  0
+9  1  19  0
+-48  -23  -44  0
+18  -41  1  0
+34  37  3  0
+18  -20  30  0
+-9  -26  30  0
+14  1  -7  0
+17  -42  -21  0
+-33  12  13  0
+-16  -24  -47  0
+39  1  -5  0
+-45  37  41  0
+-50  -32  37  0
+-13  -16  48  0
+23  -14  8  0
+15  -7  14  0
+-37  -44  -26  0
+17  50  -16  0
+27  15  49  0
+-6  -14  -29  0
+-20  -27  37  0
+-3  -39  49  0
+14  -6  -23  0
+9  46  -29  0
+31  37  42  0
+-11  -43  45  0
+23  -2  46  0
+30  13  31  0
+28  33  3  0
+8  -1  40  0
+-5  35  -39  0
+16  -44  -8  0
+-23  -47  -9  0
+-39  -5  -4  0
+-18  47  19  0
+-50  31  -11  0
+-49  -26  -37  0
+-36  -14  37  0
+-39  -40  -5  0
+-22  38  13  0
+18  -32  8  0
+-7  -44  14  0
+19  -11  -14  0
+20  28  42  0
+-31  9  39  0
+-13  22  -32  0
+-44  50  46  0
+-31  -10  38  0
+10  46  16  0
+-35  20  50  0
+42  44  -3  0
+-13  3  46  0
+-26  22  -23  0
+2  10  -5  0
+-26  50  -25  0
+-21  -13  -49  0
+44  -12  -7  0
+30  -29  3  0
+-19  32  -2  0
+-16  30  -32  0
+17  25  6  0
+47  7  -13  0
+30  -44  -28  0
+-46  -21  -43  0
+8  9  -14  0
+-20  38  -27  0
+-4  -14  -11  0
+-33  7  -46  0
+-16  35  -7  0
+27  1  -14  0
+21  47  37  0
+-14  -18  -19  0
+-46  -13  24  0
+-10  49  -33  0
+23  -21  -10  0
+10  49  -44  0
+34  -50  42  0
+-20  -11  38  0
+-9  -49  8  0
+3  7  9  0
+-5  31  -18  0
+-44  36  40  0
+37  27  29  0
+36  -24  -17  0
+44  35  18  0
+41  -12  -13  0
+-38  -23  3  0
+-48  -42  -3  0
+-3  47  19  0
+31  39  -34  0
+5  40  50  0
+-36  -13  -3  0
+-15  20  -24  0
+-23  37  33  0
+-21  38  -4  0
+-46  3  -39  0
+-11  39  -14  0
+-45  -9  30  0
+-25  6  -7  0
+-21  48  -36  0
+4  -10  -46  0
+-18  10  35  0
+1  -45  48  0
+46  20  -13  0
+21  -30  48  0
+10  -2  44  0
+40  38  -12  0
+33  10  35  0
+-44  49  17  0
+-32  -22  14  0
+-37  49  32  0
+-48  -8  -19  0
+-30  -19  10  0
+44  -42  -11  0
+-26  -12  24  0
+-22  -20  10  0
+-8  -12  48  0
+-6  -34  15  0
+37  -31  -13  0
+-13  -26  1  0
+17  50  -22  0
+26  36  49  0
+40  -43  -35  0
+-39  12  3  0
+42  43  18  0
+-26  34  -28  0
+29  -30  -15  0
+-15  23  -19  0
+-45  -1  -46  0
+-14  46  -47  0
+-9  -16  -34  0
+31  1  15  0
+49  3  45  0
+-50  23  43  0
+40  37  49  0
+1  -49  20  0
+27  43  -4  0
+27  -11  -6  0
+-30  -40  -50  0
+-8  46  -42  0
+-38  36  -23  0
+31  47  4  0
+-44  -10  -39  0
+-41  -5  -24  0
+-15  -6  -2  0
+11  19  50  0
+-27  -32  -26  0
+-15  18  -33  0
+18  40  16  0
+15  43  -14  0
+1  -48  31  0
+18  48  -28  0
+35  6  -4  0
+38  36  -48  0
+23  2  -44  0
+36  -49  37  0
+9  -8  -6  0
+16  -35  -33  0
+1  24  -34  0
+2  -24  -40  0
+-20  41  16  0
+-26  50  31  0
+-30  -12  48  0
+-34  20  5  0
+50  -5  26  0
+-29  -3  -14  0
+-35  13  -25  0
+-13  -46  -19  0
+29  -36  -19  0
+-12  32  29  0
+-1  4  24  0
+-19  4  -16  0
+-45  33  31  0
+-8  36  44  0
+-48  -13  16  0
+8  40  -37  0
+45  -48  30  0
+-16  -37  -40  0
+-6  -34  7  0
+-4  24  22  0
+7  -22  -49  0
+-50  -47  -8  0
+-23  -32  -44  0
+33  -47  17  0
+-28  -5  30  0
+-11  -35  43  0
+34  39  7  0
+33  -41  -14  0
+-24  39  -10  0
+47  41  -5  0
+-22  32  -7  0
+-46  -26  -40  0
+46  22  -26  0
+40  -50  -44  0
+-35  -33  40  0
+-5  41  -49  0
+16  25  -38  0
+11  -2  -34  0
+-47  -8  -22  0
+-34  19  20  0
+39  -42  -28  0
+-10  2  -40  0
+5  18  -4  0
+35  23  -49  0
+21  3  -11  0
+10  -23  -46  0
+25  12  26  0
+-48  1  -38  0
+10  -27  47  0
+-30  -46  -29  0
+30  2  43  0
+7  -11  -41  0
+-21  32  -48  0
+6  -9  -14  0
+12  47  -50  0
+-18  -19  -10  0
+32  -20  50  0
+20  47  -5  0
+30  -25  8  0
+25  31  17  0
+41  -12  -47  0
+-39  5  -41  0
+-2  6  9  0
+11  -25  16  0
+-4  28  14  0
+27  -42  -32  0
+25  21  9  0
+3  -6  -20  0
+34  -20  -28  0
+-12  -37  -22  0
+-33  -13  6  0
+43  -31  -8  0
+-48  -31  19  0
+-46  50  -15  0
+46  37  -41  0
+3  10  9  0
+-10  -20  -35  0
+33  41  30  0
+27  -30  -32  0
+18  -31  12  0
+-4  12  23  0
+38  37  19  0
+23  -47  27  0
+31  25  1  0
+-48  20  -3  0
+-31  -28  -18  0
+-14  5  32  0
+-38  -45  33  0
+28  -49  -14  0
+42  21  33  0
+44  34  -20  0
+-36  -11  37  0
+-40  49  -7  0
+-41  36  13  0
+1  -49  -37  0
+-44  2  10  0
+-42  28  11  0
+-5  -8  7  0
+2  9  13  0
+-39  26  50  0
+-47  -3  1  0
+8  32  -44  0
+22  4  -40  0
+7  -48  -47  0
+43  -6  -14  0
+1  -24  23  0
+-48  -22  -29  0
+-25  15  -49  0
+10  6  -20  0
+-25  42  24  0
+-1  -18  -46  0
+10  49  25  0
+-41  -15  47  0
+-45  1  -50  0
+-39  9  -27  0
+-35  -32  19  0
+8  -20  18  0
+-4  -14  19  0
+-14  47  28  0
+-48  30  44  0
+17  -15  12  0
+42  -33  30  0
+-41  -14  24  0
+23  -20  5  0
+-20  -47  -49  0
+-16  48  45  0
+8  -42  28  0
+-32  19  10  0
+7  49  34  0
+-22  -30  -9  0
+26  -3  4  0
+-25  -27  -28  0
+-25  20  -27  0
+-32  -38  4  0
+4  -6  3  0
+-50  -3  -31  0
+47  7  26  0
+-36  50  21  0
+-44  31  -19  0
+22  34  -28  0
+27  42  -38  0
+43  -33  34  0
+24  -21  39  0
+-47  -3  -35  0
+15  -3  -24  0
+46  -50  -1  0
+-27  -39  -35  0
+33  -4  16  0
+40  49  -3  0
+-27  -44  12  0
+-1  29  2  0
+2  -36  -5  0
+-29  38  -40  0
+-44  -48  5  0
+-9  -36  12  0
+-41  27  19  0
+-4  -19  40  0
+28  15  26  0
+-12  -41  50  0
+-2  -40  -21  0
+17  -37  -20  0
+41  -39  17  0
+7  4  49  0
+-16  -44  22  0
+-48  20  -44  0
+6  5  -10  0
+-19  -10  30  0
+1  -36  -25  0
+16  -50  -21  0
+3  -44  43  0
+32  24  50  0
+-28  49  32  0
+37  -11  14  0
+-11  -10  -16  0
+21  42  30  0
+-34  46  -12  0
+-50  -9  -4  0
+-2  10  36  0
+-47  35  -25  0
+-13  -42  -33  0
+21  50  42  0
+1  -33  38  0
+42  14  -43  0
+31  -18  22  0
+-19  -50  42  0
+-20  -43  8  0
+24  -16  -36  0
+-7  -40  21  0
+-11  -50  -27  0
+-47  -1  -27  0
+-15  -7  45  0
+-33  -29  14  0
+50  -26  -28  0
+-43  20  -9  0
+11  24  -4  0
+-29  33  21  0
+-45  11  -33  0
+23  29  47  0
+-8  33  34  0
+-8  5  29  0
+-14  36  -38  0
+35  -27  -7  0
+42  -24  -45  0
+30  26  14  0
+-20  -8  25  0
+10  17  -28  0
+-1  16  -46  0
+-30  -13  -12  0
+-41  -13  -48  0
+-30  -38  49  0
+35  12  22  0
+42  25  32  0
+7  44  -19  0
+-49  -32  3  0
+-24  6  -11  0
+-26  31  9  0
+7  -34  -45  0
+35  5  -16  0
+-25  47  42  0
+-42  7  11  0
+-30  27  7  0
+7  32  22  0
+1  -16  -44  0
+-9  8  -3  0
+-5  -28  -2  0
+28  -34  42  0
+-25  -15  -38  0
+20  18  -13  0
+35  -3  -6  0
+3  1  34  0
+-45  -29  -4  0
+-34  -19  40  0
+28  -11  1  0
+-43  17  34  0
+-17  46  -1  0
+15  24  -17  0
+-35  26  1  0
+18  -2  -36  0
+4  -45  -33  0
+3  -49  40  0
+48  -32  -3  0
+39  4  27  0
+46  -10  -15  0
+-2  9  41  0
+-49  23  21  0
+-11  32  -27  0
+36  -43  19  0
+14  35  17  0
+43  -26  18  0
+-28  -21  13  0
+-1  20  3  0
+-25  -31  17  0
+-25  -36  15  0
+27  -32  -11  0
+9  -20  -42  0
+45  -40  39  0
+-9  -44  24  0
+-1  14  34  0
+-22  19  -27  0
+8  -11  -39  0
+31  24  1  0
+-44  12  21  0
+-24  47  -6  0
+-26  12  -7  0
+41  32  -14  0
+-19  16  -42  0
+12  27  -24  0
+49  -6  43  0
+-43  25  4  0
+33  32  -31  0
+-32  44  47  0
+3  -47  -17  0
+-38  42  22  0
+-32  -2  -7  0
+7  44  1  0
+-14  22  -6  0
+2  -44  -20  0
+-24  -37  -28  0
+-3  30  29  0
+46  -44  30  0
+44  21  18  0
+26  -21  37  0
+6  19  -28  0
+20  30  -29  0
+-20  -7  40  0
+21  32  26  0
+32  16  -35  0
+-8  38  27  0
+33  14  -17  0
+-10  39  -47  0
+-33  -24  -38  0
+-13  -24  -4  0
+-8  -17  -42  0
+41  -2  -3  0
+-19  1  -42  0
+18  -25  46  0
+-13  26  -37  0
+-45  20  50  0
+-44  -4  -19  0
+19  -20  42  0
+38  -9  7  0
+7  8  18  0
+33  -4  -26  0
+10  16  29  0
+22  6  -18  0
+-32  -24  -26  0
+40  7  -23  0
+45  31  -7  0
+-42  -22  -12  0
+-31  -1  15  0
+-3  -46  -16  0
+47  25  44  0
+-8  11  9  0
+-9  -21  34  0
+35  -14  -17  0
+-21  4  -33  0
+-39  -20  49  0
+40  4  -11  0
+-47  -30  45  0
+-9  25  -26  0
+-49  -17  37  0
+-9  -22  49  0
+6  -9  -10  0
+-15  -35  -46  0
+25  -50  17  0
+16  -34  28  0
+-5  -45  -37  0
+-35  -43  -3  0
+-21  4  -13  0
+-27  11  43  0
+37  -21  -25  0
+-24  -10  36  0
+-32  -12  -49  0
+-29  20  4  0
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-215.cnf
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-215.cnf	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sat/data-215.cnf	(revision 6152)
@@ -0,0 +1,219 @@
+c mkcnf random cnf with seed 522186, max clause length 3
+c FORCED SATISFIABLE
+c 
+p cnf 50  215
+49  44  28  0
+-18  38  7  0
+-13  26  40  0
+-23  -16  -6  0
+1  6  22  0
+-26  -6  -20  0
+-43  -2  14  0
+-40  21  30  0
+36  -21  -27  0
+22  -16  6  0
+-37  29  -26  0
+-14  -16  18  0
+-29  -10  -18  0
+50  -41  7  0
+1  -9  -39  0
+-4  -43  -50  0
+1  42  30  0
+19  47  -9  0
+-41  -17  -34  0
+-8  -44  36  0
+26  -28  41  0
+-26  35  19  0
+-35  11  -28  0
+10  -42  27  0
+37  -50  42  0
+23  5  46  0
+36  35  8  0
+-19  45  21  0
+-39  -30  14  0
+-29  43  -42  0
+-43  -28  6  0
+6  -31  16  0
+4  22  -45  0
+-4  -39  29  0
+46  -18  -23  0
+7  -36  -28  0
+15  -33  -44  0
+23  16  -43  0
+-30  -41  -1  0
+-20  -14  26  0
+25  44  -50  0
+3  -40  2  0
+-39  -10  -16  0
+16  5  42  0
+-22  -2  32  0
+-42  44  -25  0
+-19  -50  -32  0
+4  -10  19  0
+-41  -38  33  0
+-7  29  -38  0
+8  -17  -47  0
+30  5  -17  0
+43  30  -41  0
+-17  11  -23  0
+13  -32  26  0
+-39  7  17  0
+-35  -17  11  0
+-50  -35  49  0
+27  -2  35  0
+9  44  -40  0
+45  17  -29  0
+-26  -30  -47  0
+3  23  -44  0
+-38  -48  21  0
+12  49  -26  0
+47  -38  22  0
+-45  -22  38  0
+23  37  1  0
+3  12  16  0
+-47  35  39  0
+16  -44  15  0
+42  -14  8  0
+-45  40  28  0
+-40  -3  27  0
+-44  -9  12  0
+35  33  19  0
+-2  -14  12  0
+-10  26  -14  0
+-22  12  36  0
+-19  31  16  0
+-43  35  -12  0
+39  -7  24  0
+-14  31  10  0
+-7  -21  10  0
+14  41  4  0
+-7  13  -49  0
+5  31  18  0
+23  25  30  0
+-25  -34  -14  0
+44  45  1  0
+-47  -38  -17  0
+28  -4  -13  0
+-36  -4  50  0
+8  -15  1  0
+-45  -8  7  0
+-9  7  -34  0
+-2  36  -1  0
+-15  19  -33  0
+11  43  50  0
+30  22  34  0
+25  -5  -21  0
+14  32  17  0
+32  -35  39  0
+9  -37  42  0
+1  -19  -18  0
+27  -36  5  0
+45  16  32  0
+19  30  -46  0
+49  19  -32  0
+-42  45  -32  0
+2  -45  -30  0
+-44  21  12  0
+8  5  34  0
+41  48  -45  0
+-27  43  -1  0
+-23  -30  7  0
+-18  -47  -15  0
+31  -20  -19  0
+38  -46  16  0
+48  23  -17  0
+-41  34  -16  0
+5  19  -2  0
+23  -17  29  0
+-7  17  -40  0
+-49  -11  -26  0
+48  -49  39  0
+17  -33  4  0
+-12  35  -5  0
+18  9  27  0
+-19  -38  -40  0
+35  -42  44  0
+17  2  -31  0
+35  -5  14  0
+14  -35  1  0
+43  -9  2  0
+50  34  -22  0
+43  -1  -15  0
+-11  -12  -32  0
+-9  -2  -10  0
+14  30  49  0
+-18  39  -28  0
+38  34  -46  0
+2  35  -44  0
+-5  49  42  0
+27  -14  -42  0
+20  -6  30  0
+5  -44  26  0
+-28  -16  -22  0
+-43  45  36  0
+-18  -28  44  0
+-42  13  -15  0
+-15  -43  24  0
+8  10  7  0
+15  -36  -32  0
+41  4  -46  0
+-15  -17  11  0
+24  34  -35  0
+39  -46  -50  0
+-12  43  -24  0
+9  5  28  0
+-48  -41  -15  0
+-7  32  34  0
+-22  50  -38  0
+-17  23  -37  0
+-26  -31  40  0
+48  8  -21  0
+-46  32  37  0
+26  39  -38  0
+-21  -10  -27  0
+-7  -13  -26  0
+-17  48  -47  0
+-12  -17  -32  0
+-17  43  42  0
+-43  12  -18  0
+-39  1  36  0
+38  -34  44  0
+-24  1  -33  0
+-48  19  18  0
+18  23  -30  0
+7  11  -49  0
+41  -37  26  0
+20  47  -15  0
+16  -21  26  0
+5  -40  43  0
+42  -25  16  0
+-6  -15  -25  0
+13  4  22  0
+13  43  -45  0
+-22  -10  -16  0
+43  38  -8  0
+41  -20  -39  0
+14  -9  50  0
+50  12  17  0
+-5  -45  -3  0
+-23  26  43  0
+3  -14  30  0
+13  26  19  0
+-25  35  23  0
+44  14  -33  0
+33  -37  -1  0
+-22  -21  -33  0
+20  49  18  0
+-45  -5  39  0
+8  21  37  0
+-37  16  46  0
+16  -26  47  0
+-49  -6  28  0
+11  30  48  0
+-33  -10  -8  0
+-19  -32  30  0
+-22  12  -18  0
+9  10  46  0
+-50  -44  -8  0
+-6  -20  43  0
+11  8  26  0
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sat/sat.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sat/sat.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sat/sat.params	(revision 6152)
@@ -0,0 +1,29 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../simple/simple.params
+
+seed.0 = time
+
+pop.subpop.0.species.genome-size = 50 
+
+eval.problem = ec.app.sat.SAT
+eval.problem.sat-filename = data-1000.cnf
+
+pop.subpop.0.size = 1000 
+generations = 100 
+
+pop.subpop.0.species = ec.vector.VectorSpecies 
+pop.subpop.0.species.pipe = ec.vector.breed.VectorMutationPipeline 
+pop.subpop.0.species.pipe.source.0 = ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same 
+
+pop.subpop.0.species.ind = ec.vector.BitVectorIndividual
+pop.subpop.0.species.fitness = ec.simple.SimpleFitness
+
+select.tournament.size =                2 
+pop.subpop.0.species.mutation-prob = 0.05
+pop.subpop.0.species.crossover-type =two  
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/README	(revision 6152)
@@ -0,0 +1,5 @@
+This package shows two examples of evolutionary search using ECJ's spatially-embedded models.  Both of them use the optimization in the Rosenbrock problem domain.
+
+First, we show how to use a regular spatially-embedded evolutionary computation model (file: spatial.params).  The population is embedded in a 1-D ring (the only spatial model available in ECJ v14), and a spatial version of tournament selection is used for breeding.
+
+Second, we show hot to use a spatially-embedded coevolutionary model (file: spatialcoevolve.params).  Here, both populations are embedded in 1-D rings of the same size.  Aside from the evolution in each population (which is set as in the previous case), we also employ a spatial coevolutionary evaluator: individuals are evaluated in combination with partners that reside at neighboring locations in the other populations.
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/spatial.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/spatial.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/spatial.params	(revision 6152)
@@ -0,0 +1,42 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =                              		../../simple/simple.params
+
+# We use the Rosenbrock function as defined in the ECSuite application
+eval.problem = 						ec.app.ecsuite.ECSuite
+eval.problem.type = 					rosenbrock
+
+# The SpatialBreeder puts spatial constraints on the whole breeding process, such that only
+# nearby individuals are selected as parents for a child
+breed =							ec.spatial.SpatialBreeder
+
+# For spatial EAs, we employ a Spatial1DSubpopulation, which embeds the whole population
+# onto a toroidal ring with the same size as the population.  We also use the new Gaussian
+# mutation for DoubleVectorIndividuals. 
+pop.subpops =                           		1
+pop.subpop.0 =						ec.spatial.Spatial1DSubpopulation
+pop.subpop.0.duplicate-retries =			10
+pop.subpop.0.size =					16
+pop.subpop.0.species =					ec.vector.FloatVectorSpecies
+pop.subpop.0.species.crossover-type = 			one
+pop.subpop.0.species.genome-size =			2
+pop.subpop.0.species.fitness =				ec.simple.SimpleFitness
+pop.subpop.0.species.ind =				ec.vector.DoubleVectorIndividual
+pop.subpop.0.species.min-gene =				-5.12
+pop.subpop.0.species.max-gene =				5.12
+pop.subpop.0.species.pipe =             		ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.mutation-type =                    gauss
+pop.subpop.0.species.mutation-stdev =	       		0.25
+pop.subpop.0.species.mutation-prob =    		0.75
+
+# Parents are selected via SpatialTournamentSelection: given mutation alone, a child at location
+# x is created by mutating an parent that is selected from the current population in the vecinity
+# of location x (the neighborhood size is set to 2 in this case).  If ind-competes is set to true,
+# the parent at location x is always selected as one of the participants to the spatial tournament
+# selection.  In our case, the tournament selection is of size 2.
+pop.subpop.0.species.pipe.source.0 = 			ec.spatial.SpatialTournamentSelection
+pop.subpop.0.species.pipe.source.0.size = 		2
+pop.subpop.0.species.pipe.source.0.neighborhood-size = 	2
+pop.subpop.0.species.pipe.source.0.ind-competes = 	true
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/spatialcoevolve.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/spatialcoevolve.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/spatial/spatialcoevolve.params	(revision 6152)
@@ -0,0 +1,50 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =                              		../coevolve2/coevolve2.params
+
+# The breeder is of type SpatialBreeder to take advantage of the spatially-embedded population
+breed =                                 		ec.spatial.SpatialBreeder
+
+# We use the SpatialMultiPopCoevolutionaryEvaluator class, which selects partners in the vecinity of the
+# location where the child will be created (it assumes all populations have the same spatial embedding).
+eval =                                  		ec.spatial.SpatialMultiPopCoevolutionaryEvaluator
+
+# Notice that multiple partners (collaborators) can be selected for evaluating each individual.  In our
+# experiments, we have found that selecting just the partner at the same location in the other populations
+# works best; this is what the following settings accomplish.
+eval.subpop.0.use-same-location-partners =              true
+eval.subpop.0.num-partners =                            1
+eval.subpop.0.select =                                  ec.spatial.SpatialTournamentSelection
+eval.subpop.0.select.size =                             1
+eval.subpop.0.select.neighborhood-size =                1
+
+eval.subpop.1.use-same-location-partners =              true
+eval.subpop.1.num-partners =                            1
+eval.subpop.1.select =                                  ec.spatial.SpatialTournamentSelection
+eval.subpop.1.select.size =                             1
+eval.subpop.1.select.neighborhood-size =                1
+
+
+# The last three lines of each of the following two groups
+# could have been replaced with just:
+# spatial.tournament.size = 2
+# spatial.tournament.neighborhood-size = 2
+# spatial.tournament.ind-competes = true
+
+pop.subpops =                           		2
+pop.subpop.0 = 						ec.spatial.Spatial1DSubpopulation
+pop.subpop.0.size = 					32
+pop.subpop.0.species.pipe.source.0 = 			ec.spatial.SpatialTournamentSelection
+pop.subpop.0.species.pipe.source.0.size = 		2
+pop.subpop.0.species.pipe.source.0.neighborhood-size = 	2
+pop.subpop.0.species.pipe.source.0.ind-competes = 	true
+
+pop.subpop.1 = 						ec.spatial.Spatial1DSubpopulation
+pop.subpop.1.size = 					32
+pop.subpop.1.species.pipe.source.0 = 			ec.spatial.SpatialTournamentSelection
+pop.subpop.1.species.pipe.source.0.size = 		2
+pop.subpop.1.species.pipe.source.0.neighborhood-size = 	2
+pop.subpop.1.species.pipe.source.0.ind-competes = 	true
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/README	(revision 6152)
@@ -0,0 +1,46 @@
+This directory contains two examples for the ECJ master/slave evaluator.
+See ec/eval/README for more information on how to run the evaluator
+and the ec/eval/master.params file for more parameter information and
+options.
+
+NOTE: these examples are worst-case scenarios for the master/slave
+evaluator -- they evaluate rapidly and so the time is CONSUMED by
+transfering over the net.  The examples are only here to give you 
+the idea of how to get your own jobs up and running.
+
+
+Artificial Ant (change the eval.master.host in ant.slave.params to the
+	appropriate IP of the master's machine.  By default it's
+	127.0.0.1, which only works if all the slaves are on the
+	same machine as the host; this configuration is likely 
+	only useful for testing purposes)
+
+MASTER:		java ec.Evolve -file ant.master.params
+EACH SLAVE:	java ec.eval.Slave -file ant.slave.params
+
+
+
+Coevolve1 - an example of competitive coevolution using the
+	master-slave architecture. (change the eval.master.host 
+	in coevolve1.slave.params to the
+        appropriate IP of the master's machine.  By default it's
+        127.0.0.1, which only works if all the slaves are on the
+        same machine as the host; this configuration is likely 
+        only useful for testing purposes). 
+
+MASTER:         java ec.Evolve -file coevolve1.master.params
+EACH SLAVE:     java ec.eval.Slave -file coevolve1.slave.params
+
+
+Coevolve2 - an example of cooperative coevolution using the
+	master-slave architecture. (change the eval.master.host 
+	in coevolve2.slave.params to the
+        appropriate IP of the master's machine.  By default it's
+        127.0.0.1, which only works if all the slaves are on the
+        same machine as the host; this configuration is likely
+        only useful for testing purposes).
+
+MASTER:         java ec.Evolve -file coevolve2.master.params
+EACH SLAVE:     java ec.eval.Slave -file coevolve2.slave.params
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/ant.master.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/ant.master.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/ant.master.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../ant/ant.params
+parent.1 = ../../eval/master.params
+
+# That's it!  We're not changing any of the parameters
+# but you might want to look at your options in 
+# ec/eval/master.params
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/ant.slave.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/ant.slave.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/ant.slave.params	(revision 6152)
@@ -0,0 +1,34 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ant.master.params
+
+#### NO LONGER NEEDED
+# We tell our slave that he's a slave.
+# eval.i-am-slave = true
+#### END NO LONGER NEEDED
+
+# You may want to customize each slave by giving it a unique
+# name like this:
+# 
+# eval.slave-name = my-slave-name
+#
+# (do this differently for each slave:, slave-2, slave-3, etc.)
+# Otherwise, each slave will give itself an approximately unique name based
+# on the current time and the IP address of the slave.  The unique name
+# doesn't HAVE to be unique -- it's just for printing/debug purposes.
+
+
+# We want to make sure that the Slave's Statistics object does not
+# override the Master's statistics files.  The easiest way to do this
+# is to eliminate the Statistics object in the slave by setting it
+# to the (empty default) Statistics class with no children.
+
+eval.stat = ec.Statistics
+eval.stat.num-children = 0
+
+
+# The slave needs to know where the Master is.  You need to 
+# change this.
+eval.master.host = 127.0.0.1
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve1.master.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve1.master.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve1.master.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../coevolve1/coevolve1.params
+parent.1 = ../../eval/master.params
+
+# That's it!  We're not changing any of the parameters
+# but you might want to look at your options in 
+# ec/eval/master.params
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve1.slave.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve1.slave.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve1.slave.params	(revision 6152)
@@ -0,0 +1,35 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =      coevolve1.master.params
+
+### NO LONGER NEEDED
+# We tell our slave that he's a slave.
+# eval.i-am-slave = true
+### END NO LONGER NEEDED
+
+# You may want to customize each slave by giving it a unique
+# name like this:
+# 
+# eval.slave-name = my-slave-name
+#
+# (do this differently for each slave:, slave-2, slave-3, etc.)
+# Otherwise, each slave will give itself an approximately unique name based
+# on the current time and the IP address of the slave.  The unique name
+# doesn't HAVE to be unique -- it's just for printing/debug purposes.
+
+
+# We want to make sure that the Slave's Statistics object does not
+# override the Master's statistics files.  The easiest way to do this
+# is to eliminate the Statistics object in the slave by setting it
+# to the (empty default) Statistics class with no children.
+
+eval.stat = ec.Statistics
+eval.stat.num-children = 0
+
+
+# The slave needs to know where the Master is.  You need to 
+# change this.
+eval.master.host = 127.0.0.1
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve2.master.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve2.master.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve2.master.params	(revision 6152)
@@ -0,0 +1,11 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../coevolve2/coevolve2.params
+parent.1 = ../../eval/master.params
+
+# That's it!  We're not changing any of the parameters
+# but you might want to look at your options in 
+# ec/eval/master.params
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve2.slave.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve2.slave.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/coevolve2.slave.params	(revision 6152)
@@ -0,0 +1,36 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =      coevolve2.master.params
+
+### NO LONGER NEEDED
+# We tell our slave that he's a slave.
+# eval.i-am-slave = true
+### END NO LONGER NEEDED
+
+
+# You may want to customize each slave by giving it a unique
+# name like this:
+# 
+# eval.slave-name = my-slave-name
+#
+# (do this differently for each slave:, slave-2, slave-3, etc.)
+# Otherwise, each slave will give itself an approximately unique name based
+# on the current time and the IP address of the slave.  The unique name
+# doesn't HAVE to be unique -- it's just for printing/debug purposes.
+
+
+# We want to make sure that the Slave's Statistics object does not
+# override the Master's statistics files.  The easiest way to do this
+# is to eliminate the Statistics object in the slave by setting it
+# to the (empty default) Statistics class with no children.
+
+eval.stat = ec.Statistics
+eval.stat.num-children = 0
+
+
+# The slave needs to know where the Master is.  You need to 
+# change this.
+eval.master.host = 127.0.0.1
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave1.params	(revision 6152)
@@ -0,0 +1,7 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ant.master.params
+
+eval.slave-name = first
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave2.params	(revision 6152)
@@ -0,0 +1,7 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ant.master.params
+
+eval.slave-name = second
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/ant.slave3.params	(revision 6152)
@@ -0,0 +1,7 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ant.master.params
+
+eval.slave-name = third
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave1.params	(revision 6152)
@@ -0,0 +1,7 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = coevolve1.star.params
+
+eval.slave-name = first
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave2.params	(revision 6152)
@@ -0,0 +1,7 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = coevolve1.star.params
+
+eval.slave-name = second
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/star/old/coevolve1.slave3.params	(revision 6152)
@@ -0,0 +1,14 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = coevolve1.star.params
+
+# You may want to customize each slave by giving it a unique 
+# Name like this:
+#
+# eval.slave-name = slave-1
+# 
+# (do this differently for each slave of course: slave-2, etc.)
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sum/Sum.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sum/Sum.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sum/Sum.java	(revision 6152)
@@ -0,0 +1,75 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.sum;
+import ec.vector.*;
+import ec.*;
+import ec.simple.*;
+import ec.util.*;
+
+/* 
+ * Sum.java
+ * 
+ * Created on Sat Jun 16 23:26:38 EDT 2001
+ * By Sean Luke
+ */
+
+/**
+ * Sum is a simple example of the ec.Vector package, implementing the
+ * very simple sum problem (fitness = sum over vector).
+ * This is a generalization of the common MaxOnes problem
+ * (fitness = number of 1's in vector).
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+
+
+public class Sum extends Problem implements SimpleProblemForm
+    {
+    public static final String P_SUM = "sum";
+    
+    public Parameter defaultBase()
+        {
+        return super.defaultBase().push(P_SUM);
+        }
+
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (ind.evaluated) return;
+
+        if (!(ind instanceof IntegerVectorIndividual))
+            state.output.fatal("Whoa!  It's not an IntegerVectorIndividual!!!",null);
+
+        IntegerVectorIndividual ind2 = (IntegerVectorIndividual)ind;
+        IntegerVectorSpecies s = (IntegerVectorSpecies)ind2.species;
+        
+        long sum=0;
+        long max=0;
+        for(int x=0; x<ind2.genome.length; x++)
+            {
+            sum += ind2.genome[x];
+            max += (int)(s.maxGene(x));  // perhaps this neededn't be computed over and over again
+            }
+
+        // Now we know that max is the maximum possible value, and sum is the fitness.
+        
+        // assume we're using SimpleFitness
+        ((SimpleFitness)ind2.fitness).setFitness(state,
+            /// ...the fitness...
+            (float)(((double)sum)), 
+            ///... our definition of the ideal individual
+            sum == max);
+                
+        ind2.evaluated = true;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sum/steadysum.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sum/steadysum.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sum/steadysum.params	(revision 6152)
@@ -0,0 +1,68 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../steadystate/steadystate.params
+parent.1 = sum.params
+
+# The stuff above is all you need to do single-population
+# steady-state evolution.  But there are some additional
+# gizmos you should be aware of.
+
+# 0. By default, the "deselector" (the selection operator
+# responsible for determining who in the population will
+# die) is tournament selection of size 1 -- that is,
+# random selection.  Let's say you'd like it to be more
+# aggressive, say, tournament selection of size 2, picking
+# the worse individual.  You can do that like this:
+# 
+# steady.deselector.0.size = 	2	
+#
+# Or much more aggressive:
+#
+# steady.deselector.0.size =	7
+#
+# You can change the deselector entirely but it needs
+# to be of SteadyStateBreedingSourceForm, and the most
+# obvous choice (the classic for Steady State GA's,
+# BestSelection set to pick-worst) is actually not of
+# this form because it's expensive to scan through the
+# whole population each time.
+
+# 1. By default, the steady-state evolution runs for some
+# number of *generations*, where a generation is defined
+# as the time in which N individuals are evaluated, where
+# N is the size of subpopulation 0.  The first generation
+# is of course special as all the individuals are
+# evaluated together.  Subsequent "generations" are just
+# however long it takes for N more individuals to be
+# evaluated.  You can change the run-length from being
+# based on generations to being based on number of
+# evaluations if you want something more precise.  To do
+# that you'd set:
+#
+#evaluations = 100 
+#
+# Which says how many evaluations you want.  Obviously
+# this must be larger than the initial population size...
+
+# 2. When you run in its current form, this parameter
+# file will cause the system to complain that you didn't
+# provide a SteadyStateStatistics object.  This is okay,
+# but you may not get the statistics you expect.  For
+# more information, see SteadyStateEvolutionState
+
+# statistics =		...
+
+# 3. You want to specify whether or not to allow any
+# children to enter the population if they are identical
+# to some existing member of the population.  Disallowing
+# duplicates in this way is the traditional approach to
+# steady-state evolution.  At present, each time we 
+# need to make an individual, we try up to 100 times to
+# create one that's not a duplicate.  You can change
+# the number of times to retry (or set to 0 to not
+# retry) by changing this parameter:
+
+# steady.duplicate-retries = 		...
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/sum/sum.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/sum/sum.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/sum/sum.params	(revision 6152)
@@ -0,0 +1,39 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../simple/simple.params
+
+# The following is a quick-and-dirty example of how to use the vector
+# package to create a simple GA.  The GA is as follows:
+#
+# 1-point crossover over a vector of integers
+# ints range from 0 to 100 inclusive.  Fitness = sum(vector)
+# 2-tournament selection
+# Individuals are selected, crossed over, and then mutated
+# mutation probability = 0.1
+# mutation is randomization of the integer
+
+pop.subpop.0.size = 10
+generations = 20000 
+
+pop.subpop.0.duplicate-retries = 0
+
+# specify species information
+pop.subpop.0.species = 			ec.vector.IntegerVectorSpecies
+pop.subpop.0.species.fitness =		ec.simple.SimpleFitness
+pop.subpop.0.species.ind = 		ec.vector.IntegerVectorIndividual
+pop.subpop.0.species.min-gene = 0
+pop.subpop.0.species.max-gene = 100
+pop.subpop.0.species.genome-size = 10
+pop.subpop.0.species.crossover-type = one
+pop.subpop.0.species.mutation-prob = 0.1
+
+pop.subpop.0.species.pipe = ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0 = ec.vector.breed.VectorCrossoverPipeline
+
+select.tournament.size = 2
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same
+
+eval.problem = ec.app.sum.Sum
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial1/MaxOnes.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial1/MaxOnes.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial1/MaxOnes.java	(revision 6152)
@@ -0,0 +1,40 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial1;
+import ec.*;
+import ec.simple.*;
+import ec.vector.*;
+
+public class MaxOnes extends Problem implements SimpleProblemForm
+    {
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (ind.evaluated) return;
+
+        if (!(ind instanceof BitVectorIndividual))
+            state.output.fatal("Whoa!  It's not a BitVectorIndividual!!!",null);
+        
+        int sum=0;
+        BitVectorIndividual ind2 = (BitVectorIndividual)ind;
+        
+        for(int x=0; x<ind2.genome.length; x++)
+            sum += (ind2.genome[x] ? 1 : 0);
+        
+        if (!(ind2.fitness instanceof SimpleFitness))
+            state.output.fatal("Whoa!  It's not a SimpleFitness!!!",null);
+        ((SimpleFitness)ind2.fitness).setFitness(state,
+            /// ...the fitness...
+            (float)(((double)sum)/ind2.genome.length),
+            ///... is the individual ideal?  Indicate here...
+            sum == ind2.genome.length);
+        ind2.evaluated = true;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial1/tutorial1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial1/tutorial1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial1/tutorial1.params	(revision 6152)
@@ -0,0 +1,53 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# The parameters that were laid out in Tutorial 1 (see the documentation)
+
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads	= 1
+seed.0		= 4357
+
+state		= ec.simple.SimpleEvolutionState
+
+pop		= ec.Population
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+eval		= ec.simple.SimpleEvaluator
+stat		= ec.simple.SimpleStatistics
+exch		= ec.simple.SimpleExchanger
+
+generations		= 200
+quit-on-run-complete	= true
+checkpoint		= false
+prefix			= ec
+checkpoint-modulo	= 1
+
+stat.file		= $out.stat
+
+pop.subpops		= 1
+pop.subpop.0		= ec.Subpopulation
+
+pop.subpop.0.size 		= 10
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.0.species 		= ec.vector.VectorSpecies
+
+pop.subpop.0.species.fitness 	= ec.simple.SimpleFitness
+pop.subpop.0.species.ind	= ec.vector.BitVectorIndividual
+
+pop.subpop.0.species.genome-size	= 20
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.0.species.crossover-prob	= 1.0
+pop.subpop.0.species.mutation-prob	= 0.01
+
+pop.subpop.0.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0		= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0	= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1	= ec.select.TournamentSelection
+
+select.tournament.size		= 2
+
+eval.problem		= ec.app.tutorial1.MaxOnes
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/AddSubtract.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/AddSubtract.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/AddSubtract.java	(revision 6152)
@@ -0,0 +1,47 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial2;
+import ec.*;
+import ec.simple.*;
+import ec.vector.*;
+
+public class AddSubtract extends Problem implements SimpleProblemForm
+    {
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (ind.evaluated) return;
+
+        if (!(ind instanceof IntegerVectorIndividual))
+            state.output.fatal("Whoa!  It's not a IntegerVectorIndividual!!!",null);
+        
+        IntegerVectorIndividual ind2 = (IntegerVectorIndividual)ind;
+        
+        int rawfitness = 0;
+        for(int x=0; x<ind2.genome.length; x++)
+            if (x % 2 == 0) rawfitness += ind2.genome[x];
+            else rawfitness -= ind2.genome[x];
+        
+        // We finish by taking the ABS of rawfitness.  By the way,
+        // in SimpleFitness, fitness values must be set up so that 0 is <= the worst
+        // fitness and +infinity is >= the ideal possible fitness.  Our raw fitness
+        // value here satisfies this. 
+        if (rawfitness < 0) rawfitness = -rawfitness;
+        if (!(ind2.fitness instanceof SimpleFitness))
+            state.output.fatal("Whoa!  It's not a SimpleFitness!!!",null);
+        ((SimpleFitness)ind2.fitness).setFitness(state,
+            // what the heck, lets normalize the fitness for genome length
+            // so it's within float range
+            (float)(((double)rawfitness)/ind2.genome.length),
+            ///... is the individual ideal?  Indicate here...
+            false);
+        ind2.evaluated = true;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/OurMutatorPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/OurMutatorPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/OurMutatorPipeline.java	(revision 6152)
@@ -0,0 +1,100 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial2;
+import ec.vector.*;
+import ec.*;
+import ec.util.*;
+
+/*
+ * OurMutatorPipeline.java
+ */
+
+/**
+   OurMutatorPipeline is a BreedingPipeline which negates the sign of genes.
+   The individuals must be IntegerVectorIndividuals.  Because we're lazy,
+   we'll use the individual's species' mutation-probability parameter to tell
+   us whether or not to mutate a given gene.
+ 
+   <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+   (however many its source produces)
+
+   <p><b>Number of Sources</b><br>
+   1
+*/
+
+
+public class OurMutatorPipeline extends BreedingPipeline
+    {
+    public static final String P_OURMUTATION = "our-mutation";
+
+    // We have to specify a default base, even though we never use it 
+    public Parameter defaultBase() { return VectorDefaults.base().push(P_OURMUTATION); }
+    
+    public static final int NUM_SOURCES = 1;
+
+    // Return 1 -- we only use one source
+    public int numSources() { return NUM_SOURCES; }
+
+    // We're supposed to create a most _max_ and at least _min_ individuals,
+    // drawn from our source and mutated, and stick them into slots in inds[]
+    // starting with the slot inds[start].  Let's do this by telling our 
+    // source to stick those individuals into inds[] and then mutating them
+    // right there.
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+        // clone the individuals if necessary -- if our source is a BreedingPipeline
+        // they've already been cloned, but if the source is a SelectionMethod, the
+        // individuals are actual individuals from the previous population
+        if (!(sources[0] instanceof BreedingPipeline))
+            for(int q=start;q<n+start;q++)
+                inds[q] = (Individual)(inds[q].clone());
+
+        // Check to make sure that the individuals are IntegerVectorIndividuals and
+        // grab their species.  For efficiency's sake, we assume that all the 
+        // individuals in inds[] are the same type of individual and that they all
+        // share the same common species -- this is a safe assumption because they're 
+        // all breeding from the same subpopulation.
+
+        if (!(inds[start] instanceof IntegerVectorIndividual)) // uh oh, wrong kind of individual
+            state.output.fatal("OurMutatorPipeline didn't get an IntegerVectorIndividual." +
+                "The offending individual is in subpopulation " + subpopulation + " and it's:" + inds[start]);
+        IntegerVectorSpecies species = (IntegerVectorSpecies)(inds[start].species);
+
+        // mutate 'em!
+        for(int q=start;q<n+start;q++)
+            {
+            IntegerVectorIndividual i = (IntegerVectorIndividual)inds[q];
+            for(int x=0;x<i.genome.length;x++)
+                if (state.random[thread].nextBoolean(species.mutationProbability))
+                    i.genome[x] = -i.genome[x];
+            // it's a "new" individual, so it's no longer been evaluated
+            i.evaluated=false;
+            }
+
+        return n;
+        }
+
+    }
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/tutorial2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/tutorial2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial2/tutorial2.params	(revision 6152)
@@ -0,0 +1,30 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0		= ../../simple/simple.params
+pop.subpop.0.size = 100
+generations = 200
+
+pop.subpop.0.species		= ec.vector.IntegerVectorSpecies
+pop.subpop.0.species.ind	= ec.vector.IntegerVectorIndividual
+pop.subpop.0.species.fitness 	= ec.simple.SimpleFitness
+pop.subpop.0.species.min-gene	= -12312
+pop.subpop.0.species.max-gene 	= 2341212	
+pop.subpop.0.species.genome-size	= 20
+pop.subpop.0.species.crossover-type	= two
+pop.subpop.0.species.crossover-prob	= 1.0
+pop.subpop.0.species.mutation-prob	= 0.05
+
+# Use our own custom mutation class
+pop.subpop.0.species.pipe = ec.app.tutorial2.OurMutatorPipeline
+pop.subpop.0.species.pipe.source.0	= ec.vector.breed.VectorCrossoverPipeline
+# Toss the second child
+pop.subpop.0.species.pipe.source.0.toss = true
+pop.subpop.0.species.pipe.source.0.source.0 = ec.select.FitProportionateSelection
+pop.subpop.0.species.pipe.source.0.source.1 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1.size = 5
+# Pick the worst individual in the tournament
+pop.subpop.0.species.pipe.source.0.source.1.pick-worst = true
+
+eval.problem            = ec.app.tutorial2.AddSubtract
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/MyStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/MyStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/MyStatistics.java	(revision 6152)
@@ -0,0 +1,84 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial3;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+import ec.vector.*;
+
+public class MyStatistics extends Statistics
+    {
+    // The parameter string and log number of the file for our readable population
+    public static final String P_POPFILE = "pop-file";
+    public int popLog;
+
+    // The parameter string and log number of the file for our best-genome-#3 individual
+    public static final String P_INFOFILE = "info-file";
+    public int infoLog;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // DO NOT FORGET to call super.setup(...) !!
+        super.setup(state,base);
+
+        // set up popFile
+        File popFile = state.parameters.getFile(
+            base.push(P_POPFILE),null);
+        if (popFile!=null) try
+                               {
+                               popLog = state.output.addLog(popFile,true);
+                               }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + 
+                    popFile + ":\n" + i);
+                }
+
+        // set up infoFile
+        File infoFile = state.parameters.getFile(
+            base.push(P_INFOFILE),null);
+        if (infoFile!=null) try
+                                {
+                                infoLog = state.output.addLog(infoFile,true);
+                                }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + 
+                    infoFile + ":\n" + i);
+                }
+
+        }
+
+    public void postEvaluationStatistics(final EvolutionState state)
+        {
+        // be certain to call the hook on super!
+        super.postEvaluationStatistics(state);
+
+        // write out a warning that the next generation is coming 
+        state.output.println("-----------------------\nGENERATION " + 
+            state.generation + "\n-----------------------", popLog);
+
+        // print out the population 
+        state.population.printPopulation(state,popLog);
+
+        // print out best genome #3 individual in subpop 0
+        int best = 0;
+        double best_val = ((DoubleVectorIndividual)state.population.subpops[0].individuals[0]).genome[3];
+        for(int y=1;y<state.population.subpops[0].individuals.length;y++)
+            {
+            // We'll be unsafe and assume the individual is a DoubleVectorIndividual
+            double val = ((DoubleVectorIndividual)state.population.subpops[0].individuals[y]).genome[3];
+            if (val > best_val)
+                {
+                best = y;
+                best_val = val;
+                }
+            }
+        state.population.subpops[0].individuals[best].printIndividualForHumans(state,infoLog);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/OddRosenbrock.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/OddRosenbrock.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/OddRosenbrock.java	(revision 6152)
@@ -0,0 +1,47 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial3;
+
+import ec.util.*;
+import ec.*;
+import ec.simple.*;
+import ec.vector.*;
+
+public class OddRosenbrock extends Problem implements SimpleProblemForm
+    {
+    public void setup(final EvolutionState state, final Parameter base) { }
+
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if( !( ind instanceof DoubleVectorIndividual ) )
+            state.output.fatal( "The individuals for this problem should be DoubleVectorIndividuals." );
+
+        double[] genome = ((DoubleVectorIndividual)ind).genome;
+        int len = genome.length;
+        double value = 0;
+
+        // Compute the Rosenbrock function for our genome
+        for( int i = 1 ; i < len ; i++ )
+            value += 100*(genome[i-1]*genome[i-1]-genome[i])*
+                (genome[i-1]*genome[i-1]-genome[i]) +
+                (1-genome[i-1])*(1-genome[i-1]);
+
+        // Rosenbrock is a minimizing function which does not drop below 0. 
+        // But SimpleFitness requires a maximizing function -- where 0 is worst
+        // and 1 is best.  To use SimpleFitness, we must convert the function.
+        // This is the Koza style of doing it:
+
+        value = 1.0 / ( 1.0 + value );
+        ((SimpleFitness)(ind.fitness)).setFitness( state, (float)value, value==1.0 );
+    
+        ind.evaluated = true;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/OurSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/OurSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/OurSelection.java	(revision 6152)
@@ -0,0 +1,72 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial3;
+import ec.*;
+import ec.util.*;
+
+public class OurSelection extends SelectionMethod
+    {
+    // We have to specify a default base
+    public static final String P_OURSELECTION = "our-selection";
+    public Parameter defaultBase() { return new Parameter(P_OURSELECTION); }
+
+    public static final String P_MIDDLEPROBABILITY = "middle-probability";  // our parameter name
+
+    public double middleProbability;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);   // always call super.setup(...) first if it exists!
+
+        Parameter def = defaultBase();
+
+        // gets a double between min (0.0) and max (1.0), from the parameter
+        // database, returning a value of min-1 (-1.0) if the parameter doesn't exist or was 
+        // outside this range.
+        middleProbability = state.parameters.getDoubleWithMax(base.push(P_MIDDLEPROBABILITY),
+            def.push(P_MIDDLEPROBABILITY),0.0,1.0);
+        if (middleProbability < 0.0)
+            state.output.fatal("Middle-Probability must be between 0.0 and 1.0",
+                base.push(P_MIDDLEPROBABILITY),def.push(P_MIDDLEPROBABILITY));
+        } 
+
+    public int produce(final int subpopulation, final EvolutionState state, final int thread)
+        {
+        //toss a coin
+        if (state.random[thread].nextBoolean(middleProbability))
+            {
+            //pick three individuals, return the middle one
+            Individual[] inds = state.population.subpops[subpopulation].individuals;
+            int one = state.random[thread].nextInt(inds.length);
+            int two = state.random[thread].nextInt(inds.length);
+            int three = state.random[thread].nextInt(inds.length);
+            // generally the betterThan(...) method imposes an ordering,
+            // so you shouldn't see any cycles here except in very unusual domains...
+            if (inds[two].fitness.betterThan(inds[one].fitness))
+                {
+                if (inds[three].fitness.betterThan(inds[two].fitness)) //  1 < 2 < 3
+                    return two;
+                else if (inds[three].fitness.betterThan(inds[one].fitness)) //  1 < 3 < 2
+                    return three;
+                else //  3 < 1 < 2
+                    return one;
+                }
+            else if (inds[three].fitness.betterThan(inds[one].fitness)) //  2 < 1 < 3
+                return one;
+            else if (inds[three].fitness.betterThan(inds[two].fitness)) //  2 < 3 < 1
+                return three;
+            else //  3 < 2 < 1
+                return two;
+            }
+        else        //select a random individual's index
+            {
+            return state.random[thread].nextInt(
+                state.population.subpops[subpopulation].individuals.length);
+            }
+        }
+    }  // close the class
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/README.pop.in
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/README.pop.in	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/README.pop.in	(revision 6152)
@@ -0,0 +1,2 @@
+Note that the first two lines of pop.in have already been deleted -- see the
+discussion in the index.html file.
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/pop.in
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/pop.in	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/pop.in	(revision 6152)
@@ -0,0 +1,422 @@
+Number of Individuals: i105|
+Individual Number: i0|
+Evaluated: T
+Fitness: f1002942528|0.0060940087|
+i5|d4603465286301627482|0.5873153914705072|d4597428611412532157|0.2292774615163732|d-4619408552638912050|-0.6426264709910414|d4600795048182272205|0.3954297036682533|d-4617176899879843007|-0.8903896985997123|
+Individual Number: i1|
+Evaluated: T
+Fitness: f984767828|0.0013608136|
+i5|d4609948961860618604|1.6142959608992795|d4597071599245998119|0.21936838333243822|d-4619365585285318550|-0.6473968055177128|d4600893587565985814|0.4008997382998144|d-4617120262697461339|-0.8966776889927145|
+Individual Number: i2|
+Evaluated: T
+Fitness: f1002928209|0.006087341|
+i5|d4603066580863426029|0.5430501957170556|d4597705872700541387|0.23697300816100006|d-4619540987300130110|-0.6279232699767692|d4600788631004767265|0.39507347875729876|d-4617056071501186785|-0.9038043434009387|
+Individual Number: i3|
+Evaluated: T
+Fitness: f1002440846|0.005860395|
+i5|d4603361207245802792|0.5757602950547254|d4596158419912791952|0.19402256529900486|d-4619360093446160218|-0.6480065221458247|d4600749562934678523|0.3929047652102892|d-4616855010631941882|-0.9261265840396227|
+Individual Number: i4|
+Evaluated: T
+Fitness: f1002108196|0.0057054926|
+i5|d4603328555441739939|0.5721352165881125|d4598040120587398396|0.24625025065902395|d-4619266771723560502|-0.6583673146586133|d4600867889913563632|0.39947323202991836|d-4616852436844573595|-0.9264123318392988|
+Individual Number: i5|
+Evaluated: T
+Fitness: f962149156|2.0716764E-4|
+i5|d-4610164952666077760|-2.675488892070206|d4610790210885611676|1.801090768297434|d-4616859102625016266|-0.9256722815468439|d4604105185599509066|0.6583584848654678|d-4616502699828985364|-0.965240940566273|
+Individual Number: i6|
+Evaluated: T
+Fitness: f950399897|7.913187E-5|
+i5|d4614681958071338210|3.3304644692403693|d4607292432363260573|1.0244279181867235|d-4611591335175816756|-2.042047810376266|d4600854465421021014|0.3987280229941822|d-4617288085305535575|-0.8780456366390484|
+Individual Number: i7|
+Evaluated: T
+Fitness: f999136950|0.0043218983|
+i5|d4607323025077215248|1.0312208652703738|d4597061954899431321|0.21910069894204012|d-4619431450518189519|-0.6400842957121481|d4600737002083750190|0.39220749791481324|d-4617219837939455705|-0.8856226163582378|
+Individual Number: i8|
+Evaluated: T
+Fitness: f997485014|0.0037294528|
+i5|d4607722241959996267|1.1198648202868877|d4597394653996928031|0.22833495389986155|d-4619583473304655290|-0.6232063759319508|d4600929921796167619|0.4029166932463079|d-4617097594016732123|-0.8991944181210597|
+Individual Number: i9|
+Evaluated: T
+Fitness: f1002982637|0.006112686|
+i5|d4603007992576185665|0.5365455891702952|d4596885925159102026|0.21421489217373085|d-4619490296363220521|-0.6335510945064539|d4600761001690253439|0.3935397437009058|d-4617058913237940046|-0.9034888472435993|
+Individual Number: i10|
+Evaluated: T
+Fitness: f958755871|1.5778885E-4|
+i5|d-4609793706054378785|-2.8403555065191166|d4597416855994941807|0.22895118313455096|d-4619419304902007896|-0.6414327299854579|d4600805580542086767|0.3960143670867415|d-4616517203968648997|-0.9636306575855785|
+Individual Number: i11|
+Evaluated: T
+Fitness: f996294526|0.0034522708|
+i5|d4607871808293345408|1.1530752176854833|d4597251479893734058|0.22436107425246138|d-4619587658652875823|-0.6227417089358999|d4601000998098479286|0.40686222061288946|d-4616921656205928324|-0.9187274389667119|
+Individual Number: i12|
+Evaluated: T
+Fitness: f999706091|0.0045869253|
+i5|d4607281015450521272|1.0218928543080619|d4598068486774030802|0.24703757049702674|d-4619366392050192780|-0.6473072366238299|d4600818416476774451|0.39672690459838406|d-4617625974088507956|-0.8405324459771975|
+Individual Number: i13|
+Evaluated: T
+Fitness: f1001100768|0.0052363724|
+i5|d4605232231864168482|0.7834857561497339|d4597239703533141850|0.22403421458556744|d-4619501625259844958|-0.632293334318849|d4600843768807665906|0.3981342416725645|d-4616573480441203316|-0.9573827140281295|
+Individual Number: i14|
+Evaluated: T
+Fitness: f992169565|0.0024918534|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4619547152334911676|-0.6272388136205582|d4600824642072891008|0.397072494605915|d-4617110792264153930|-0.8977291183038207|
+Individual Number: i15|
+Evaluated: T
+Fitness: f999715774|0.0045914343|
+i5|d4607004595175316441|0.9802576117534684|d4597158781056646721|0.22178816467020293|d-4619358289251685437|-0.648206827970505|d4600786802579442633|0.39497198076258805|d-4617164625456901147|-0.8917524332961163|
+Individual Number: i16|
+Evaluated: T
+Fitness: f933994441|2.0459194E-5|
+i5|d4616999486609759043|4.719307773345295|d4596467428920049610|0.2025992881658552|d-4619570892586945639|-0.6246031161787072|d4600991869047158063|0.40635545646439913|d-4617248934522861287|-0.8823922466747575|
+Individual Number: i17|
+Evaluated: T
+Fitness: f999127517|0.0043175058|
+i5|d4607281015450521272|1.0218928543080619|d4598068486774030802|0.24703757049702674|d-4619301567396522226|-0.65450421893067|d4600808264354989711|0.3961633486306732|d-4617074460792606220|-0.9017627219268989|
+Individual Number: i18|
+Evaluated: T
+Fitness: f991921099|0.002434003|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4619375673288838661|-0.6462768121396602|d4600830584446936330|0.39740236263021755|d-4616985286638798535|-0.9116630418027746|
+Individual Number: i19|
+Evaluated: T
+Fitness: f974400157|5.652102E-4|
+i5|d4603451916970419896|0.585831097537457|d4610680635906249840|1.7767602352953666|d-4619350366049646486|-0.649086480103745|d4600826686862169915|0.39718600321281244|d-4617158418956705107|-0.8924414932381147|
+Individual Number: i20|
+Evaluated: T
+Fitness: f1000925870|0.005154929|
+i5|d4605122150270126213|0.7712642441204173|d4596541338025592541|0.20465067793343553|d-4619066753601313482|-0.6805737871247064|d4601052184095099679|0.40970361421220675|d-4616783403771987443|-0.9340765425038754|
+Individual Number: i21|
+Evaluated: T
+Fitness: f991996341|0.0024515216|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4619547152334911676|-0.6272388136205582|d4601060472001014356|0.4101636854108268|d-4616928761501195583|-0.9179385927264648|
+Individual Number: i22|
+Evaluated: T
+Fitness: f999326537|0.0044101817|
+i5|d4607075044356793760|0.9880790420876799|d4598110783424829987|0.24821153838657137|d-4619625302898287448|-0.6185623581358373|d4600952942770604535|0.4041946140397665|d-4616683483602119279|-0.9451699098250846|
+Individual Number: i23|
+Evaluated: T
+Fitness: f970508610|4.134868E-4|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4611643915661006887|-2.0186973842546476|d4600968602668937425|0.40506391302438965|d-4617017412102921494|-0.9080963988081667|
+Individual Number: i24|
+Evaluated: T
+Fitness: f1001594631|0.005466345|
+i5|d4604842584585301016|0.7402262181016139|d4596735728585104556|0.21004609980693567|d-4619751946758666363|-0.6045020651638288|d4601032924276798428|0.40863447952579945|d-4616644719180574528|-0.9494736251586104|
+Individual Number: i25|
+Evaluated: T
+Fitness: f998357233|0.0039588143|
+i5|d4607592865208800861|1.0911374106812197|d4596261106554313071|0.19687269214245925|d-4619488626038149894|-0.6337365378416557|d4600953774567804846|0.4042407880599467|d-4617485220858243116|-0.8561591936802366|
+Individual Number: i26|
+Evaluated: T
+Fitness: f997220832|0.0036679432|
+i5|d4607722241959996267|1.1198648202868877|d4597394653996928031|0.22833495389986155|d-4619217573704401812|-0.663829392022206|d4600975224140327324|0.4054314785240878|d-4617175015360572792|-0.8905989222681265|
+Individual Number: i27|
+Evaluated: T
+Fitness: f999803950|0.0046324944|
+i5|d4607004595175316441|0.9802576117534684|d4596768825563420507|0.21096472549123288|d-4619524578245133770|-0.6297450410436969|d4601028169180439587|0.40837051865270463|d-4617272678561059056|-0.8797561288842832|
+Individual Number: i28|
+Evaluated: T
+Fitness: f956419188|1.2378563E-4|
+i5|d4612816832727769786|2.5021824291437413|d-4612709291657016553|-1.7727876999967458|d-4618747206166060452|-0.7160506791324894|d4600989488132731779|0.406223289163613|d-4616815860816194663|-0.9304730867248622|
+Individual Number: i29|
+Evaluated: T
+Fitness: f955887621|1.19060314E-4|
+i5|d-4609333607232807595|-3.0446804286436113|d4596806048951590538|0.21199788205625608|d-4619578396555546651|-0.6237700083070165|d4601082408941935662|0.4113814302558606|d-4616511171857047247|-0.9643003565043157|
+Individual Number: i30|
+Evaluated: T
+Fitness: f1001950775|0.0056321877|
+i5|d-4628084630732595479|-0.16984707617142838|d4596757444987961732|0.21064885106853748|d-4619893160464345036|-0.5888241944201185|d4601018138417615969|0.4078136994606379|d-4616507847751877054|-0.964669406313938|
+Individual Number: i31|
+Evaluated: T
+Fitness: f998092227|0.0038708306|
+i5|d4607569706066251136|1.0859950480233636|d4597303234003109185|0.22579753934864225|d-4619217770775733576|-0.6638075127092042|d4600930093420425010|0.4029262203064149|d-4617150541437145812|-0.8933160735972812|
+Individual Number: i32|
+Evaluated: T
+Fitness: f954778909|1.1099337E-4|
+i5|d-4610164952666077760|-2.675488892070206|d-4613005361611756440|-1.7070469638663557|d-4625833811890978368|-0.2323198487270144|d4600993565273768838|0.40644961595631235|d-4616649039645294724|-0.9489939572176662|
+Individual Number: i33|
+Evaluated: T
+Fitness: f998470479|0.0040115486|
+i5|d4607323025077215248|1.0312208652703738|d4597912769139995296|0.24271553793086742|d-4619170533515456137|-0.6690519021072266|d4600799624781015803|0.39568375593323396|d-4616579587690227969|-0.9567046731797005|
+Individual Number: i34|
+Evaluated: T
+Fitness: f998322504|0.0039426424|
+i5|d4607266577901543511|1.0186870744492091|d4597366688722664121|0.2275587616154178|d-4618729123909712068|-0.7180582128660045|d4600989756940412320|0.40623821098741963|d-4616708541524144083|-0.9423879216269647|
+Individual Number: i35|
+Evaluated: T
+Fitness: f997723263|0.0037849245|
+i5|d4607601365309334843|1.0930248121461108|d4596208455266632172|0.19541132534597183|d-4619580601954007706|-0.6235251598920228|d4600944315826481141|0.40371572243986914|d-4616968342653121218|-0.9135442021055622|
+Individual Number: i36|
+Evaluated: T
+Fitness: f994305006|0.0029890495|
+i5|d-4616159353555632988|-1.006720068751556|d-4623878665048503194|-0.3231721495059844|d4600654364797301107|0.3876202070093974|d4601769529275318104|0.44952427099632564|d-4616689710807281412|-0.9444785511700782|
+Individual Number: i37|
+Evaluated: T
+Fitness: f984896755|0.0013758227|
+i5|d4609948961860618604|1.6142959608992795|d4596748183391637606|0.21039179013144177|d-4619956981170243028|-0.5817386727065403|d4600990538772962687|0.4062816114123606|d-4617302971007017112|-0.8763929917867985|
+Individual Number: i38|
+Evaluated: T
+Fitness: f950108437|7.701122E-5|
+i5|d4614681958071338210|3.3304644692403693|d-4626068941317202416|-0.22579369615799338|d-4619899976070461143|-0.5880675101364307|d4601067320232894478|0.410543838646391|d-4616691839776303761|-0.9442421881273456|
+Individual Number: i39|
+Evaluated: T
+Fitness: f950096401|7.692364E-5|
+i5|d4614681958071338210|3.3304644692403693|d-4626068941317202416|-0.22579369615799338|d-4619178883580682066|-0.6681248586401318|d4600867678276422773|0.399461483808586|d-4616456949996127587|-0.9703201923474186|
+Individual Number: i40|
+Evaluated: T
+Fitness: f970479304|4.1263388E-4|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4611643915661006887|-2.0186973842546476|d4600892499614671478|0.40083934486987205|d-4616907631440750358|-0.9202845006882658|
+Individual Number: i41|
+Evaluated: T
+Fitness: f1002462182|0.00587033|
+i5|d-4627520237597454353|-0.18551213251077978|d4597111775340633547|0.2204834939650325|d-4619938864176744608|-0.5837500630384334|d4600790523637554024|0.3951785409821498|d-4616707214527483723|-0.942535247851558|
+Individual Number: i42|
+Evaluated: T
+Fitness: f946221460|5.4882446E-5|
+i5|d4615512666968120690|3.699373326827918|d4598295210710463456|0.2566608477171126|d-4619424672198650109|-0.64083684035424|d4600848662807237302|0.398405913222898|d-4616519741978557737|-0.9633488818818375|
+Individual Number: i43|
+Evaluated: T
+Fitness: f970450009|4.1178128E-4|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4611643915661006887|-2.0186973842546476|d4600918716005282381|0.4022946468938116|d-4616667704699089482|-0.9469217199697855|
+Individual Number: i44|
+Evaluated: T
+Fitness: f1001193523|0.0052795648|
+i5|d-4625399512283782292|-0.244374084314383|d4597024398379959067|0.21805829612596814|d-4619238476772858532|-0.6615086852336094|d4600848611448701412|0.3984030622514452|d-4616349193541499861|-0.9822835620453864|
+Individual Number: i45|
+Evaluated: T
+Fitness: f971023067|4.2845946E-4|
+i5|d-4615962134454270927|-1.0505115061971646|d4607292083170974110|1.024350381923433|d-4611643915661006887|-2.0186973842546476|d4603373667229817468|0.5771436311686808|d-4617020706875972240|-0.9077306055179815|
+Individual Number: i46|
+Evaluated: T
+Fitness: f996388364|0.0034741191|
+i5|d4607722241959996267|1.1198648202868877|d4597394653996928031|0.22833495389986155|d-4619446080116448685|-0.6384600840293139|d4600914793442534363|0.4020769009198923|d-4616372269504619078|-0.9797216154883508|
+Individual Number: i47|
+Evaluated: T
+Fitness: f1000020216|0.004733201|
+i5|d4603093128330273048|0.545997556610959|d4601924066801289080|0.4581028269714049|d-4619564157484471824|-0.6253508627626712|d4600883000916357359|0.4003120611912569|d-4616196266921757262|-0.9992618274770193|
+Individual Number: i48|
+Evaluated: T
+Fitness: f965305554|2.6205793E-4|
+i5|d4612816832727769786|2.5021824291437413|d4597423939932535601|0.2291478019000919|d-4618895460311084209|-0.6995911626023402|d4600932143287545981|0.4030400107901711|d-4617071669861970582|-0.9020725774720806|
+Individual Number: i49|
+Evaluated: T
+Fitness: f933268242|1.9138246E-5|
+i5|d4617089191878805437|4.798982057445696|d4596833486924218988|0.21275943878028458|d-4619492584468544535|-0.6332970637851051|d4600853025536343962|0.3986480933381188|d-4616656074894246490|-0.9482128876806442|
+Individual Number: i50|
+Evaluated: T
+Fitness: f998491677|0.0040214197|
+i5|d4607288669818105134|1.0235924653341715|d4597290151363504168|0.22543442315583317|d-4619079017818461388|-0.6792121854990456|d4600805841829386437|0.39602887144554827|d-4616638594102786568|-0.9501536453973918|
+Individual Number: i51|
+Evaluated: T
+Fitness: f997675513|0.0037738068|
+i5|d4607722241959996267|1.1198648202868877|d4597394653996928031|0.22833495389986155|d-4619583473304655290|-0.6232063759319508|d4600785216475597053|0.3948839343121476|d-4617174208353284489|-0.890688518075378|
+Individual Number: i52|
+Evaluated: T
+Fitness: f954526465|1.091566E-4|
+i5|d4614196878660830842|3.115045937113618|d4597382068541682646|0.22798563734514116|d-4619554080675821288|-0.6264696132605279|d4600859512734970934|0.39900820520216784|d-4616460969917488054|-0.9698738914222613|
+Individual Number: i53|
+Evaluated: T
+Fitness: f1002243943|0.0057687047|
+i5|d-4626839014744543752|-0.20441986491583441|d4597108238463778761|0.22038532591204632|d-4619597039229499711|-0.6217002557206898|d4600773747855895425|0.3942472980294767|d-4616764022597002433|-0.9362282851751401|
+Individual Number: i54|
+Evaluated: T
+Fitness: f998706566|0.004121485|
+i5|d4607210208404627236|1.006170531776612|d4597485361119228654|0.2308525822917526|d-4618899420302698762|-0.6991515152155603|d4600903858971250933|0.40146991583084396|d-4616809046016714871|-0.931229681453929|
+Individual Number: i55|
+Evaluated: T
+Fitness: f950972333|8.329689E-5|
+i5|d4614681958071338210|3.3304644692403693|d4597251644340825365|0.22436563857613892|d-4619084539948850088|-0.6785991058687939|d4600952936591142171|0.40419427101069666|d-4616356802215115983|-0.9814388295818387|
+Individual Number: i56|
+Evaluated: T
+Fitness: f996316218|0.0034573213|
+i5|d4607867319140915480|1.1520784256077317|d4597146783817902082|0.22145517440304735|d-4619853036654801899|-0.593278832139165|d4600815341566434474|0.39655621278547903|d-4616706689993435878|-0.9425934828292697|
+Individual Number: i57|
+Evaluated: T
+Fitness: f951815272|8.9430076E-5|
+i5|d-4609333607232807595|-3.0446804286436113|d4598494456522401392|0.26772121211579414|d-4611024989915100956|-2.293555629709873|d4600820639671337490|0.3968503166879894|d-4616596356422808226|-0.9548429698792622|
+Individual Number: i58|
+Evaluated: T
+Fitness: f996902985|0.0035939387|
+i5|d4607673597740204489|1.109063633721336|d4596247933906514709|0.19650707772043377|d-4619519994714409432|-0.6302539151781206|d4600854915872635254|0.39875302808186264|d-4616679593353571708|-0.9456018141759874|
+Individual Number: i59|
+Evaluated: T
+Fitness: f965294494|2.6173604E-4|
+i5|d4612816832727769786|2.5021824291437413|d4597423939932535601|0.2291478019000919|d-4618895460311084209|-0.6995911626023402|d4600793576534456177|0.3953480108037786|d-4616825970953214243|-0.9293506360347369|
+Individual Number: i60|
+Evaluated: T
+Fitness: f1002275044|0.005783187|
+i5|d4604822182046706781|0.7379610812908016|d4597132252399973810|0.2210518465339369|d-4619646692594088635|-0.6161876248590167|d4600847230349791269|0.3983263958609789|d-4617028555263940309|-0.9068592594151473|
+Individual Number: i61|
+Evaluated: T
+Fitness: f1001705125|0.005517798|
+i5|d4605267225156679605|0.7873707920550631|d4595620681608576345|0.1790973291349285|d-4619389889952380755|-0.644698445419882|d4600929019966212973|0.4028666316273107|d-4617160607949081986|-0.8921984662643607|
+Individual Number: i62|
+Evaluated: T
+Fitness: f951941061|9.034531E-5|
+i5|d4614535401338892518|3.265380205730355|d4597043807396838633|0.21859700456159395|d-4619666769702605513|-0.6139586180446831|d4600861715866874000|0.39913050359042135|d-4617308054554537811|-0.8758286046363729|
+Individual Number: i63|
+Evaluated: T
+Fitness: f996294534|0.0034522726|
+i5|d4607867319140915480|1.1520784256077317|d4597146783817902082|0.22145517440304735|d-4619392876881698595|-0.6443668296497226|d4600947876788330045|0.4039133955315924|d-4617024165097986755|-0.9073466657475034|
+Individual Number: i64|
+Evaluated: T
+Fitness: f998575745|0.004060567|
+i5|d4607266577901543511|1.0186870744492091|d4597366688722664121|0.2275587616154178|d-4618729123909712068|-0.7180582128660045|d4600989756940412320|0.40623821098741963|d-4617012736267232322|-0.908615520852315|
+Individual Number: i65|
+Evaluated: T
+Fitness: f996681532|0.0035423776|
+i5|d4607867319140915480|1.1520784256077317|d4596598919688117744|0.20624889012172742|d-4619825015643415392|-0.5963897893406234|d4600916610515037460|0.40217776870640987|d-4617162920674807399|-0.8919417021293611|
+Individual Number: i66|
+Evaluated: T
+Fitness: f936534310|2.5079189E-5|
+i5|d4616736347930405619|4.485593676955193|d4596278209859896530|0.19734740423385816|d-4619590693009453659|-0.6224048276821362|d4600926987099634133|0.4027537848632197|d-4616801269988828832|-0.9320929939738498|
+Individual Number: i67|
+Evaluated: T
+Fitness: f1000618366|0.0050117364|
+i5|d4605122150270126213|0.7712642441204173|d4596541338025592541|0.20465067793343553|d-4619066753601313482|-0.6805737871247064|d4600921337603637821|0.40244017483658806|d-4616509935352984225|-0.9644376360323966|
+Individual Number: i68|
+Evaluated: T
+Fitness: f956522215|1.2528487E-4|
+i5|d4612816832727769786|2.5021824291437413|d-4612709291657016553|-1.7727876999967458|d-4619810308428775184|-0.5980226181727897|d4600831782381990890|0.39746886138419646|d-4616986261345387403|-0.9115548276330531|
+Individual Number: i69|
+Evaluated: T
+Fitness: f954376926|1.0806856E-4|
+i5|d-4610164952666077760|-2.675488892070206|d-4613005361611756440|-1.7070469638663557|d-4619532216730386071|-0.6288969988236605|d4600895297988496179|0.4009946858224566|d-4617028890016021267|-0.9068220944683653|
+Individual Number: i70|
+Evaluated: T
+Fitness: f951000410|8.3501174E-5|
+i5|d4614681958071338210|3.3304644692403693|d4597786115479789318|0.23920019268802423|d-4618549356150149411|-0.7380164434411786|d4600837733229555856|0.39779919978332945|d-4616682450804931889|-0.9452845733468055|
+Individual Number: i71|
+Evaluated: T
+Fitness: f946227139|5.4903107E-5|
+i5|d4615512666968120690|3.699373326827918|d4598386604656917190|0.2617342309003273|d-4619148863601672595|-0.6714577458296397|d4600895949236520475|0.4010308373500224|d-4616473349595105105|-0.9684994711094727|
+Individual Number: i72|
+Evaluated: T
+Fitness: f998901380|0.0042122025|
+i5|d4607288669818105134|1.0235924653341715|d4598044267272641740|0.2463653442948498|d-4619325322230901543|-0.6518669025232625|d4600849199014177429|0.3984356786874426|d-4616855618944374954|-0.9260590477926864|
+Individual Number: i73|
+Evaluated: T
+Fitness: f946227139|5.4903107E-5|
+i5|d4615512666968120690|3.699373326827918|d4598386604656917190|0.2617342309003273|d-4619148863601672595|-0.6714577458296397|d4600895949236520475|0.4010308373500224|d-4616473349595105105|-0.9684994711094727|
+Individual Number: i74|
+Evaluated: T
+Fitness: f1002016087|0.005662601|
+i5|d4605194042536186540|0.7792458890276825|d4596453532615936263|0.20221358824625943|d-4619352048641569497|-0.6488996748743475|d4600883618657021162|0.40034635268666696|d-4617288307245902436|-0.8780209963085102|
+Individual Number: i75|
+Evaluated: T
+Fitness: f956436577|1.2403868E-4|
+i5|d4612816832727769786|2.5021824291437413|d-4612709291657016553|-1.7727876999967458|d-4618747206166060452|-0.7160506791324894|d4600839914055959571|0.3979202599676352|d-4617466830151550891|-0.8582009722811202|
+Individual Number: i76|
+Evaluated: T
+Fitness: f999822493|0.004641129|
+i5|d4607171733522810357|0.998813695922023|d4597510884328586090|0.23156099365902644|d-4619549747939083073|-0.6269506436691684|d4601032476294121503|0.4086096114916717|d-4617433771055479593|-0.8618712692442853|
+Individual Number: i77|
+Evaluated: T
+Fitness: f951000410|8.3501174E-5|
+i5|d4614681958071338210|3.3304644692403693|d4597786115479789318|0.23920019268802423|d-4618549356150149411|-0.7380164434411786|d4600837733229555856|0.39779919978332945|d-4616682450804931889|-0.9452845733468055|
+Individual Number: i78|
+Evaluated: T
+Fitness: f962380259|2.1053063E-4|
+i5|d-4610164952666077760|-2.675488892070206|d4610790210885611676|1.801090768297434|d-4616859102625016266|-0.9256722815468439|d4600859784526300895|0.39902329265178865|d-4617567281025893728|-0.8470486849272056|
+Individual Number: i79|
+Evaluated: T
+Fitness: f1001253496|0.005307492|
+i5|d4605510604886219593|0.8143913700012969|d4596625661848584843|0.20699113417869727|d-4619668086226169138|-0.6138124545674033|d4600908295443016131|0.40171618948593507|d-4616792132762043440|-0.9331074299296862|
+Individual Number: i80|
+Evaluated: T
+Fitness: f956495553|1.2489689E-4|
+i5|d4612816832727769786|2.5021824291437413|d-4612709291657016553|-1.7727876999967458|d-4619782709930907460|-0.6010866669505712|d4600968676719573867|0.40506802366046796|d-4616163559429719369|-1.0057861771016812|
+Individual Number: i81|
+Evaluated: T
+Fitness: f995924705|0.003366165|
+i5|d4607867319140915480|1.1520784256077317|d4597146783817902082|0.22145517440304735|d-4619319627125036554|-0.6524991862891614|d4600896866870728598|0.40108177628132446|d-4616746358142612334|-0.938189433573273|
+Individual Number: i82|
+Evaluated: T
+Fitness: f995610769|0.0032930712|
+i5|d4607871808293345408|1.1530752176854833|d4597251479893734058|0.22436107425246138|d-4619587658652875823|-0.6227417089358999|d4601000998098479286|0.40686222061288946|d-4616356367981874039|-0.9814870391561651|
+Individual Number: i83|
+Evaluated: T
+Fitness: f1001062359|0.005218487|
+i5|d4605281205607145566|0.7889229338552572|d4596652655191646984|0.20774034995317714|d-4619991649045387995|-0.5778897653864631|d4600855769955222755|0.3988004391895414|d-4616323333224138126|-0.9851546340212975|
+Individual Number: i84|
+Evaluated: T
+Fitness: f933168213|1.8956294E-5|
+i5|d-4606271152038354166|-4.809367472299309|d4596693017057077421|0.20886061676111947|d-4619792060401949726|-0.6000485561263498|d4600872607906448520|0.3997351332464594|d-4616178037924328977|-1.0025713054861816|
+Individual Number: i85|
+Evaluated: T
+Fitness: f965305554|2.6205793E-4|
+i5|d4612816832727769786|2.5021824291437413|d4597423939932535601|0.2291478019000919|d-4618895460311084209|-0.6995911626023402|d4600932143287545981|0.4030400107901711|d-4617071669861970582|-0.9020725774720806|
+Individual Number: i86|
+Evaluated: T
+Fitness: f950981391|8.336279E-5|
+i5|d4614681958071338210|3.3304644692403693|d4597786115479789318|0.23920019268802423|d-4618549356150149411|-0.7380164434411786|d4600837733229555856|0.39779919978332945|d-4616045710912338695|-1.0319538045844736|
+Individual Number: i87|
+Evaluated: T
+Fitness: f941994801|3.950595E-5|
+i5|d-4607172859249611992|-4.008490586372126|d4597009783468741392|0.21765265085255026|d-4619622824593223284|-0.6188375052702653|d4600907430699550301|0.40166818658062714|d-4616982178349990786|-0.9120081311829293|
+Individual Number: i88|
+Evaluated: T
+Fitness: f1001710448|0.0055202767|
+i5|d-4625834429505104059|-0.2323027064914475|d4596167185742504623|0.19426586594842862|d-4620169343617167752|-0.5581617048923837|d4600879975457196356|0.40014411447022646|d-4616144299907590165|-1.0100626500839052|
+Individual Number: i89|
+Evaluated: T
+Fitness: f962149156|2.0716764E-4|
+i5|d-4610164952666077760|-2.675488892070206|d4610790210885611676|1.801090768297434|d-4616859102625016266|-0.9256722815468439|d4604105185599509066|0.6583584848654678|d-4616502699828985364|-0.965240940566273|
+Individual Number: i90|
+Evaluated: T
+Fitness: f951012840|8.3591614E-5|
+i5|d4614681958071338210|3.3304644692403693|d4597786115479789318|0.23920019268802423|d-4619736092990895540|-0.6062621869644516|d4600826861002544935|0.39719566994550565|d-4616326387342410916|-0.9848155587786596|
+Individual Number: i91|
+Evaluated: T
+Fitness: f941993862|3.9502534E-5|
+i5|d-4607172859249611992|-4.008490586372126|d4597009783468741392|0.21765265085255026|d-4620138892421555709|-0.5615424667419692|d4600990309752031728|0.406268898196827|d-4616649576337123653|-0.9489343724551057|
+Individual Number: i92|
+Evaluated: T
+Fitness: f933989866|2.0450872E-5|
+i5|d4616999486609759043|4.719307773345295|d4596452519145550506|0.20218545879233335|d-4619422265633085672|-0.6411040228042308|d4600900038231579102|0.4012578221731057|d-4616554542206385062|-0.9594852804622278|
+Individual Number: i93|
+Evaluated: T
+Fitness: f950202819|7.7697936E-5|
+i5|d4614810438820890626|3.3875213837900455|d4596864210034566577|0.2136121763926844|d-4619819217078054982|-0.5970335594179155|d4600926130799262158|0.40270625064377163|d-4616170564811408855|-1.0042306698920902|
+Individual Number: i94|
+Evaluated: T
+Fitness: f950973547|8.330572E-5|
+i5|d4614681958071338210|3.3304644692403693|d4597059612015754892|0.21903567085700038|d-4619798104782673062|-0.599377495061485|d4600889550606740077|0.40067564204460987|d-4616380194651634616|-0.9788417474193318|
+Individual Number: i95|
+Evaluated: T
+Fitness: f962384984|2.1059939E-4|
+i5|d-4633192367804036864|-0.07653944683014302|d-4610808005509666674|-2.389916062868969|d-4619424139830193419|-0.6408959451260602|d4600848333559160587|0.39838763628311885|d-4616673029716476702|-0.9463305242788034|
+Individual Number: i96|
+Evaluated: T
+Fitness: f954574496|1.0950607E-4|
+i5|d4614196878660830842|3.115045937113618|d4597939938323935344|0.24346963427013035|d-4619911379572344115|-0.5868014671012475|d4600881187895826669|0.4002114183343924|d-4616302871628141755|-0.9874263275208724|
+Individual Number: i97|
+Evaluated: T
+Fitness: f1002726124|0.0059932377|
+i5|d-4626197649992931910|-0.22222131277639595|d4596968516063020403|0.2165072502526005|d-4619894382552912356|-0.5886885153335615|d4600883424730753796|0.4003355876163115|d-4616881511584978915|-0.9231843872160003|
+Individual Number: i98|
+Evaluated: T
+Fitness: f1002450567|0.0058649215|
+i5|d-4628082954287484533|-0.1698936068704707|d4596593624573461270|0.20610192116648623|d-4619890843340569974|-0.5890814468367165|d4600948470786587245|0.4039463690586789|d-4616747426440503139|-0.93807082868172|
+Individual Number: i99|
+Evaluated: T
+Fitness: f1002648554|0.0059571164|
+i5|d-4627806336786647213|-0.17757128483156723|d4596307526123185491|0.1981610939963426|d-4620000125480576666|-0.5769486920351425|d4600920852640315430|0.4024132539642572|d-4616757301624789172|-0.9369744629850429|
+Individual Number: i100|
+Evaluated: T
+Fitness: f1002791303|0.006023589|
+i5|d4603256366686557892|0.5641206547758988|d4597336809842271884|0.22672945609138073|d-4619428897062754833|-0.6403677862137424|d4600813434778744902|0.3964503648056773|d-4617060625804638803|-0.9032987141455827|
+Individual Number: i101|
+Evaluated: T
+Fitness: f1001950054|0.005631852|
+i5|d4604938473422984995|0.7508720176417437|d4596700300440068424|0.20906277124846384|d-4619572681754522832|-0.624404478674796|d4601010490538544533|0.40738915688890504|d-4617006075643200375|-0.9093549986681789|
+Individual Number: i102|
+Evaluated: T
+Fitness: f1001922514|0.0056190277|
+i5|d-4627043164713823616|-0.19875356500655883|d4597107637485565401|0.22036864541580206|d-4619624948825781956|-0.6186016680806357|d4600835470431542761|0.39767358926061874|d-4616585816051106127|-0.95601318621444|
+Individual Number: i103|
+Evaluated: T
+Fitness: f1001901367|0.0056091803|
+i5|d4605211423592666225|0.7811755739372882|d4596503555138100036|0.2036019921426605|d-4619609904679664802|-0.6202719038211446|d4600882454341200434|0.4002817201750616|d-4617054004345776644|-0.9040338437541204|
+Individual Number: i104|
+Evaluated: T
+Fitness: f1001818479|0.0055705826|
+i5|d-4627234362512848531|-0.19344676003818098|d4596712920042560961|0.20941303557968463|d-4619783876687464040|-0.6009571309512465|d4600874293302943614|0.39982869154618317|d-4616412234654735574|-0.9752845925041573|
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/tutorial3.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/tutorial3.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial3/tutorial3.params	(revision 6152)
@@ -0,0 +1,57 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 =	../../es/es.params
+
+#                    ...the default option is ec.es.MuCommaLambdaBreeder
+breed =              ec.es.MuPlusLambdaBreeder
+es.mu.0 =            5 
+es.lambda.0 =        100 
+pop.subpop.0.size =  105 
+generations =        200
+
+pop.subpop.0.species.pipe = ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0 = ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.es.ESSelection
+
+# Use our own custom selection operator class
+pop.subpop.0.species.pipe.source.1 = ec.app.tutorial3.OurSelection
+
+# We'll talk about this parameter later on
+pop.subpop.0.species.pipe.source.1.middle-probability = 0.5
+
+eval.problem = ec.app.tutorial3.OddRosenbrock
+# Doubles and floats use the FloatVectorSpecies
+pop.subpop.0.species =                  ec.vector.FloatVectorSpecies
+pop.subpop.0.species.ind =              ec.vector.DoubleVectorIndividual
+pop.subpop.0.species.fitness = 		ec.simple.SimpleFitness
+
+# Per-gene mutation probability of 1.0
+pop.subpop.0.species.mutation-prob = 1.0
+# Use Gaussian Convolution with a standard deviation of 0.5
+pop.subpop.0.species.mutation-type = gauss
+pop.subpop.0.species.mutation-stdev = 0.5
+# One-point crossover
+pop.subpop.0.species.crossover-type = one
+pop.subpop.0.species.genome-size =      5
+pop.subpop.0.species.min-gene.0 = -5.12
+pop.subpop.0.species.max-gene.0 = 5.12
+pop.subpop.0.species.min-gene.1 = -3
+pop.subpop.0.species.max-gene.1 = 2
+pop.subpop.0.species.min-gene.2 = -7.6
+pop.subpop.0.species.max-gene.2 = 1.1
+pop.subpop.0.species.min-gene.3 = 0
+pop.subpop.0.species.max-gene.3 = 1.0
+pop.subpop.0.species.min-gene.4 = -10.3
+pop.subpop.0.species.max-gene.4 = 2.2
+# Because we need default min/max genes even if we don't use them
+pop.subpop.0.species.min-gene = -100
+pop.subpop.0.species.max-gene = 100
+
+# Add our statistics object
+stat.num-children      = 1
+stat.child.0           = ec.app.tutorial3.MyStatistics
+stat.child.0.pop-file  = pop.stat
+stat.child.0.info-file = info.stat
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Add.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Add.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Add.java	(revision 6152)
@@ -0,0 +1,46 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+public class Add extends GPNode
+    {
+    public String toString() { return "+"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        DoubleData rd = ((DoubleData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result + rd.x;
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/DoubleData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/DoubleData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/DoubleData.java	(revision 6152)
@@ -0,0 +1,19 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.gp.*;
+
+public class DoubleData extends GPData
+    {
+    public double x;    // return value
+
+    public void copyTo(final GPData gpd)   // copy my stuff to another DoubleData
+        { ((DoubleData)gpd).x = x; }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Mul.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Mul.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Mul.java	(revision 6152)
@@ -0,0 +1,45 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+public class Mul extends GPNode
+    {
+    public String toString() { return "*"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        DoubleData rd = ((DoubleData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result * rd.x;
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/MultiValuedRegression.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/MultiValuedRegression.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/MultiValuedRegression.java	(revision 6152)
@@ -0,0 +1,73 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+public class MultiValuedRegression extends GPProblem implements SimpleProblemForm
+    {
+    public double currentX;
+    public double currentY;
+    
+    public DoubleData input;
+
+    public Object clone()
+        {
+        MultiValuedRegression newobj = (MultiValuedRegression) (super.clone());
+        newobj.input = (DoubleData)(input.clone());
+        return newobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        // set up our input -- don't want to use the default base, it's unsafe here
+        input = (DoubleData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA), null, DoubleData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            int hits = 0;
+            double sum = 0.0;
+            double expectedResult;
+            double result;
+            for (int y=0;y<10;y++)
+                {
+                currentX = state.random[threadnum].nextDouble();
+                currentY = state.random[threadnum].nextDouble();
+                expectedResult = currentX*currentX*currentY + currentX*currentY + currentY;
+                ((GPIndividual)ind).trees[0].child.eval(
+                    state,threadnum,input,stack,((GPIndividual)ind),this);
+
+                result = Math.abs(expectedResult - input.x);
+                if (result <= 0.01) hits++;
+                sum += result;                  
+                }
+
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)sum);
+            f.hits = hits;
+            ind.evaluated = true;
+            }
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Sub.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Sub.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Sub.java	(revision 6152)
@@ -0,0 +1,45 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+public class Sub extends GPNode
+    {
+    public String toString() { return "-"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        DoubleData rd = ((DoubleData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result - rd.x;
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/X.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/X.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/X.java	(revision 6152)
@@ -0,0 +1,40 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+public class X extends GPNode
+    {
+    public String toString() { return "x"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        DoubleData rd = ((DoubleData)(input));
+        rd.x = ((MultiValuedRegression)problem).currentX;
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Y.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Y.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/Y.java	(revision 6152)
@@ -0,0 +1,40 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.tutorial4;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+public class Y extends GPNode
+    {
+    public String toString() { return "y"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        DoubleData rd = ((DoubleData)(input));
+        rd.x = ((MultiValuedRegression)problem).currentY;
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/tree.tex
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/tree.tex	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/tree.tex	(revision 6152)
@@ -0,0 +1,25 @@
+\documentclass[]{article}
+\usepackage{epic}	% required by ecltree and fancybox packages
+\usepackage{ecltree}	% to draw the GP trees
+\usepackage{fancybox}	% required by \Ovalbox
+
+\begin{document}
+
+% minimum distance between nodes on the same line
+\setlength{\GapWidth}{1em}    
+
+% draw with a thick dashed line, very nice looking
+\thicklines \drawwith{\dottedline{2}}   
+
+% draw an oval and center it with the rule.  You may want to fool with the
+% rule values, though these seem to work quite well for me.  If you make the
+% rule smaller than the text height, then the GP nodes may not line up with
+% each other horizontally quite right, so watch out.
+\newcommand{\gpbox}[1]{\Ovalbox{#1\rule[-.7ex]{0ex}{2.7ex}}}
+
+\begin{bundle}{\gpbox{+}}\chunk{\gpbox{y}}\chunk{\begin{bundle}{\gpbox{+}}\chunk{\begin{bundle}{\gpbox{*}}
+\chunk{\gpbox{x}}\chunk{\gpbox{y}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{*}}\chunk{\gpbox{y}}
+\chunk{\begin{bundle}{\gpbox{*}}\chunk{\gpbox{x}}\chunk{\gpbox{x}}\end{bundle}}\end{bundle}}\end{bundle}}
+\end{bundle}
+\end{document}
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/tutorial4.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/tutorial4.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/tutorial4/tutorial4.params	(revision 6152)
@@ -0,0 +1,31 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+# the next four items are already defined in koza.params, but we
+# put them here to be clear.
+
+# We have one function set, of class GPFunctionSet
+gp.fs.size = 1
+gp.fs.0 = ec.gp.GPFunctionSet
+# We'll call the function set "f0".
+gp.fs.0.name = f0
+
+# We have five functions in the function set.  They are:
+gp.fs.0.size = 5
+gp.fs.0.func.0 = ec.app.tutorial4.X
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.tutorial4.Y
+gp.fs.0.func.1.nc = nc0
+gp.fs.0.func.2 = ec.app.tutorial4.Add
+gp.fs.0.func.2.nc = nc2
+gp.fs.0.func.3 = ec.app.tutorial4.Sub
+gp.fs.0.func.3.nc = nc2
+gp.fs.0.func.4 = ec.app.tutorial4.Mul
+gp.fs.0.func.4.nc = nc2
+
+eval.problem = ec.app.tutorial4.MultiValuedRegression
+eval.problem.data = ec.app.tutorial4.DoubleData
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/TwoBox.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/TwoBox.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/TwoBox.java	(revision 6152)
@@ -0,0 +1,178 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox;
+import ec.util.*;
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+
+/* 
+ * TwoBox.java
+ * 
+ * Created: Mon Nov  1 15:46:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * TwoBox implements the TwoBox problem, with or without ADFs,
+ * as discussed in Koza-II.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt><br>
+ <font size=-1>classname, inherits or == ec.app.twobox.TwoBoxData</font></td>
+ <td valign=top>(the class for the prototypical GPData object for the TwoBox problem)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>(the size of the training set)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>range</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>(the range of dimensional values in the training set -- they'll be integers 1...range inclusive)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>species (the GPData object)</td></tr>
+ </table>
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class TwoBox extends GPProblem implements SimpleProblemForm
+    {
+    public static final String P_SIZE = "size";
+    public static final String P_RANGE= "range";
+
+    public int currentIndex;
+    public int trainingSetSize;
+    public int range;
+    
+    // these are read-only during evaluation-time, so
+    // they can be just light-cloned and not deep cloned.
+    // cool, huh?
+    
+    public double inputsl0[];
+    public double inputsw0[];
+    public double inputsh0[];
+    public double inputsl1[];
+    public double inputsw1[];
+    public double inputsh1[];
+    public double outputs[];
+
+    // we'll need to deep clone this one though.
+    public TwoBoxData input;
+
+    public final double func(final double l0, final double w0, 
+        final double h0, final double l1, 
+        final double w1, final double h1)
+        { return l0*w0*h0-l1*w1*h1; }
+
+    public Object clone()
+        {
+        // don't bother copying the inputs and outputs; they're read-only :-)
+        // don't bother copying the currentIndex; it's transitory
+        // but we need to copy our twobox data
+        TwoBox myobj = (TwoBox) (super.clone());
+
+        myobj.input = (TwoBoxData)(input.clone());
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state,
+        final Parameter base)
+        {
+        // very important, remember this
+        super.setup(state,base);
+
+        trainingSetSize = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (trainingSetSize<1) state.output.fatal("Training Set Size must be an integer greater than 0"); 
+
+        range = state.parameters.getInt(base.push(P_RANGE),null,1);
+        if (trainingSetSize<1) state.output.fatal("Range must be an integer greater than 0"); 
+
+        // Compute our inputs so they
+        // can be copied with clone later
+        
+        inputsl0 = new double[trainingSetSize];
+        inputsw0 = new double[trainingSetSize];
+        inputsh0 = new double[trainingSetSize];
+        inputsl1 = new double[trainingSetSize];
+        inputsw1 = new double[trainingSetSize];
+        inputsh1 = new double[trainingSetSize];
+        outputs = new double[trainingSetSize];
+        
+        for(int x=0;x<trainingSetSize;x++)
+            {
+            inputsl0[x] = state.random[0].nextInt(range)+1;
+            inputsw0[x] = state.random[0].nextInt(range)+1;
+            inputsh0[x] = state.random[0].nextInt(range)+1;
+            inputsl1[x] = state.random[0].nextInt(range)+1;
+            inputsw1[x] = state.random[0].nextInt(range)+1;
+            inputsh1[x] = state.random[0].nextInt(range)+1;
+            outputs[x] = func(inputsl0[x],inputsw0[x],inputsh0[x],
+                inputsl1[x],inputsw1[x],inputsh1[x]);
+            state.output.println("{" + inputsl0[x]+ "," + inputsw0[x]+ "," +
+                inputsh0[x]+ "," + inputsl1[x]+ "," +
+                inputsw1[x]+ "," + inputsh1[x]+ "," +
+                outputs[x] + "},",0);
+            }
+
+        // set up our input -- don't want to use the default base, it's unsafe
+        input = (TwoBoxData) state.parameters.getInstanceForParameterEq(
+            base.push(P_DATA), null, TwoBoxData.class);
+        input.setup(state,base.push(P_DATA));
+        }
+
+
+    public void evaluate(final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!ind.evaluated)  // don't bother reevaluating
+            {
+            int hits = 0;
+            double sum = 0.0;
+            double result;
+            for (int y=0;y<trainingSetSize;y++)
+                {
+                currentIndex = y;
+                ((GPIndividual)ind).trees[0].child.eval(
+                    state,threadnum,input,stack,((GPIndividual)ind),this);
+
+                final double HIT_LEVEL = 0.01;
+                final double PROBABLY_ZERO = 1.11E-15;
+                final double BIG_NUMBER = 1.0e15;  // the same as lilgp uses
+                    
+                result = Math.abs(outputs[y] - input.x);
+
+                // very slight math errors can creep in when evaluating
+                // two equivalent by differently-ordered functions, like
+                // x * (x*x*x + x*x)  vs. x*x*x*x + x*x
+
+                if (result<PROBABLY_ZERO)  // slightly off
+                    result = 0.0;
+
+                if (result > BIG_NUMBER)
+                    result = BIG_NUMBER;                    
+
+                if (result <= HIT_LEVEL) hits++;  // whatever!
+
+                sum += result;              }
+                
+            // the fitness better be KozaFitness!
+            KozaFitness f = ((KozaFitness)ind.fitness);
+            f.setStandardizedFitness(state,(float)sum);
+            f.hits = hits;
+            ind.evaluated = true;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/TwoBoxData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/TwoBoxData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/TwoBoxData.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox;
+import ec.gp.*;
+
+/* 
+ * TwoBoxData.java
+ * 
+ * Created: Wed Nov  3 18:32:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class TwoBoxData extends GPData
+    {
+    // return value
+    public double x;
+
+    public void copyTo(final GPData gpd) 
+        { ((TwoBoxData)gpd).x = x; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/adf.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/adf.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/adf.params	(revision 6152)
@@ -0,0 +1,116 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+# First, we're gonna change the number of trees in
+# the individual, to accommodate the ADFs
+# Each of our three trees uses a different tree constraints,
+# tc0, tc1, tc2
+
+pop.subpop.0.species.ind.numtrees = 2
+
+# "The result-producing branch" (Koza-II p. 84)
+pop.subpop.0.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.0.tc = tc0
+# "ADF0 body" (Koza-II p. 84)
+pop.subpop.0.species.ind.tree.1 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.1.tc = tc1
+
+
+# Now, let's define what tc0, and tc1 are.
+# Each has a different function set, f0 and f1
+
+gp.tc.size = 2
+
+gp.tc.0 = ec.gp.GPTreeConstraints
+gp.tc.0.name = tc0
+gp.tc.0.fset = f0
+gp.tc.0.returns = nil
+gp.tc.0.init = ec.gp.koza.HalfBuilder
+gp.tc.0.init.growp = 0.5
+gp.tc.0.init.min = 2
+gp.tc.0.init.max = 6
+
+gp.tc.1 = ec.gp.GPTreeConstraints
+gp.tc.1.name = tc1
+gp.tc.1.fset = f1
+gp.tc.1.returns = nil
+gp.tc.1.init = ec.gp.koza.HalfBuilder
+gp.tc.1.init.growp = 0.5
+gp.tc.1.init.min = 2
+gp.tc.1.init.max = 6
+
+
+
+
+# Now we define the two function sets f0 and f1
+
+gp.fs.size = 2
+gp.fs.0 = ec.gp.GPFunctionSet
+gp.fs.0.name = f0
+gp.fs.0.size = 11
+gp.fs.0.func.0 = ec.app.twobox.func.L0
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.twobox.func.W0
+gp.fs.0.func.1.nc = nc0
+gp.fs.0.func.2 = ec.app.twobox.func.H0
+gp.fs.0.func.2.nc = nc0
+gp.fs.0.func.3 = ec.app.twobox.func.L1
+gp.fs.0.func.3.nc = nc0
+gp.fs.0.func.4 = ec.app.twobox.func.W1
+gp.fs.0.func.4.nc = nc0
+gp.fs.0.func.5 = ec.app.twobox.func.H1
+gp.fs.0.func.5.nc = nc0
+gp.fs.0.func.6 = ec.app.twobox.func.Add
+gp.fs.0.func.6.nc = nc2
+gp.fs.0.func.7 = ec.app.twobox.func.Sub
+gp.fs.0.func.7.nc = nc2
+gp.fs.0.func.8 = ec.app.twobox.func.Mul
+gp.fs.0.func.8.nc = nc2
+gp.fs.0.func.9 = ec.app.twobox.func.Div
+gp.fs.0.func.9.nc = nc2
+gp.fs.0.func.10 = ec.gp.ADF
+# tree 1 (the "ADF0 body")
+gp.fs.0.func.10.tree = 1
+gp.fs.0.func.10.name = ADF0
+gp.fs.0.func.10.nc = nc3
+
+
+
+gp.fs.1 = ec.gp.GPFunctionSet
+gp.fs.1.name = f1
+gp.fs.1.size = 7
+gp.fs.1.func.0 = ec.app.twobox.func.Add
+gp.fs.1.func.0.nc = nc2
+gp.fs.1.func.1 = ec.app.twobox.func.Sub
+gp.fs.1.func.1.nc = nc2
+gp.fs.1.func.2 = ec.app.twobox.func.Mul
+gp.fs.1.func.2.nc = nc2
+gp.fs.1.func.3 = ec.app.twobox.func.Div
+gp.fs.1.func.3.nc = nc2
+gp.fs.1.func.4 = ec.gp.ADFArgument
+gp.fs.1.func.4.arg = 0
+gp.fs.1.func.4.name = ARG0
+gp.fs.1.func.4.nc = nc0
+gp.fs.1.func.5 = ec.gp.ADFArgument
+gp.fs.1.func.5.arg = 1
+gp.fs.1.func.5.name = ARG1
+gp.fs.1.func.5.nc = nc0
+gp.fs.1.func.6 = ec.gp.ADFArgument
+gp.fs.1.func.6.arg = 2
+gp.fs.1.func.6.name = ARG2
+gp.fs.1.func.6.nc = nc0
+
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.twobox.TwoBox
+eval.problem.data = ec.app.twobox.TwoBoxData
+
+# Define our training set size and range here
+eval.problem.size = 10
+eval.problem.range = 10
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Add.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Add.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Add.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Add.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Add extends GPNode
+    {
+    public String toString() { return "+"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        TwoBoxData rd = ((TwoBoxData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result + rd.x;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Div.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Div.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Div.java	(revision 6152)
@@ -0,0 +1,68 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Div.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Div extends GPNode
+    {
+    public String toString() { return "%"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+
+        // evaluate children[1] first to determine if the demoniator is 0
+        children[1].eval(state,thread,input,stack,individual,problem);
+        if (rd.x==0.0) 
+            // the answer is 1.0 since the denominator was 0.0
+            rd.x = 1.0;
+        else
+            {
+            double result;
+            result = rd.x;
+            
+            children[0].eval(state,thread,input,stack,individual,problem);
+            rd.x = rd.x / result;
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/H0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/H0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/H0.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * H0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class H0 extends GPNode
+    {
+    public String toString() { return "h0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+        TwoBox tb = ((TwoBox)problem);
+        rd.x = tb.inputsh0[tb.currentIndex];
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/H1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/H1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/H1.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * H1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class H1 extends GPNode
+    {
+    public String toString() { return "h1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+        TwoBox tb = ((TwoBox)problem);
+        rd.x = tb.inputsh1[tb.currentIndex];
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/L0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/L0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/L0.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * L0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class L0 extends GPNode
+    {
+    public String toString() { return "l0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+        TwoBox tb = ((TwoBox)problem);
+        rd.x = tb.inputsl0[tb.currentIndex];
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/L1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/L1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/L1.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * L1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class L1 extends GPNode
+    {
+    public String toString() { return "l1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+        TwoBox tb = ((TwoBox)problem);
+        rd.x = tb.inputsl1[tb.currentIndex];
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Mul.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Mul.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Mul.java	(revision 6152)
@@ -0,0 +1,63 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Mul.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Mul extends GPNode
+    {
+    public String toString() { return "*"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        if ( rd.x != 0 ) // safe to short-circuit
+            {
+            double result;
+            result = rd.x;
+            children[1].eval(state,thread,input,stack,individual,problem);
+            rd.x = result * rd.x;
+            }
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Sub.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Sub.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/Sub.java	(revision 6152)
@@ -0,0 +1,61 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * Sub.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Sub extends GPNode
+    {
+    public String toString() { return "-"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=2)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        double result;
+        TwoBoxData rd = ((TwoBoxData)(input));
+
+        children[0].eval(state,thread,input,stack,individual,problem);
+        result = rd.x;
+
+        children[1].eval(state,thread,input,stack,individual,problem);
+        rd.x = result - rd.x;
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/W0.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/W0.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/W0.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * W0.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class W0 extends GPNode
+    {
+    public String toString() { return "w0"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+        TwoBox tb = ((TwoBox)problem);
+        rd.x = tb.inputsw0[tb.currentIndex];
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/W1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/W1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/func/W1.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.app.twobox.func;
+import ec.*;
+import ec.app.twobox.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * W1.java
+ * 
+ * Created: Wed Nov  3 18:26:37 1999
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class W1 extends GPNode
+    {
+    public String toString() { return "w1"; }
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        if (children.length!=0)
+            state.output.error("Incorrect number of children for node " + 
+                toStringForError() + " at " +
+                individualBase);
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        TwoBoxData rd = ((TwoBoxData)(input));
+        TwoBox tb = ((TwoBox)problem);
+        rd.x = tb.inputsw1[tb.currentIndex];
+        }
+    }
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/noadf.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/noadf.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/app/twobox/noadf.params	(revision 6152)
@@ -0,0 +1,45 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../gp/koza/koza.params
+
+# Stolen from koza/params -- overwriting just
+# a little for readability
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+
+gp.fs.size = 1
+gp.fs.0.name = f0
+gp.fs.0.size = 10
+gp.fs.0.func.0 = ec.app.twobox.func.L0
+gp.fs.0.func.0.nc = nc0
+gp.fs.0.func.1 = ec.app.twobox.func.W0
+gp.fs.0.func.1.nc = nc0
+gp.fs.0.func.2 = ec.app.twobox.func.H0
+gp.fs.0.func.2.nc = nc0
+gp.fs.0.func.3 = ec.app.twobox.func.L1
+gp.fs.0.func.3.nc = nc0
+gp.fs.0.func.4 = ec.app.twobox.func.W1
+gp.fs.0.func.4.nc = nc0
+gp.fs.0.func.5 = ec.app.twobox.func.H1
+gp.fs.0.func.5.nc = nc0
+gp.fs.0.func.6 = ec.app.twobox.func.Add
+gp.fs.0.func.6.nc = nc2
+gp.fs.0.func.7 = ec.app.twobox.func.Sub
+gp.fs.0.func.7.nc = nc2
+gp.fs.0.func.8 = ec.app.twobox.func.Mul
+gp.fs.0.func.8.nc = nc2
+gp.fs.0.func.9 = ec.app.twobox.func.Div
+gp.fs.0.func.9.nc = nc2
+
+#
+# We specify our problem here
+#
+
+eval.problem = ec.app.twobox.TwoBox
+eval.problem.data = ec.app.twobox.TwoBoxData
+
+# Define our training set size and range here
+eval.problem.size = 10
+eval.problem.range = 10
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/BreedDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/BreedDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/BreedDefaults.java	(revision 6152)
@@ -0,0 +1,33 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.breed;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * BreedDefaults.java
+ * 
+ * Created: Thu Jan 20 17:12:49 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class BreedDefaults implements DefaultsForm 
+    {
+    public static final String P_BREED = "breed";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_BREED);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/BufferedBreedingPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/BufferedBreedingPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/BufferedBreedingPipeline.java	(revision 6152)
@@ -0,0 +1,139 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.breed;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * BufferedBreedingPipeline.java
+ * 
+ * Created: December 28, 1999
+ * By: Sean Luke
+ */
+
+/**
+ * If empty, a 
+ * BufferedBreedingPipeline makes a request of exactly <i>num-inds</i> 
+ * individuals from a single child source; it then uses these
+ * individuals to fill requests (returning min each time),
+ * until the buffer is emptied, at
+ * which time it grabs exactly <i>num-inds</i> more individuals, and so on.
+ *
+ * <p>What is this useful for?  Well, let's say for example that 
+ * you want to cross over two individuals, then cross
+ * them over again.  You'd like to hook up two CrossoverPipelines
+ * in series.  Unfortunately, CrossoverPipeline takes
+ * two sources; even if you set them to the same source, it requests
+ * <i>one</i> individual from the first source and then <i>one</i>
+ * from the second, where what you really want is for it to request
+ * <i>two</i> individuals from a single source (the other CrossoverPipeline).
+ * 
+ * <p>The solution to this is to hook a CrossoverPipeline as the
+ * source to a BufferedBreedingPipeline of buffer-size 2 (or some
+ * multiple of 2 actually).  Then the BufferedBreedingPipeline is
+ * set as both sources to another CrossoverPipeline.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ 1
+
+ <p><b>Number of Sources</b><br>
+ 1
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>num-inds</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the buffer size)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ breed.buffered
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class BufferedBreedingPipeline extends BreedingPipeline
+    {
+    public static final String P_BUFSIZE = "num-inds";
+    public static final String P_BUFFERED = "buffered";
+    public static final int INDS_PRODUCED = 1;
+    public static final int NUM_SOURCES = 1;
+
+    public Individual[] buffer;
+    public int currentSize;
+
+    public Parameter defaultBase()
+        {
+        return BreedDefaults.base().push(P_BUFFERED);
+        }
+
+    public int numSources() { return NUM_SOURCES; }    
+    public int typicalIndsProduced() { return INDS_PRODUCED;}
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        int bufsize = state.parameters.getInt(base.push(P_BUFSIZE),
+            def.push(P_BUFSIZE),1);
+        if (bufsize == 0)
+            state.output.fatal("BufferedBreedingPipeline's number of individuals must be >= 1.",base.push(P_BUFSIZE),def.push(P_BUFSIZE));
+        
+        buffer = new Individual[bufsize];
+        currentSize=0; // just in case 
+
+        // declare that likelihood isn't used
+        if (likelihood < 1.0f)
+            state.output.warning("BufferedBreedingPipeline does not respond to the 'likelihood' parameter.",
+                base.push(P_LIKELIHOOD), def.push(P_LIKELIHOOD));
+        }
+
+
+    public void prepareToProduce(final EvolutionState state,
+        final int subpopulation,
+        final int thread)
+        {
+        super.prepareToProduce(state,subpopulation,thread);
+        // reset my number of individuals to 0
+        currentSize=0;
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        for(int q=start;q<min+start; q++ )
+            {
+            if (currentSize==0)         // reload
+                {
+                sources[0].produce(buffer.length,buffer.length,
+                    0,subpopulation,buffer,state,thread);
+                currentSize=buffer.length;
+                
+                // clone if necessary
+                if (sources[0] instanceof SelectionMethod)
+                    for(int z=0; z < buffer.length; z++)
+                        buffer[z] = (Individual)(buffer[z].clone());
+                }
+            
+            inds[q] = buffer[currentSize-1];
+            currentSize--;
+            }
+        return min;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/ForceBreedingPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/ForceBreedingPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/ForceBreedingPipeline.java	(revision 6152)
@@ -0,0 +1,115 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.breed;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * ForceBreedingPipeline.java
+ * 
+ * Created: December 28, 1999
+ * By: Sean Luke
+ */
+
+/**
+ *
+ * ForceBreedingPipeline has one source.  To fill its quo for produce(...),
+ * ForceBreedingPipeline repeatedly forces its source to produce exactly numInds
+ * individuals at a time, except possibly the last time, where the number of
+ * individuals its source produces may be as low as 1.  This is useful for forcing
+ * Crossover to produce only one individual, or mutation to produce 2 individuals
+ * always, etc.
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Determined by <i>base</i>.<tt>num-inds</tt>
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>num-inds</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(The number of individuals this breeding pipeline will force its
+ source to produce each time in order to fill the quo for produce(...).)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ breed.force
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ForceBreedingPipeline extends BreedingPipeline
+    {
+    public static final String P_NUMINDS = "num-inds";
+    public static final String P_FORCE = "force";
+
+    public int numInds;
+
+    public Parameter defaultBase()
+        {
+        return BreedDefaults.base().push(P_FORCE);
+        }
+
+    public int numSources() { return 1; }    
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        Parameter def = defaultBase();
+        numInds = state.parameters.getInt(base.push(P_NUMINDS),def.push(P_NUMINDS),1);
+        if (numInds==0)
+            state.output.fatal("ForceBreedingPipeline must produce at least 1 child at a time", base.push(P_NUMINDS),def.push(P_NUMINDS));
+
+        // declare that likelihood isn't used
+        if (likelihood < 1.0f)
+            state.output.warning("ForceBreedingPipeline does not respond to the 'likelihood' parameter.",
+                base.push(P_LIKELIHOOD), def.push(P_LIKELIHOOD));
+        }
+
+    /** Returns the max of typicalIndsProduced() of all its children */
+    public int typicalIndsProduced()
+        {
+        return numInds;
+        }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        int n = numInds;
+        if (n < min) n = min;
+        if (n > max) n = max;
+
+        int total;
+        int numToProduce;
+        for(total=0; total<n; )
+            {
+            numToProduce = n - total;
+            if (numToProduce > numInds) numToProduce = numInds;
+
+            total += sources[0].produce(numToProduce,numToProduce,start+total,
+                subpopulation,inds,state,thread);
+            }
+        
+        // clone if necessary
+        if (sources[0] instanceof SelectionMethod)
+            for(int q=start; q < total+start; q++)
+                inds[q] = (Individual)(inds[q].clone());
+                
+        return total;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/GenerationSwitchPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/GenerationSwitchPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/GenerationSwitchPipeline.java	(revision 6152)
@@ -0,0 +1,143 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.breed;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GenerationSwitchPipeline.java
+ * 
+ * Created: Sat Nov 10 14:10:35 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * GenerationSwitchPipeline is a simple BreedingPipeline which switches its source depending
+ * on the generation.  If the generation number is < n, then GenerationSwitchPipeline uses
+ * source.0.  If the generation number if >= n, then GenerationSwitchPipeline uses source.1.
+ 
+ * <p><b>Important Note:</b> Because GenerationSwitchPipeline gets the generation number
+ * from the EvolutionState, and this number is not protected by a mutex, if you create
+ * an EvolutionState or Breeder which uses multiple threads that can update the generation
+ * number as they like, you could cause a race condition.  This doesn't occur with the
+ * present EvolutionState objects provided with ECJ, but you should be aware of the
+ * possibility.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Defined as the max of its children's responses. 
+
+ <p><b>Number of Sources</b><br>
+ 2
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>generate-max</tt><br>
+ <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ <td valign=top>(Each time produce(...) is called, should the GenerationSwitchPipeline
+ force all its sources to produce exactly the same number of individuals as the largest
+ typical number of individuals produced by any source in the group?)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>switch-at</tt><br>
+ <font size=-1> int &gt;= 0</tt></font></td>
+ <td valign=top>(The generation we will switch at)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ breed.generation-switch
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+ 
+public class GenerationSwitchPipeline extends BreedingPipeline
+    {
+    public static final String P_SWITCHAT = "switch-at";
+    public static final String P_MULTIBREED = "generation-switch";
+    public static final String P_GEN_MAX = "generate-max";
+    public static final int NUM_SOURCES = 2;
+
+    public int maxGeneratable;
+    public boolean generateMax;
+    public int generationSwitch;
+
+    public Parameter defaultBase()
+        {
+        return BreedDefaults.base().push(P_MULTIBREED);
+        }
+
+    public int numSources() { return NUM_SOURCES; }    
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        state.output.exitIfErrors();
+
+        generationSwitch = state.parameters.getInt(base.push(P_SWITCHAT),def.push(P_SWITCHAT),0);
+        if (generationSwitch < 0)
+            state.output.fatal("GenerationSwitchPipeline must have a switch-at >= 0", 
+                base.push(P_SWITCHAT),def.push(P_SWITCHAT));
+
+        generateMax = state.parameters.getBoolean(base.push(P_GEN_MAX),def.push(P_GEN_MAX),true);
+        maxGeneratable=0;  // indicates that I don't know what it is yet.  
+
+        // declare that likelihood isn't used
+        if (likelihood < 1.0f)
+            state.output.warning("GenerationSwitchPipeline does not respond to the 'likelihood' parameter.",
+                base.push(P_LIKELIHOOD), def.push(P_LIKELIHOOD));
+        }
+
+    /** Returns the max of typicalIndsProduced() of all its children */
+    public int typicalIndsProduced()
+        { 
+        if (maxGeneratable==0) // not determined yet
+            maxGeneratable = maxChildProduction();
+        return maxGeneratable; 
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        BreedingSource s = (state.generation < generationSwitch ?
+            sources[0] : sources[1] );
+        int total;
+
+        if (generateMax)
+            {
+            if (maxGeneratable==0)
+                maxGeneratable = maxChildProduction();
+            int n = maxGeneratable;
+            if (n < min) n = min;
+            if (n > max) n = max;
+
+            total = s.produce(
+                n,n,start,subpopulation,inds,state,thread);
+            }
+        else
+            {
+            total = s.produce(
+                min,max,start,subpopulation,inds,state,thread);
+            }
+            
+        // clone if necessary
+        if (s instanceof SelectionMethod)
+            for(int q=start; q < total+start; q++)
+                inds[q] = (Individual)(inds[q].clone());
+        
+        return total;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/MultiBreedingPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/MultiBreedingPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/MultiBreedingPipeline.java	(revision 6152)
@@ -0,0 +1,146 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.breed;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * MultiBreedingPipeline.java
+ * 
+ * Created: December 28, 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MultiBreedingPipeline is a BreedingPipeline stores some <i>n</i> child sources; 
+ * each time it must produce an individual or two, 
+ * it picks one of these sources at random and has it do the production.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ If by <i>base</i>.<tt>generate-max</tt> is <tt>true</tt>, then always the maximum
+ number of the typical numbers of any child source.  If <tt>false</itt>, then varies
+ depending on the child source picked.
+
+ <p><b>Number of Sources</b><br>
+ Dynamic.  As many as the user specifies.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>generate-max</tt><br>
+ <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ <td valign=top>(Each time produce(...) is called, should the MultiBreedingPipeline
+ force all its sources to produce exactly the same number of individuals as the largest
+ typical number of individuals produced by any source in the group?)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ breed.multibreed
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MultiBreedingPipeline extends BreedingPipeline
+    {
+    public static final String P_GEN_MAX = "generate-max";
+    public static final String P_MULTIBREED = "multibreed";
+
+    public int maxGeneratable;
+    public boolean generateMax;
+
+    public Parameter defaultBase()
+        {
+        return BreedDefaults.base().push(P_MULTIBREED);
+        }
+
+    public int numSources() { return DYNAMIC_SOURCES; }    
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        float total = 0.0f;
+
+        for(int x=0;x<sources.length;x++)
+            {
+            // make sure the sources are actually breeding pipelines
+            if (!(sources[x] instanceof BreedingPipeline))
+                state.output.error("Source #" + x + "is not a BreedingPipeline",base);
+            else if (sources[x].probability<0.0) // null checked from state.output.error above
+                state.output.error("Pipe #" + x + " must have a probability >= 0.0",base);  // convenient that NO_PROBABILITY is -1...
+            else total += sources[x].probability;
+            }
+
+        state.output.exitIfErrors();
+
+        // Now check for nonzero probability (we know it's positive)
+        if (total == 0.0)
+            state.output.warning("MultiBreedingPipeline's children have all zero probabilities -- this will be treated as a uniform distribution.  This could be an error.", base);
+
+        // allow all zero probabilities
+        BreedingSource.setupProbabilities(sources);
+
+        generateMax = state.parameters.getBoolean(base.push(P_GEN_MAX),def.push(P_GEN_MAX),true);
+        maxGeneratable=0;  // indicates that I don't know what it is yet.  
+                
+        // declare that likelihood isn't used
+        if (likelihood < 1.0f)
+            state.output.warning("MultiBreedingPipeline does not respond to the 'likelihood' parameter.",
+                base.push(P_LIKELIHOOD), def.push(P_LIKELIHOOD));
+        }
+
+    /** Returns the max of typicalIndsProduced() of all its children */
+    public int typicalIndsProduced()
+        { 
+        if (maxGeneratable==0) // not determined yet
+            maxGeneratable = maxChildProduction();
+        return maxGeneratable; 
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        BreedingSource s = sources[BreedingSource.pickRandom(
+                sources,state.random[thread].nextFloat())];
+        int total;
+        
+        if (generateMax)
+            {
+            if (maxGeneratable==0)
+                maxGeneratable = maxChildProduction();
+            int n = maxGeneratable;
+            if (n < min) n = min;
+            if (n > max) n = max;
+
+            total = s.produce(
+                n,n,start,subpopulation,inds,state,thread);
+            }
+        else
+            {
+            total = s.produce(
+                min,max,start,subpopulation,inds,state,thread);
+            }
+            
+        // clone if necessary
+        if (s instanceof SelectionMethod)
+            for(int q=start; q < total+start; q++)
+                inds[q] = (Individual)(inds[q].clone());
+        
+        return total;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/README	(revision 6152)
@@ -0,0 +1,48 @@
+This directory contains some simple utility breeding pipelines.  These
+pipelines don't make modifications of individuals, so if you're looking
+for crossover or mutation etc., you'll need to check in other packages
+more specifically designed for your representation.
+
+ec.breed.ReproductionPipeline
+	Requests an individual from its sole source pipeline, then
+	makes a copy of it and returns the copy.  Largely used in the
+	genetic programming package.
+
+ec.breed.MultiBreedingPipeline
+	When asked to create one or more children, selects from among
+	some N source pipelines attached to it, requests indivdiuals
+	from the chosen source, copies them, and returns them.  The
+	selection procedure is probabilistic, based on the 'probability'
+	values stored in each of the sources (in fact,
+	MultiBreedingPipeline is the reason those probability values exist.
+	This is historical: we probably should have stored them in
+	the MultiBreedingPipeline instead!  Might change in the future.)
+
+ec.breed.ForceBreedingPipeline
+	When asked to create some N children, this repeatedly requests from
+	its sole source some M<=N children at a time (you specify the M)
+	until it gets the N children asked for.  This is useful for various
+	minor tricks, such as forcing Crossover to only produce one individual.
+
+ec.breed.BufferedBreedingPipeline
+	When asked to create some N children, this makes a large request
+	from its sole source to create some M >= N children at a time
+	(you specify the M).  It then returns N of these children, storing
+	away the other M - N ones.  When asked again to create some more 
+	children, it reaches into this storage and provides some of them.
+	When the storage is depleted, it creates another M children.  This
+	is useful for certain minor tricks: for example, enabling you to cross
+	over two individuals, then cross them over *again*.  We'd do that by
+	attaching the same BufferedBreedingPipeline (with M=2) to _both_
+	sources of a CrossoverPipeline (use the "same" options).  The
+	BufferedBreedingPipeline then has another CrossoverPipeline as its
+	source.  When the top CrossoverPipeline asked for its first child
+	to cross over, the BufferedBreedingPipeline would demand two children
+	from the subsidiary CrossoverPipeline (already crossed over), then
+	provide one of them.  When the second child is requested, the remaining
+	child would be provided. 
+
+ec.breed.GenerationSwitchPipeline
+	This pipeline takes two sources.  If the generation is less than G,
+	then the pipeline provides copies of individuals from source 0.  Else
+	it provides copies of individuals from source 1.
Index: branches/OKBJavaConnector/ECJClient/src/ec/breed/ReproductionPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/breed/ReproductionPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/breed/ReproductionPipeline.java	(revision 6152)
@@ -0,0 +1,90 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.breed;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * ReproductionPipeline.java
+ * 
+ * Created: Thu Nov  8 13:39:32 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * ReproductionPipeline is a BreedingPipeline which simply makes a copy
+ * of the individuals it recieves from its source.  If the source is another
+ * BreedingPipeline, the individuals have already been cloned, so ReproductionPipeline
+ * won't clone them again...unless you force it to do so by turning on the <tt>must-clone</tt>
+ * parameter.
+ *
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the child produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>must-clone</tt><br>
+ <font size=-1>bool =  <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(do we <i>always</i> clone our individuals, or only clone if the individual hasn't already been cloned by our source?  Typically you want <tt>false</tt>)</td></tr>
+
+ </table>
+ <p><b>Default Base</b><br>
+ breed.reproduce
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ReproductionPipeline extends BreedingPipeline
+    {
+    public static final String P_REPRODUCE = "reproduce";
+    public static final String P_MUSTCLONE = "must-clone";
+    public static final int NUM_SOURCES = 1;
+    
+    public boolean mustClone;
+    
+    public Parameter defaultBase() { return BreedDefaults.base().push(P_REPRODUCE); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        Parameter def = defaultBase();
+        mustClone = state.parameters.getBoolean(base.push(P_MUSTCLONE), def.push(P_MUSTCLONE),false);
+                
+        if (likelihood != 1.0)
+            state.output.warning("ReproductionPipeline given a likelihood other than 1.0.  This is nonsensical and will be ignored.",
+                base.push(P_LIKELIHOOD),
+                def.push(P_LIKELIHOOD));
+        }
+        
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+                
+        // this code is basically the same as BreedingPipeline.reproduce() but we copy it here
+        // because of the 'mustClone' option.
+                
+        if (mustClone || sources[0] instanceof SelectionMethod)
+            for(int q=start; q < n+start; q++)
+                inds[q] = (Individual)(inds[q].clone());
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/coevolve/CompetitiveEvaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/coevolve/CompetitiveEvaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/coevolve/CompetitiveEvaluator.java	(revision 6152)
@@ -0,0 +1,652 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.coevolve;
+import ec.*;
+import ec.util.*;
+
+/** 
+ * CompetitiveEvaluator.java
+ *
+
+ <p>CompetitiveEvaluator is a Evaluator which performs <i>competitive fitness evaluations</i>.  
+ Competitive fitness is where individuals' fitness is determined by testing them against 
+ other members of the same subpopulation.  Competitive fitness topologies differ from
+ co-evolution topologies in that co-evolution is a term I generally reserve for 
+ multiple sbupopulations which breed separately but compete against other subpopulations 
+ during evaluation time.  Individuals are evaluated regardless of whether or not they've
+ been evaluated in the past.
+
+ <p>Your Problem is responsible for setting up the fitness appropriately.  
+ CompetitiveEvaluator expects to use Problems which adhere to the GroupedProblemForm interface, 
+ which defines a new evaluate(...) function, plus a preprocess(...) and postprocess(...) function.
+
+ <p>This competitive fitness evaluator is single-threaded -- maybe we'll hack in multithreading later. 
+ And it only has two individuals competing during any fitness evaluation.  The order of individuals in the 
+ subpopulation will be changed during the evaluation process.  There are seven evaluation topologies
+ presently supported:
+
+ <p><dl>
+ <dt><b>Single Elimination Tournament</b><dd>
+ All members of the population are paired up and evaluated.  In each pair, the "winner" is the individual
+ which winds up with the superior fitness.  If neither fitness is superior, then the "winner" is picked
+ at random.  Then all the winners are paired up and evaluated, and so on, just like in a single elimination
+ tournament.  It is important that the <b>population size be a <i>power of two</i></b>, else some individuals
+ will not have the same number of "wins" as others and may lose the tournament as a result.
+
+ <dt><b>Round Robin</b><dd>
+ Every member of the population are paired up and evaluated with all other members of the population, not
+ not including the member itself (we might add in self-play as a future later if people ask for it, it's
+ easy to hack in).
+
+ <dt><b>K-Random-Opponents-One-Way</b><dd>
+ Each individual's fitness is calculated based on K competitions against random opponents.
+ For details, see "A Comparison of Two Competitive Fitness Functions" by Liviu Panait and
+ Sean Luke in the Proceedings of GECCO 2002.
+
+ <dt><b>K-Random-Opponents-Two-Way</b><dd>
+ Each individual's fitness is calculated based on K competitions against random opponents. The advantage of
+ this method over <b>K-Random-Opponents-One-Way</b> is a reduced number of competitions (when I competes
+ against J, both I's and J's fitnesses are updated, while in the previous method only one of the individuals
+ has its fitness updated).
+ For details, see "A Comparison of Two Competitive Fitness Functions" by Liviu Panait and
+ Sean Luke in the Proceedings of GECCO 2002.
+ </dl> 
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>style</tt><br>
+ <font size=-1>string with possible values: </font></td>
+ <td valign=top>(the style of the tournament)<br>
+ <i>single-elim-tournament</i> (a single elimination tournament)<br>
+ <i>round-robin</i> (a round robin tournament)<br>
+ <i>rand-1-way</i> (K-Random-Opponents, each game counts for only one of the players)<br>
+ <i>rand-2-way</i> (K-Random-Opponents, each game counts for both players)<br>
+ </td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>group-size</tt><br>
+ <font size=-1> int</font></td>
+ <td valign=top>(how many individuals per group, used in rand-1-way</i> and <i>rand-2-way</i> tournaments)<br>
+ <i>group-size</i> &gt;= 1 for <i>rand-1-way</i> or <i>rand-2-way</i><br>
+ </td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>over-eval</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(if the tournament style leads to an individual playing more games than others (as can be the case for rand-2-way),
+ should the extra games be used for his fitness evaluatiuon?)</td></tr>
+
+ </table>
+
+ *
+ * @author Sean Luke & Liviu Panait
+ * @version 1.0 
+ */
+
+
+public class CompetitiveEvaluator extends Evaluator
+    {
+    public static final int STYLE_SINGLE_ELIMINATION=1;
+    public static final int STYLE_ROUND_ROBIN=2;
+    public static final int STYLE_N_RANDOM_COMPETITORS_ONEWAY=3;
+    public static final int STYLE_N_RANDOM_COMPETITORS_TWOWAY=4;
+
+    public static final String P_COMPETE_STYLE = "style";
+    public int style;
+
+    public static final String P_GROUP_SIZE = "group-size";
+    public int groupSize;
+
+    public static final String P_OVER_EVAL = "over-eval";
+    public boolean allowOverEvaluation;
+
+    public void setup( final EvolutionState state, final Parameter base )
+        {
+        super.setup( state, base );
+        String temp;
+        temp = state.parameters.getStringWithDefault( base.push( P_COMPETE_STYLE ), null, "" );
+        if( temp.equalsIgnoreCase( "single-elim-tournament" ) )
+            {
+            style = STYLE_SINGLE_ELIMINATION;
+            }
+        else if( temp.equalsIgnoreCase( "round-robin" ) )
+            {
+            style = STYLE_ROUND_ROBIN;
+            }
+        else if( temp.equalsIgnoreCase( "rand-1-way" ) )
+            {
+            style = STYLE_N_RANDOM_COMPETITORS_ONEWAY;
+            }
+        else if( temp.equalsIgnoreCase( "rand-2-way" ) )
+            {
+            style = STYLE_N_RANDOM_COMPETITORS_TWOWAY;
+            }
+        else if (temp.equalsIgnoreCase( "rand-2-ways" ) )
+            {
+            state.output.fatal("'rand-2-ways' is no longer a valid style name: use 'rand-2-way'",
+                base.push(P_COMPETE_STYLE), null);
+            }
+        else
+            {
+            state.output.fatal( "Incorrect value for parameter. Acceptable values: " +
+                "single-elim-tournament, round-robin, rand-1-way, rand-2-way" , base.push( P_COMPETE_STYLE ) );
+            }
+
+        if( style == STYLE_N_RANDOM_COMPETITORS_ONEWAY || style == STYLE_N_RANDOM_COMPETITORS_TWOWAY )
+            {
+            groupSize = state.parameters.getInt( base.push( P_GROUP_SIZE ), null, 1 );
+            if( groupSize < 1 )
+                {
+                state.output.fatal( "Incorrect value for parameter", base.push( P_GROUP_SIZE ) );
+                }
+            }
+        allowOverEvaluation = state.parameters.getBoolean( base.push( P_OVER_EVAL ), null, false );
+        }
+
+    public boolean runComplete( final EvolutionState state )
+        {
+        return false;
+        }
+
+    public void randomizeOrder(final EvolutionState state, final Individual[] individuals)
+        {
+        // copy the inds into a new array, then dump them randomly into the
+        // subpopulation again
+        Individual[] queue = new Individual[individuals.length];
+        int len = queue.length;
+        System.arraycopy(individuals,0,queue,0,len);
+
+        for(int x=len;x>0;x--)
+            {
+            int i = state.random[0].nextInt(x);
+            individuals[x-1] = queue[i];
+            // get rid of queue[i] by swapping the highest guy there and then
+            // decreasing the highest value  :-)
+            queue[i] = queue[x-1];
+            }
+        }
+
+    /**
+     * An evaluator that performs coevolutionary evaluation.  Like SimpleEvaluator,
+     * it applies evolution pipelines, one per thread, to various subchunks of
+     * a new population.
+     */
+    public void evaluatePopulation(final EvolutionState state)
+        {
+        int numinds[] = new int[state.evalthreads];
+        int from[] = new int[state.evalthreads];
+        
+        for (int y=0;y<state.evalthreads;y++)
+            {
+            // figure numinds
+            if (y<state.evalthreads-1) // not last one
+                numinds[y] = state.population.subpops[0].individuals.length/
+                    state.evalthreads;
+            else
+                numinds[y] = 
+                    state.population.subpops[0].individuals.length/
+                    state.evalthreads +
+                    
+                    (state.population.subpops[0].individuals.length -
+                        (state.population.subpops[0].individuals.length /
+                        state.evalthreads)
+                    *state.evalthreads);
+            // figure from
+            from[y] = (state.population.subpops[0].individuals.length/
+                state.evalthreads) * y;
+            }
+        
+        randomizeOrder( state, state.population.subpops[0].individuals );
+        
+        GroupedProblemForm prob = (GroupedProblemForm)(p_problem.clone());
+
+        prob.preprocessPopulation(state,state.population, style == STYLE_SINGLE_ELIMINATION);
+                
+        switch(style)
+            {
+            case STYLE_SINGLE_ELIMINATION:
+                evalSingleElimination( state, state.population.subpops[0].individuals, 0, prob);
+                break;
+            case STYLE_ROUND_ROBIN:
+                evalRoundRobin( state, from, numinds, state.population.subpops[0].individuals, 0, prob );
+                break;
+            case STYLE_N_RANDOM_COMPETITORS_ONEWAY:
+                evalNRandomOneWay( state, from, numinds, state.population.subpops[0].individuals, 0, prob );
+                break;
+            case STYLE_N_RANDOM_COMPETITORS_TWOWAY:
+                evalNRandomTwoWay( state, from, numinds, state.population.subpops[0].individuals, 0, prob );
+                break;
+            }
+    
+        prob.postprocessPopulation(state, state.population, style == STYLE_SINGLE_ELIMINATION);
+        }
+    
+    public void evalSingleElimination( final EvolutionState state,
+        final Individual[] individuals,
+        final int subpop,
+        final GroupedProblemForm prob )
+        {
+
+        // for a single-elimination tournament, the subpop[0] size must be 2^n for
+        // some value n.  We don't check that here!  Check it in setup.
+        
+        // create the tournament array
+        Individual[] tourn = new Individual[individuals.length];
+        System.arraycopy( individuals, 0, tourn, 0, individuals.length );
+        int len = tourn.length;
+        Individual[] competition = new Individual[2];
+        int[] subpops = new int[] { subpop, subpop };
+        boolean[] updates = new boolean[2];
+        updates[0] = updates[1] = true;
+
+        // the "top half" of our array will be losers.
+        // the bottom half will be winners.  Then we cut our array in half and repeat.
+        while( len > 1 )
+            {
+            for(int x=0;x<len/2;x++)
+                {
+                competition[0] = tourn[x];
+                competition[1] = tourn[len-x-1];
+
+                prob.evaluate(state,competition,updates,true,subpops, 0);
+                }
+
+            for(int x=0;x<len/2;x++)
+                {
+                // if the second individual is better, than we switch them around
+                if( tourn[len-x-1].fitness.betterThan(tourn[x].fitness) )
+                    {
+                    Individual temp = tourn[x];
+                    tourn[x] = tourn[len-x-1];
+                    tourn[len-x-1] = temp;
+                    }
+
+                }
+
+            // last part of the tournament: deal with odd values of len!
+            if( len%2 != 0 )
+                len = 1 + len/2;
+            else
+                len /= 2;
+            }
+        }
+
+
+    public void evalRoundRobin( final EvolutionState state,
+        int[] from, int[] numinds,
+        final Individual[] individuals, int subpop,
+        final GroupedProblemForm prob )
+        {
+        if (state.evalthreads==1)
+            evalRoundRobinPopChunk(state,from[0],numinds[0],0,individuals, subpop, prob);
+        else
+            {
+            Thread[] t = new Thread[state.evalthreads];
+            
+            // start up the threads
+            for (int y=0;y<state.evalthreads;y++)
+                {
+                CompetitiveEvaluatorThread r = new RoundRobinCompetitiveEvaluatorThread();
+                r.threadnum = y;
+                r.numinds = numinds[y];
+                r.from = from[y];
+                r.me = this;
+                r.subpop = subpop;
+                r.state = state;
+                r.p = prob;
+                r.inds = individuals;
+                t[y] = new Thread(r);
+                t[y].start();
+                }
+            
+            // gather the threads
+            for (int y=0;y<state.evalthreads;y++) 
+                try { t[y].join(); }
+                catch(InterruptedException e)
+                    {
+                    state.output.fatal("Whoa! The main evaluation thread got interrupted!  Dying...");
+                    }
+            }
+        
+        }
+
+    /**
+     * A private helper function for evalutatePopulation which evaluates a chunk
+     * of individuals in a subpopulation for a given thread.
+     * 
+     * Although this method is declared public (for the benefit of a private
+     * helper class in this file), you should not call it.
+     * 
+     * @param state
+     * @param numinds
+     * @param from
+     * @param threadnum
+     * @param prob
+     */
+    public void evalRoundRobinPopChunk(final EvolutionState state,
+        int from, int numinds, int threadnum, 
+        final Individual[] individuals, int subpop,
+        final GroupedProblemForm prob)
+        {
+        Individual[] competition = new Individual[2];
+        int[] subpops = new int[] { subpop, subpop };
+        boolean[] updates = new boolean[2];
+        updates[0] = updates[1] = true;
+        int upperBound = from+numinds;
+        
+        // evaluate chunk of population against entire population
+        // since an individual x will be evaluated against all 
+        // other individuals <x in other threads, only evaluate it against
+        // individuals >x in this thread.
+        for(int x=from;x<upperBound;x++)
+            for(int y=x+1;y<individuals.length;y++)
+                {
+                competition[0] = individuals[x];
+                competition[1] = individuals[y];
+                prob.evaluate(state,competition,updates,false, subpops, 0);
+                }
+        }
+
+
+    public void evalNRandomOneWay( final EvolutionState state, 
+        int[] from, int[] numinds, 
+        final Individual[] individuals, int subpop, 
+        final GroupedProblemForm prob )
+        {
+        if (state.evalthreads==1)
+            evalNRandomOneWayPopChunk(state,from[0],numinds[0],0,individuals, subpop, prob);
+        else
+            {
+            Thread[] t = new Thread[state.evalthreads];
+            
+            // start up the threads
+            for (int y=0;y<state.evalthreads;y++)
+                {
+                CompetitiveEvaluatorThread r = new NRandomOneWayCompetitiveEvaluatorThread();
+                r.threadnum = y;
+                r.numinds = numinds[y];
+                r.from = from[y];
+                r.subpop = subpop;
+                r.me = this;
+                r.state = state;
+                r.p = prob;
+                r.inds = individuals;
+                t[y] = new Thread(r);
+                t[y].start();
+                }
+            
+            // gather the threads
+            for (int y=0;y<state.evalthreads;y++) 
+                try { t[y].join(); }
+                catch(InterruptedException e)
+                    {
+                    state.output.fatal("Whoa! The main evaluation thread got interrupted!  Dying...");
+                    }
+            }
+        }
+    
+    public void evalNRandomOneWayPopChunk( final EvolutionState state,
+        int from, int numinds, int threadnum,
+        final Individual[] individuals,
+        final int subpop,
+        final GroupedProblemForm prob )
+        {
+        Individual[] queue = new Individual[individuals.length];
+        int len = queue.length;
+        System.arraycopy(individuals,0,queue,0,len);
+
+        Individual[] competition = new Individual[2];
+        int subpops[] = new int[] { subpop, subpop };
+        boolean[] updates = new boolean[2];
+        updates[0] = true;
+        updates[1] = false;
+        int upperBound = from+numinds;
+        
+        for(int x=from;x<upperBound;x++)
+            {
+            competition[0] = individuals[x];
+            // fill up our tournament
+            for(int y=0;y<groupSize;)
+                {
+                // swap to end and remove
+                int index = state.random[0].nextInt(len-y);
+                competition[1] = queue[index];
+                queue[index] = queue[len-y-1];
+                queue[len-y-1] = competition[1];
+                // if the opponent is not the actual individual, we can
+                // have a competition
+                if( competition[1] != individuals[x] )
+                    {
+                    prob.evaluate(state,competition,updates,false,subpops, 0);
+                    y++;
+                    }
+                }
+            }
+        }
+
+    public void evalNRandomTwoWay( final EvolutionState state,
+        int[] from, int[] numinds,
+        final Individual[] individuals, int subpop, 
+        final GroupedProblemForm prob )
+        {
+        if (state.evalthreads==1)
+            evalNRandomTwoWayPopChunk(state,from[0],numinds[0],0,individuals, subpop, prob);
+        else
+            {
+            Thread[] t = new Thread[state.evalthreads];
+            
+            // start up the threads
+            for (int y=0;y<state.evalthreads;y++)
+                {
+                CompetitiveEvaluatorThread r = new NRandomTwoWayCompetitiveEvaluatorThread();
+                r.threadnum = y;
+                r.numinds = numinds[y];
+                r.from = from[y];
+                r.me = this;
+                r.subpop = subpop;
+                r.state = state;
+                r.p = prob;
+                r.inds = individuals;
+                t[y] = new Thread(r);
+                t[y].start();
+                }
+            
+            // gather the threads
+            for (int y=0;y<state.evalthreads;y++)
+                try { t[y].join(); }
+                catch(InterruptedException e)
+                    {
+                    state.output.fatal("Whoa! The main evaluation thread got interrupted!  Dying...");
+                    }
+            }
+        }
+    
+    public void evalNRandomTwoWayPopChunk( final EvolutionState state,
+        int from, int numinds, int threadnum,
+        final Individual[] individuals,
+        final int subpop,
+        final GroupedProblemForm prob )
+        {
+
+        // the number of games played for each player
+        EncapsulatedIndividual[] individualsOrdered = new EncapsulatedIndividual[individuals.length];
+        EncapsulatedIndividual[] queue = new EncapsulatedIndividual[individuals.length];
+        for( int i = 0 ; i < individuals.length ; i++ )
+            individualsOrdered[i] = new EncapsulatedIndividual( individuals[i], 0 );
+
+        Individual[] competition = new Individual[2];
+        int[] subpops = new int[] { subpop, subpop }; 
+        boolean[] updates = new boolean[2];
+        updates[0] = true;
+        int upperBound = from+numinds;
+        
+        for(int x=from;x<upperBound;x++)
+            {
+            System.arraycopy(individualsOrdered,0,queue,0,queue.length);
+            competition[0] = queue[x].ind;
+
+            // if the rest of individuals is not enough to fill
+            // all games remaining for the current individual
+            // (meaning that the current individual has left a
+            // lot of games to play versus players with index
+            // greater than his own), then it should play with
+            // all. In the end, we should check that he finished
+            // all the games he needs. If he did, everything is
+            // ok, otherwise he should play with some other players
+            // with index smaller than his own, but all these games
+            // will count only for his fitness evaluation, and
+            // not for the opponents' (unless allowOverEvaluations is set to true)
+
+            // if true, it means that he has to play against all opponents with greater index
+            if( individuals.length - x - 1 <= groupSize - queue[x].nOpponentsMet )
+                {
+                for( int y = x+1 ; y < queue.length ; y++ )
+                    {
+                    competition[1] = queue[y].ind;
+                    updates[1] = (queue[y].nOpponentsMet < groupSize) || allowOverEvaluation;
+                    prob.evaluate( state, competition, updates, false, subpops, 0 );
+                    queue[x].nOpponentsMet++;
+                    if( updates[1] )
+                        queue[y].nOpponentsMet++;
+                    }
+                }
+            else // here he has to play against a selection of the opponents with greater index
+                {
+                // we can use the queue structure because we'll just rearrange the indexes
+                // but we should make sure we also rearrange the other vectors referring to the individuals
+
+                for( int y = 0 ; groupSize > queue[x].nOpponentsMet ; y++ )
+                    {
+                    // swap to the end and remove from list
+                    int index = state.random[0].nextInt( queue.length - x - 1 - y )+x+1;
+                    competition[1] = queue[index].ind;
+
+                    updates[1] = (queue[index].nOpponentsMet < groupSize) || allowOverEvaluation;
+                    prob.evaluate( state, competition, updates, false, subpops, 0 );
+                    queue[x].nOpponentsMet++;
+                    if( updates[1] )
+                        queue[index].nOpponentsMet++;
+
+                    // swap the players (such that a player will not be considered twice)
+                    EncapsulatedIndividual temp = queue[index];
+                    queue[index] = queue[queue.length - y - 1];
+                    queue[queue.length - y - 1] = temp;
+
+                    }
+
+                }
+
+            // if true, it means that the current player needs to play some games with other players with lower indexes.
+            // this is an unfortunate situation, since all those players have already had their groupSize games for the evaluation
+            if( queue[x].nOpponentsMet < groupSize )
+                {
+                for( int y = queue[x].nOpponentsMet ; y < groupSize ; y++ )
+                    {
+                    // select a random opponent with smaller index (don't even care for duplicates)
+                    int index;
+                    if( x > 0 ) // if x is 0, then there are no players with smaller index, therefore pick a random one
+                        index = state.random[0].nextInt( x );
+                    else
+                        index = state.random[0].nextInt( queue.length-1 )+1;
+                    // use the opponent for the evaluation
+                    competition[1] = queue[index].ind;
+                    updates[1] = (queue[index].nOpponentsMet < groupSize) || allowOverEvaluation;
+                    prob.evaluate( state, competition, updates, false, subpops, 0 );
+                    queue[x].nOpponentsMet++;
+                    if( updates[1] )
+                        queue[index].nOpponentsMet++;
+                    
+                    }
+                }
+
+            }
+        }
+
+    int nextPowerOfTwo( int N )
+        {
+        int i = 1;
+        while( i < N )
+            i *= 2;
+        return i;
+        }
+
+    int whereToPutInformation;
+    void fillPositions( int[] positions, int who, int totalPerDepth, int total )
+        {
+        if(totalPerDepth >= total - 1 )
+            {
+            positions[whereToPutInformation] = who;
+            whereToPutInformation++;
+            }
+        else
+            {
+            fillPositions( positions, who, totalPerDepth*2+1, total );
+            fillPositions( positions, totalPerDepth-who, totalPerDepth*2+1, total );
+            }
+        }
+
+    }
+
+// used by the K-Random-Opponents-One-Way and K-Random-Opponents-Two-Ways evaluations
+class EncapsulatedIndividual
+    {
+    public Individual ind;
+    public int nOpponentsMet;
+    public EncapsulatedIndividual( Individual ind_, int value_ )
+        {
+        ind = ind_;
+        nOpponentsMet = value_;
+        }
+    };
+
+// used by the Single-Elimination-Tournament, (Double-Elimination-Tournament and World-Cup) evaluations
+class IndividualAndVictories
+    {
+    public Individual ind;
+    public int victories;
+    public IndividualAndVictories( Individual ind_, int value_ )
+        {
+        ind = ind_;
+        victories = value_;
+        }
+    };
+
+class IndComparator implements SortComparator
+    {
+    public boolean lt(Object a, Object b)
+        { return ((Individual)a).fitness.betterThan(((Individual)b).fitness); }
+    public boolean gt(Object a, Object b)
+        { return ((Individual)b).fitness.betterThan(((Individual)a).fitness); }
+    }
+
+abstract class CompetitiveEvaluatorThread implements Runnable
+    {
+    public int numinds;
+    public int from;
+    public CompetitiveEvaluator me;
+    public EvolutionState state;
+    public int threadnum;
+    public GroupedProblemForm p;
+    public int subpop;
+    public Individual[] inds;
+    }
+
+class RoundRobinCompetitiveEvaluatorThread extends CompetitiveEvaluatorThread
+    {
+    public synchronized void run()
+        { me.evalRoundRobinPopChunk(state,from,numinds,threadnum,inds, subpop, p); }
+    }
+
+class NRandomOneWayCompetitiveEvaluatorThread extends CompetitiveEvaluatorThread
+    {
+    public synchronized void run()
+        { me.evalNRandomOneWayPopChunk(state,from,numinds,threadnum,inds, subpop, p); }
+    }
+class NRandomTwoWayCompetitiveEvaluatorThread extends CompetitiveEvaluatorThread
+    {
+    public synchronized void run()
+        { me.evalNRandomTwoWayPopChunk(state,from,numinds,threadnum,inds, subpop, p); }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/coevolve/GroupedProblemForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/coevolve/GroupedProblemForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/coevolve/GroupedProblemForm.java	(revision 6152)
@@ -0,0 +1,92 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.coevolve;
+import ec.*;
+
+/**
+ * GroupedProblemForm.java
+ *
+
+ <p>GroupedProblemForm is an interface which defines methods
+ for Problems to implement simple coevolutionary evaluation.
+ In particular, the evaluate method receives as parameters a
+ set of individuals that need to be evaluated. An additional
+ vector-parameter (updateFitness) marks which individual
+ fitnesses need to be updated during the evaluation process.
+
+ *
+ * @author Sean Luke & Liviu Panait
+ * @version 1.0
+ */
+
+public interface GroupedProblemForm
+    {
+    /** Set up the population <tt>pop</tt> (such as fitness information) prior to evaluation.
+        Although this method is not static, you should not use it to write to any instance
+        variables in the GroupedProblem instance; this is because it's possible that
+        the instance used is in fact the prototype, and you will have no guarantees that
+        your instance variables will remain valid during the evaluate(...) process.
+        Do not assume that <tt>pop</tt> will be the same as <tt>state.pop</tt> -- it 
+        may not.  <tt>state</tt> is only provided to give you access to EvolutionState
+        features.   Typically you'd use this method to set the Fitness values of all
+        Individuals to 0.
+                
+        <p> <i>countVictoriesOnly</i> will be set if Individuals' fitness is to be based on
+        whether they're the winner of a test, instead of based on the specifics of the scores
+        in the tests.  This really only happens for Single-Elimination Tournament 
+        one-population competitive coevolution.
+    */ 
+    public void preprocessPopulation(final EvolutionState state, Population pop, final boolean countVictoriesOnly);
+
+    /** Finish processing the population (such as fitness information) after evaluation.
+        Although this method is not static, you should not use it to write to any instance
+        variables in the GroupedProblem instance; this is because it's possible that
+        the instance used is in fact the prototype, and you will have no guarantees that
+        your instance variables will remain valid during the evaluate(...) process.
+        Do not assume that <tt>pop</tt> will be the same as <tt>state.pop</tt> -- it 
+        may not.  <tt>state</tt> is only provided to give you access to EvolutionState
+        features. 
+                
+        <p> <i>countVictoriesOnly</i> will be set if Individuals' fitness is to be based on
+        whether they're the winner of a test, instead of based on the specifics of the scores
+        in the tests.  This really only happens for Single-Elimination Tournament 
+        one-population competitive coevolution.  If this is set, probably would leave the Fitnesses
+        as they are here (they've been set and incremented in evaluate(...)), but if it's not set,
+        you may want to set the Fitnesses to the maximum or average or the various trials
+        performed. 
+    */
+    public void postprocessPopulation(final EvolutionState state, Population pop, final boolean countVictoriesOnly);
+
+    /** Evaluates the individuals found in ind together.  If updateFitness[i] is true,
+        then you should use this evaluation to update the fitness of the individual in
+        ind[i].  Individuals which are updated should have their fitnesses modified so
+        that immediately after evaluation (and prior to postprocessPopulation(...) being
+        called) individuals' fitnesses can be checked to see which is better than which.
+        Do not assume that the individuals in <tt>ind</tt> will actually be in <tt>state.pop</tt>
+        (they may not -- this method may be called at the end of a run to determine the
+        best individual of the run in some kind of contest).
+                
+        <p> <i>countVictoriesOnly</i> will be set if Individuals' fitness is to be based on
+        whether they're the winner of a test, instead of based on the specifics of the scores
+        in the tests.  This really only happens for Single-Elimination Tournament 
+        one-population competitive coevolution.  If this is set, you should increment the Fitness of the winner
+        each time.  If it's not set, you should update Fitness as you see fit, then set
+        the final Fitness in preprocessPopulation. 
+    */
+    public void evaluate(final EvolutionState state,
+        final Individual[] ind,  // the individuals to evaluate together
+        final boolean[] updateFitness,  // should this individuals' fitness be updated?
+        final boolean countVictoriesOnly, // don't bother updating Fitness with socres, just victories
+        final int[] subpops,
+        final int threadnum);
+    }
+
+
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/coevolve/MultiPopCoevolutionaryEvaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/coevolve/MultiPopCoevolutionaryEvaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/coevolve/MultiPopCoevolutionaryEvaluator.java	(revision 6152)
@@ -0,0 +1,355 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.coevolve;
+
+import ec.*;
+import ec.util.*;
+
+/** 
+ * MultiPopCoevolutionaryEvaluator.java
+ *
+
+ <p>MultiPopCoevolutionaryEvaluator is an Evaluator which performs <i>competitive or cooperative multi-population
+ coevolution</i>.  Competitive coevolution is where individuals' fitness is determined by
+ testing them against individuals from other subpopulation.  Cooperative coevolution is where individuals
+ form teams together with members of other subpopulations, and the individuals' fitness is computed based
+ on the performance of such teams.  This evaluator assumes that the problem can only evaluate groups of
+ individuals containing one individual from each subpopulation.  Individuals are evaluated regardless of
+ whether or not they've been evaluated in the past.
+
+ <p>Your Problem is responsible for updating up the fitness appropriately with values usually obtained
+ from teaming up the individual with different partners from the other subpopulations.
+ MultiPopCoevolutionaryEvaluator expects to use Problems which adhere to the GroupedProblemForm
+ interface, which defines a new evaluate(...) function, plus a preprocess(...) and postprocess(...) function.
+
+ <p>This coevolutionary evaluator is single-threaded -- maybe we'll hack in multithreading later.  It allows
+ any number of subpopulations (implicitly, any number of individuals being evaluated together). The order of
+ individuals in the subpopulation may be changed during the evaluation process.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>subpop.num-current</tt><br>
+ <font size=-1> int &gt;= 0</font></td>
+ <td valign=top>(the number of random individuals from any given subpopulation to be selected as collaborators)
+ </td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>subpop.num-elites</tt><br>
+ <font size=-1> int &gt;= 0</font></td>
+ <td valign=top>(the number of elite individuals from any given subpopulation to be selected as collaborators. For generation 0, random individuals from the current population will be used.  )
+ </td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>subpop.num-prev</tt><br>
+ <font size=-1> int &gt;= 0</font></td>
+ <td valign=top>(the number of random individuals from any given subpopulation from the previous population to be selected as collaborators.   For generation 0, random individuals from the current population will be used)
+ </td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>subpop.X.select-prev</tt><br>
+ <font size=-1> instance of ec.SelectionMethod</font></td>
+ <td valign=top>(the SelectionMethod used to select partners from the individuals in subpopulation X at the previous generation)
+ </td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>subpop.X.select-current</tt><br>
+ <font size=-1> instance of ec.SelectionMethod</font></td>
+ <td valign=top>(the SelectionMethod used to select partners from the individuals in subpopulation X at the current generation.  
+ <b>WARNING.</b>  This SelectionMethod must not select based on fitness, since fitness hasn't been set yet.
+ RandomSelection is a good choice. )
+ </td></tr>
+ 
+
+ </table>
+
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 2.0 
+ */
+
+public class MultiPopCoevolutionaryEvaluator extends Evaluator
+    {
+    // the preamble for selecting partners from each subpopulation
+    public static final String P_SUBPOP = "subpop";
+
+    // the number of random partners selected from the current generation
+    public static final String P_NUM_RAND_IND = "num-current";
+    protected int numCurrent;
+
+    // the number of elite partners selected from the previous generation
+    public static final String P_NUM_ELITE = "num-elites";
+    protected int numElite;
+    Individual[][] eliteIndividuals;
+
+    // the number of random partners selected from the current and previous generations
+    public final static String P_NUM_IND = "num-prev";
+    protected int numPrev;
+    Population previousPopulation;
+
+    // the selection method used to select the other partners from the previous generation
+    public static final String P_SELECTION_METHOD_PREV = "select-prev";
+    SelectionMethod[] selectionMethodPrev;
+
+    // the selection method used to select the other partners from the current generation
+    public static final String P_SELECTION_METHOD_CURRENT = "select-current";
+    SelectionMethod[] selectionMethodCurrent;
+
+    public void setup( final EvolutionState state, final Parameter base )
+        {
+        super.setup( state, base );
+
+        // at this point, we do not know the number of subpopulations, so we read it as well from the parameters file
+        Parameter tempSubpop = new Parameter( ec.Initializer.P_POP ).push( ec.Population.P_SIZE );
+        int numSubpopulations = state.parameters.getInt( tempSubpop, null, 0 );
+        if( numSubpopulations <= 0 )
+            state.output.fatal( "Parameter not found, or it has a non-positive value.", tempSubpop );
+
+        selectionMethodPrev = new SelectionMethod[numSubpopulations];
+
+        numElite = state.parameters.getInt( base.push(P_NUM_ELITE), null, 0 );
+        if( numElite < 0 )
+            state.output.fatal( "Parameter not found, or it has an incorrect value.", base.push(P_NUM_ELITE) );
+
+        numCurrent = state.parameters.getInt( base.push(P_NUM_RAND_IND), null, 0 );
+        selectionMethodCurrent = new SelectionMethod[numSubpopulations];
+        if( numCurrent < 0 )
+            state.output.fatal( "Parameter not found, or it has an incorrect value.", base.push(P_NUM_RAND_IND) );
+        else if( numCurrent > 0 )
+            {
+            for(int i = 0; i < numSubpopulations; i++)
+                {
+                selectionMethodCurrent[i] = (SelectionMethod)
+                    (state.parameters.getInstanceForParameter(
+                        base.push(P_SUBPOP).push(""+i).push(P_SELECTION_METHOD_CURRENT),base.push(P_SELECTION_METHOD_CURRENT),SelectionMethod.class));
+                if (selectionMethodCurrent[i] == null)
+                    state.output.error("No selection method provided for subpopulation " + i,
+                        base.push(P_SUBPOP).push(""+i).push(P_SELECTION_METHOD_CURRENT),
+                        base.push(P_SELECTION_METHOD_CURRENT));
+                else selectionMethodCurrent[i].setup(state,base.push(P_SUBPOP).push(""+i).push(P_SELECTION_METHOD_CURRENT));
+                }
+            }
+
+        numPrev = state.parameters.getInt( base.push(P_NUM_IND), null, 0 );
+        selectionMethodPrev = new SelectionMethod[numSubpopulations];
+        if( numPrev < 0 )
+            state.output.fatal( "Parameter not found, or it has an incorrect value.", base.push(P_NUM_IND) );
+        else if( numPrev > 0 )
+            {
+            for(int i = 0; i < numSubpopulations; i++)
+                {
+                selectionMethodPrev[i] = (SelectionMethod)
+                    (state.parameters.getInstanceForParameter(
+                        base.push(P_SUBPOP).push(""+i).push(P_SELECTION_METHOD_PREV),base.push(P_SELECTION_METHOD_PREV),SelectionMethod.class));
+                if (selectionMethodPrev[i] == null)
+                    state.output.error("No selection method provided for subpopulation " + i,
+                        base.push(P_SUBPOP).push(""+i).push(P_SELECTION_METHOD_PREV),
+                        base.push(P_SELECTION_METHOD_PREV));
+                else selectionMethodPrev[i].setup(state,base.push(P_SUBPOP).push(""+i).push(P_SELECTION_METHOD_PREV));
+                }
+            }
+                                                                                          
+        if( numElite + numCurrent + numPrev <= 0 )
+            state.output.error( "The total number of partners to be selected should be > 0." );
+        state.output.exitIfErrors();
+        }
+
+    public boolean runComplete( final EvolutionState state )
+        {
+        return false;
+        }
+
+    public void evaluatePopulation(final EvolutionState state)
+        {
+        beforeCoevolutionaryEvaluation( state, state.population, (GroupedProblemForm)p_problem );
+
+        ((GroupedProblemForm)p_problem).preprocessPopulation(state,state.population, false);
+        performCoevolutionaryEvaluation( state, state.population, (GroupedProblemForm)p_problem );
+        ((GroupedProblemForm)p_problem).postprocessPopulation(state, state.population, false);
+
+        afterCoevolutionaryEvaluation( state, state.population, (GroupedProblemForm)p_problem );
+        }
+
+    protected void beforeCoevolutionaryEvaluation( final EvolutionState state,
+        final Population population,
+        final GroupedProblemForm prob )
+        {
+        if( state.generation == 0 )
+            {
+            //
+            // create arrays for the elite individuals in the population at the previous generation.
+            // deep clone the elite individuals as random individuals (in the initial generation, nobody has been evaluated yet).
+            //
+            
+            // deal with the elites
+            eliteIndividuals = new Individual[state.population.subpops.length][numElite];
+            // copy the first individuals in each subpopulation (they are already randomly generated)
+            for( int i = 0 ; i < eliteIndividuals.length ; i++ )
+                {
+                if( numElite > state.population.subpops[i].individuals.length )
+                    state.output.fatal( "Number of elite partners is greater than the size of the subpopulation." );
+                for( int j = 0; j < numElite ; j++ )
+                    eliteIndividuals[i][j] = (Individual)(state.population.subpops[i].individuals[j].clone());
+                }
+            }
+        }
+
+    // individuals to evaluate together
+    Individual[] inds = null;
+    // which individual should have its fitness updated as a result
+    boolean[] updates = null;
+        
+    public void performCoevolutionaryEvaluation( final EvolutionState state,
+        final Population population,
+        final GroupedProblemForm prob )
+        {
+        inds = new Individual[population.subpops.length];
+        updates = new boolean[population.subpops.length];
+                
+        // we start by warming up the selection methods
+        for( int i = 0 ; i < selectionMethodPrev.length ; i++ )
+            {
+            selectionMethodCurrent[i].prepareToProduce( state, i, 0 );
+                                
+            // do a hack here
+            Population currentPopulation = state.population;
+            state.population = previousPopulation;
+            selectionMethodPrev[i].prepareToProduce( state, i, 0 );
+            state.population = currentPopulation;
+            }
+
+
+        // build subpopulation array to pass in each time
+        int[] subpops = new int[state.population.subpops.length];
+        for(int j = 0; j < subpops.length; j++) subpops[j] = j;
+
+        // for each subpopulation
+        for(int j = 0; j < state.population.subpops.length; j++)
+            // for each individual
+            for(int i = 0; i < state.population.subpops[j].individuals.length; i++)
+                {
+                                
+                // Test against all the elites
+                for(int k = 0; k < eliteIndividuals[j].length; k++)
+                    {
+                    for(int ind = 0; ind < inds.length; ind++)
+                        {
+                        if (ind == j) { inds[ind] = state.population.subpops[j].individuals[i]; updates[ind] = true; }
+                        else  { inds[ind] = eliteIndividuals[ind][k]; updates[ind] = false; }
+                        }
+                    prob.evaluate(state,inds,updates, false, subpops, 0);
+                    }
+                                        
+                // Test against random individuals of currrent population
+                for(int k = 0; k < numCurrent; k++)
+                    {
+                    for(int ind = 0; ind < inds.length; ind++)
+                        {
+                        if (ind == j) { inds[ind] = state.population.subpops[j].individuals[i]; updates[ind] = true; }
+                        else { inds[ind] = produce(selectionMethodCurrent[j], j, i, state, 0); updates[ind] = false; }
+                        }
+                    prob.evaluate(state,inds,updates, false, subpops, 0);
+                    }
+
+                // Test against random individuals of previous population
+                for(int k = 0; k < numCurrent; k++)
+                    {
+                    for(int ind = 0; ind < inds.length; ind++)
+                        {
+                        if (ind == j) { inds[ind] = state.population.subpops[j].individuals[i]; updates[ind] = true; }
+                        else if (state.generation > 0)
+                            { 
+                            // do a hack here
+                            Population currentPopulation = state.population;
+                            state.population = previousPopulation;
+                            inds[ind] = produce(selectionMethodPrev[j], j, i, state, 0); 
+                            state.population = currentPopulation;
+                                                        
+                            updates[ind] = false;
+                            }
+                        else
+                            {
+                            inds[ind] = state.population.subpops[j].individuals[
+                                state.random[0].nextInt(state.population.subpops[j].individuals.length)];
+                            updates[ind] = false;
+                            }
+                        }
+                    prob.evaluate(state,inds,updates, false, subpops, 0);
+                    }
+                }
+
+        // now shut down the selection methods
+        for( int i = 0 ; i < selectionMethodPrev.length ; i++ )
+            {
+            selectionMethodCurrent[i].finishProducing( state, i, 0 );
+                                
+            // do a hack here
+            Population currentPopulation = state.population;
+            state.population = previousPopulation;
+            selectionMethodPrev[i].finishProducing( state, i, 0 );
+            state.population = currentPopulation;
+            }
+        }
+
+
+    protected Individual produce(SelectionMethod method, int subpopulation, int individual, EvolutionState state, int thread)
+        {
+        return state.population.subpops[subpopulation].individuals[method.produce(subpopulation, state, thread)];
+        }
+
+    protected void afterCoevolutionaryEvaluation( final EvolutionState state,
+        final Population population,
+        final GroupedProblemForm prob )
+        {
+        if( numElite > 0 )
+            {
+            for(int i = 0 ; i < state.population.subpops.length; i++)
+                loadElites( state, state.population.subpops[i], i );
+            }
+                                
+        // copy over the previous population
+        previousPopulation = (Population)(state.population.emptyClone());
+        for( int i = 0 ; i < previousPopulation.subpops.length ; i++ )
+            for( int j = 0 ; j < previousPopulation.subpops[i].individuals.length ; j++ )
+                previousPopulation.subpops[i].individuals[j] = (Individual)(state.population.subpops[i].individuals[j].clone());
+        }
+
+    void loadElites( final EvolutionState state,
+        final Subpopulation subpop,
+        int whichSubpop )
+        {
+        if (numElite==1)
+            {
+            int best = 0;
+            Individual[] oldinds = subpop.individuals;
+            for(int x=1;x<oldinds.length;x++)
+                if (oldinds[x].fitness.betterThan(oldinds[best].fitness))
+                    best = x;
+            eliteIndividuals[whichSubpop][0] = (Individual)(state.population.subpops[whichSubpop].individuals[best].clone());
+            }
+        else if (numElite > 0)  // we'll need to sort
+            {
+            int[] orderedPop = new int[subpop.individuals.length];
+            for(int x=0;x<subpop.individuals.length;x++) orderedPop[x] = x;
+
+            // sort the best so far where "<" means "more fit than"
+            QuickSort.qsort(orderedPop, new EliteComparator(subpop.individuals));
+
+            // load the top N individuals
+            for( int j = 0 ; j < numElite ; j++ )
+                eliteIndividuals[whichSubpop][j] = (Individual)(state.population.subpops[whichSubpop].individuals[orderedPop[j]].clone());
+            }
+        }
+
+    }
+
+class EliteComparator implements SortComparatorL
+    {
+    Individual[] inds;
+    public EliteComparator(Individual[] inds) {super(); this.inds = inds;}
+    public boolean lt(long a, long b)
+        { return inds[(int)a].fitness.betterThan(inds[(int)b].fitness); }
+    public boolean gt(long a, long b)
+        { return inds[(int)b].fitness.betterThan(inds[(int)a].fitness); }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/coevolve/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/coevolve/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/coevolve/README	(revision 6152)
@@ -0,0 +1,132 @@
+This package contains classes for doing certain kinds of coevolution:
+
+	- 1-population competitive coevolution
+	- 2-population parallel/parallel-previous competitive coevolution
+	- N-population parallel/parallel-previous cooperative coevolution
+
+ECJ does not presently support N-population sequential cooperative coevolution,
+but there's no reason it couldn't -- it'd just need a special Breeder and one
+or two minor tweaks to the MultiPopCoevolutionaryEvaluator.
+
+"Parallel" methods are ones in which individuals are tested against other
+individuals from the current generation.
+
+"Sequential" methods are ones in which each subpopulation in turn is tested
+against other individuals, then undergoes breeding, before other subpopulations
+are tested against it.
+
+"Parallel-previous" is the term we use to describe coevolutionary methods in
+which individuals are tested against the *previous* generations' individuals
+rather than the current ones.
+
+Coevolution is largely defined by the form of evaluation, so this package
+contains mostly Evaluators of different kinds.  The coevolution system places
+each coevolved "population" in a separate ECJ subpopulation.  Fitness
+assessment in coevolution typically consists of three parts:
+
+	1. Preprocess the full population (all subpopulations) in some way
+	2. Perform various tests on groups of individuals
+	3. Postprocess the full population, which gathers all the test
+	   results and assesses fitness on the individuals.
+
+These three elements are embodied in a Problem form called GroupedProblemForm,
+which you are required to use.  It shouldn't be surprising to you that
+your Problem subclass will need to understand what kind of coevolution it's
+being involved in and assess fitness appropriately.  The GroupedProblemForm
+class is:
+	
+	ec.coevolve.GroupedProblemForm
+
+The evaluate(...) method in GroupedProblemForm is a bit unusual.  You are
+given an array of individuals to test together -- the particular subpopulations
+from which the individuals are drawn depends on the coevolution method.  The
+subpopulations in question are also provided to you as an array.  You are also
+provided with an array of booleans indicating WHICH individuals are supposed to
+have their fitnesses updated each time.  Last, you're given a boolean telling
+you whether fitnesses should be (temporarily) updated to reflect victories
+won rather than actual scores (as in the case of Single Elimination Tournament).
+
+
+
+
+1 POPULATION COMPETITIVE COEVOLUTION
+
+Here members of a single subpopulation are tested against one another in some
+fashion, often multiple times with multiple "testing partners", before their
+fitness is assessed.  ECJ's implementation can be found in
+
+	ec.coevolve.CompetitiveEvaluator
+
+This evaluator has a number of ways that individuals can be tested.  First,
+there is the issue of competition style:
+
+	- Single Elimination Tournament.  Individuals are put into a
+	  single elimination tournament, and "winners" go on to compete
+	  further in the bracket.  It's common for single elimination
+	  tournament to be defined such that the degree to which an individual
+	  rises in the tournament is defined as his fitness.  You'll need
+	  to set a temporary fitness of individuals immediately during 
+	  evaluate(...), rather than waiting for Step 3 above, since this 
+	  "fitness" will determine which individual won a competition in the
+	  tournament.  Afterwards in postprocessing you can then set the final
+	  fitness of the individual.  Single Elimination Tournament requires
+	  that your subpopulation be a power of 2 in size.
+
+	- Round Robin.  Every individual is tested exactly once against every
+	  other individual in the subpopulation.
+
+	- K Random Opponents (One Way).  Each individual is tested against
+	  exactly K other individuals, chosen at random.
+
+	- K Random Opponents (Two Ways).  Each individual is tested against
+	  AT LEAST K other individuals, chosen at random. Here the other
+	  individuals are expected to have their fitnesses updated as well.
+ 	  In some cases an individual may have one or two more tests than
+	  the others.	
+
+
+
+
+
+2 POPULATION PARALLEL/PARALLEL-PREVIOUS COMPETITIVE COEVOLUTION
+
+Here two subpopulations are pit against one another.  Members from one
+subpopulation are tested against members of the other subpopulation.  ECJ's
+implementation is found in
+
+	ec.coevolve.MultiPopCoevolutionaryEvaluator
+
+Each individual in a subpopulation will be tested against certain individuals
+in the other subpopulation.  This class allows you to specify how many of three
+kinds of individuals to test against:
+
+	1. The fittest individuals in the other subpopulation from the
+	   previous generation
+	
+	2. Other individuals from the previous generation, selected via
+	   a selection method which you specify.
+
+	3. Random individuals from the current generation
+
+To implement 2-population methods, you'll need to set the number of
+subpopulations to 2.  You are responsible for computing the fitness of
+individuals in competitive form.
+
+
+
+
+N POPULATION PARALLEL/PARALLEL-PREVIOUS COOPERATIVE COEVOLUTION 
+
+Here N populations are tested in collaboration with one another.  Members from
+one subpopulation are tested by grouping them with a member each from the other
+subpopulations and assessing their joint fitness.  ECJ's implementation is
+again
+
+	ec.coevolve.MutltiPopCoevolutionaryEvaluator
+
+See above for more information about how this class works.  To implement
+n-population methods, you'll need to set the number of subpopulations to N
+as appropriate.  You are responsible for computing the fitness of individuals
+in some cooperative form.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/de/Best1BinDEBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/de/Best1BinDEBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/de/Best1BinDEBreeder.java	(revision 6152)
@@ -0,0 +1,108 @@
+package ec.de;
+
+import ec.*;
+import ec.util.*;
+import ec.vector.*;
+
+/* 
+ * Best1BinDEBreeder.java
+ * 
+ * Created: Wed Apr 26 17:50:17 2006
+ * By: Liviu Panait
+ */
+
+/**
+ * Best1BinDEBreeder is a differential evolution breeding operator.
+ * The code is derived from a DE algorithm, known as DE/best/1/bin "with uniform jitter", 
+ * found on page 140 of
+ * "Differential Evolution: A Practical Approach to Global Optimization"
+ * by Kenneth Price, Rainer Storn, and Jouni Lampinen.
+ *
+ * <p>Best1BinDEBreeder requires that all individuals be DoubleVectorIndividuals.
+ *
+ * <p>In short, the algorithm is as follows.  For each individual in the population, we produce a child
+ * by first selecting the best individual in the population, which we call r0.  We then
+ * select two more (different) individuals, none the original individual nor r0, called r1 and r2.
+ * We then create an individal c, defined as c = r0 + FJitter() * (r1 - r2), where FJitter() is
+ * a per-gene independent random number defined as F + F_NOISE * (random(0,1) - 0.5).  A common value for
+ * F_NOISE is 0.001.  Last, we cross over c with the
+ * original individual and produce a single child, using uniform crossover with gene-independent 
+ * crossover probability "Cr".
+ *
+ * <p>This class should be used in conjunction with 
+ * DEEvaluator, which allows the children to enter the population only if they're superior to their
+ * parents (the original individuals).  If so, they replace their parents.
+ * 
+ * <p><b>Parameters</b><br>
+ * <table>
+ * <tr><td valign=top><i>base.</i><tt>f-noise</tt><br>
+ * <font size=-1>0.0 &lt;= double </font></td>
+ * <td valign=top>The "F_NOISE" jitter value</td></tr>
+ *
+ * </table>
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 2.0
+ */
+
+public class Best1BinDEBreeder extends DEBreeder
+    {
+    /** limits on uniform noise for F */
+    public double F_NOISE = 0.0;
+        
+    public static final String P_FNOISE = "f-noise";
+        
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        super.setup(state,base);
+
+        F_NOISE = state.parameters.getDouble(base.push(P_FNOISE), null, 0.0);
+        if ( F_NOISE < 0.0 )
+            state.output.fatal( "Parameter not found, or its value is below 0.0.", base.push(P_FNOISE), null );
+        }
+        
+
+    public DoubleVectorIndividual createIndividual( final EvolutionState state,
+        int subpop,
+        int index,
+        int thread)
+        {
+        Individual[] inds = state.population.subpops[subpop].individuals;
+                
+        DoubleVectorIndividual v = (DoubleVectorIndividual)(inds[index].clone());
+
+        do
+            {
+            // select three indexes different from each other and from that of the current parent
+            int r0, r1, r2;
+            // do
+                    {
+                    r0 = bestSoFarIndex[subpop];
+                    }
+            // while( r0 == index );
+            do
+                {
+                r1 = state.random[thread].nextInt(inds.length);
+                }
+            while( r1 == r0 || r1 == index );
+            do
+                {
+                r2 = state.random[thread].nextInt(inds.length);
+                }
+            while( r2 == r1 || r2 == r0 || r2 == index );
+
+            DoubleVectorIndividual g0 = (DoubleVectorIndividual)(inds[r0]);
+            DoubleVectorIndividual g1 = (DoubleVectorIndividual)(inds[r1]);
+            DoubleVectorIndividual g2 = (DoubleVectorIndividual)(inds[r2]);
+
+            for(int i = 0; i < v.genome.length; i++)
+                v.genome[i] = g0.genome[i] + 
+                    (F + state.random[thread].nextDouble() * F_NOISE - (F_NOISE / 2.0)) *
+                    (g1.genome[i] - g2.genome[i]);
+            }
+        while(!valid(v));
+                                        
+        return crossover(state, (DoubleVectorIndividual)(inds[index]), v, thread);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/de/DEBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/de/DEBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/de/DEBreeder.java	(revision 6152)
@@ -0,0 +1,203 @@
+package ec.de;
+
+import ec.*;
+import ec.util.*;
+import ec.vector.*;
+
+/* 
+ * DEBreeder.java
+ * 
+ * Created: Wed Apr 26 17:37:59 2006
+ * By: Liviu Panait
+ */
+
+/**
+ * DEBreeder provides a straightforward Differential Evolution (DE) breeder
+ * for the ECJ system.  The code is derived from the "classic" DE algorithm, known as DE/rand/1/bin, found on page 140 of
+ * "Differential Evolution: A Practical Approach to Global Optimization"
+ * by Kenneth Price, Rainer Storn, and Jouni Lampinen.
+ *
+ * <p>DEBreeder requires that all individuals be DoubleVectorIndividuals.
+ *
+ * <p>In short, the algorithm is as follows.  For each individual in the population, we produce a child
+ * by selecting three (different) individuals, none the original individual, called r0, r1, and r2.
+ * We then create an individal c, defined as c = r0 + F * (r1 - r2).  Last, we cross over c with the
+ * original individual and produce a single child, using uniform crossover with gene-independent 
+ * crossover probability "Cr".
+ *
+ * <p>This class should be used in conjunction with 
+ * DEEvaluator, which allows the children to enter the population only if they're superior to their
+ * parents (the original individuals).  If so, they replace their parents.
+ * 
+ * <p><b>Parameters</b><br>
+ * <table>
+ * <tr><td valign=top><i>base.</i><tt>f</tt><br>
+ * <font size=-1>0.0 &lt;= double &lt;= 1.0 </font></td>
+ * <td valign=top>The "F" mutation scaling factor</td></tr>
+ *
+ * <tr><td valign=top><i>base.</i><tt>cr</tt><br>
+ * <font size=-1>0.0 &lt;= double &lt;= 1.0 </font></td>
+ * <td valign=top>The "Cr" probability of crossing over genes</td></tr>
+ * </table>
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 2.0
+ */
+
+public class DEBreeder extends Breeder
+    {
+    public static final double CR_UNSPECIFIED = -1;
+
+    /** Scaling factor for mutation */
+    public double F = 0.0;
+    /** Probability of crossover per gene */
+    public double Cr = CR_UNSPECIFIED;
+        
+    public static final String P_F = "f";
+    public static final String P_Cr = "cr";
+        
+    /** the previous population is stored in order to have parents compete directly with their children */
+    public Population previousPopulation = null;
+
+    /** the best individuals in each population (required by some DE breeders).  It's not required by DEBreeder's algorithm */
+    public int[] bestSoFarIndex = null;
+
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        if (!state.parameters.exists(base.push(P_Cr), null))  // it wasn't specified -- hope we know what we're doing
+            Cr = CR_UNSPECIFIED;
+        else
+            {
+            Cr = state.parameters.getDouble(base.push(P_Cr),null,0.0);
+            if ( Cr < 0.0 || Cr > 1.0 )
+                state.output.fatal( "Parameter not found, or its value is outside of [0.0,1.0].", base.push(P_Cr), null );
+            }
+                        
+        F = state.parameters.getDouble(base.push(P_F),null,0.0);
+        if ( F < 0.0 || F > 1.0 )
+            state.output.fatal( "Parameter not found, or its value is outside of [0.0,1.0].", base.push(P_F), null );
+        }
+
+    // this function is called just before chldren are to be bred
+    public void prepareDEBreeder(EvolutionState state)
+        {
+        // update the bestSoFar for each population
+        if( bestSoFarIndex == null || state.population.subpops.length != bestSoFarIndex.length )
+            bestSoFarIndex = new int[state.population.subpops.length];
+
+        for( int subpop = 0 ; subpop < state.population.subpops.length ; subpop++ )
+            {
+            Individual[] inds = state.population.subpops[subpop].individuals;
+            bestSoFarIndex[subpop] = 0;
+            for( int j = 1 ; j < inds.length ; j++ )
+                if( inds[j].fitness.betterThan(inds[bestSoFarIndex[subpop]].fitness) )
+                    bestSoFarIndex[subpop] = j;
+            }
+        }
+
+    public Population breedPopulation(EvolutionState state)
+        {
+        // double check that we're using DEEvaluator
+        if (!(state.evaluator instanceof DEEvaluator))
+            state.output.warnOnce("DEEvaluator not used, but DEBreeder used.  This is almost certainly wrong.");
+                
+        // prepare the breeder (some global statistics might need to be computed here)
+        prepareDEBreeder(state);
+
+        // create the new population
+        Population newpop = (Population) state.population.emptyClone();
+
+        // breed the children
+        for( int subpop = 0 ; subpop < state.population.subpops.length ; subpop++ )
+            {
+            if (state.population.subpops[subpop].individuals.length < 4)  // Magic number, sorry.  createIndividual() requires at least 4 individuals in the pop
+                state.output.fatal("Subpopulation " + subpop + " has fewer than four individuals, and so cannot be used with DEBreeder.");
+            
+            Individual[] inds = newpop.subpops[subpop].individuals;
+            for( int i = 0 ; i < inds.length ; i++ )
+                {
+                newpop.subpops[subpop].individuals[i] = createIndividual( state, subpop, i, 0);  // unthreaded for now
+                }
+            }
+
+        // store the current population for competition with the new children
+        previousPopulation = state.population;
+        return newpop;
+        }
+
+    /** Tests the Individual to see if its values are in range. */
+    public boolean valid(DoubleVectorIndividual ind)
+        {
+        FloatVectorSpecies species = (FloatVectorSpecies)(ind.species);
+        return (!(species.mutationIsBounded && !ind.isInRange()));
+        }
+
+    public DoubleVectorIndividual createIndividual(EvolutionState state,
+        int subpop,
+        int index,
+        int thread)
+        {
+        Individual[] inds = state.population.subpops[subpop].individuals;
+
+        DoubleVectorIndividual v = (DoubleVectorIndividual)(inds[index].clone());
+        do
+            {
+            // select three indexes different from each other and from that of the current parent
+            int r0, r1, r2;
+            do
+                {
+                r0 = state.random[thread].nextInt(inds.length);
+                }
+            while( r0 == index );
+            do
+                {
+                r1 = state.random[thread].nextInt(inds.length);
+                }
+            while( r1 == r0 || r1 == index );
+            do
+                {
+                r2 = state.random[thread].nextInt(inds.length);
+                }
+            while( r2 == r1 || r2 == r0 || r2 == index );
+
+            DoubleVectorIndividual g0 = (DoubleVectorIndividual)(inds[r0]);
+            DoubleVectorIndividual g1 = (DoubleVectorIndividual)(inds[r1]);
+            DoubleVectorIndividual g2 = (DoubleVectorIndividual)(inds[r2]);
+
+            for(int i = 0; i < v.genome.length; i++)
+                v.genome[i] = g0.genome[i] + F * (g1.genome[i] - g2.genome[i]);
+            }
+        while(!valid(v));
+
+        return crossover(state, (DoubleVectorIndividual)(inds[index]), v, thread);
+        }
+
+
+    /** Crosses over child with target, storing the result in child and returning it.  The default
+        procedure copies each value from the target, with independent probability CROSSOVER, into
+        the child.  The crossover guarantees that at least one child value, chosen at random, will
+        not be overwritten.  Override this method to perform some other kind of crossover. */
+                
+    public DoubleVectorIndividual crossover(EvolutionState state, DoubleVectorIndividual target, DoubleVectorIndividual child, int thread)
+        {
+        if (Cr == CR_UNSPECIFIED)
+            state.output.warnOnce("Differential Evolution Parameter cr unspecified.  Assuming cr = 0.5");
+                        
+        // first, hold one value in abeyance
+        int index = state.random[thread].nextInt(child.genome.length);
+        double val = child.genome[index];
+                
+        // do the crossover
+        for(int i = 0; i < child.genome.length; i++)
+            {
+            if (state.random[thread].nextDouble() < Cr)
+                child.genome[i] = target.genome[i];
+            }
+                
+        // reset the one value so it's not just a duplicate copy
+        child.genome[index] = val;
+        
+        return child;
+        }
+                        
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/de/DEEvaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/de/DEEvaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/de/DEEvaluator.java	(revision 6152)
@@ -0,0 +1,56 @@
+package ec.de;
+
+import ec.*;
+import ec.simple.*;
+
+/* 
+ * DEEvaluator.java
+ * 
+ * Created: Fri Aug 13 11:20:54 EDT 2010
+ * By: Sean Luke
+ */
+
+/**
+ * DEEvaluator is a simple subclass of SimpleEvaluator which first evaluates the population, then
+ * compares each population member against the parent which had created it in Differential Evolution.
+ * The parents are stored in DEBreeder.previousPopulation.  If the parent is superior to the child,
+ * then the parent replaces the child in the population and the child is discarded.  This does not
+ * happen in the first generation, as there are of course no parents yet.
+ *
+ * <p>This code could have been moved into the Breeder of course.  But then the better of the parents
+ * and children would not appear in standard Statistics objects.  So we've broken it out here.
+ *
+ * <p>The full description of Differential Evolution may be found in the book
+ * "Differential Evolution: A Practical Approach to Global Optimization"
+ * by Kenneth Price, Rainer Storn, and Jouni Lampinen.
+ * 
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class DEEvaluator extends SimpleEvaluator
+    {
+    public void evaluatePopulation(EvolutionState state)
+        {
+        super.evaluatePopulation(state);
+
+        if( state.breeder instanceof DEBreeder )
+            {
+            Population previousPopulation = ((DEBreeder)(state.breeder)).previousPopulation; // for faster access
+            if( previousPopulation != null )
+                {
+                if( previousPopulation.subpops.length != state.population.subpops.length )
+                    state.output.fatal( "DEEvaluator requires that the population have the same number of subpopulations every generation.");
+                for( int i = 0 ; i < previousPopulation.subpops.length ; i++ )
+                    {
+                    if( state.population.subpops[i].individuals.length != previousPopulation.subpops[i].individuals.length )
+                        state.output.fatal( "DEEvaluator requires that subpopulation " + i + " should have the same number of individuals in all generations." );
+                    for( int j = 0 ; j < state.population.subpops[i].individuals.length ; j++ )
+                        if( previousPopulation.subpops[i].individuals[j].fitness.betterThan( state.population.subpops[i].individuals[j].fitness ) )
+                            state.population.subpops[i].individuals[j] = previousPopulation.subpops[i].individuals[j];
+                    }
+                }
+            }
+        else state.output.fatal("DEEvaluator requires DEBreeder to be the breeder.");
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/de/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/de/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/de/README	(revision 6152)
@@ -0,0 +1,96 @@
+This package implements various Differential Evolution algorithms from
+"Differential Evolution: A Practical Approach to Global Optimization"
+by Kenneth Price, Rainer Storn, and Jouni Lampinen.  
+
+ECJ's implementation of Differential Evolution requires that the
+user specify one of several Breeders, and also that you (optionally but
+highly suggested) use a specific Evaluator.
+
+The Breeder options implement various Differential Evolution Algorithms.
+Options include:
+
+breed = 	ec.de.DEBreeder
+breed = 	ec.de.Best1BinDEBreeder
+breed = 	ec.de.Rand1EitherOrDEBreeder
+
+The Evaluator is ec.de.DEEvaluator:
+
+eval =          ec.de.DEEvaluator
+
+The ec/app/ecsuite/de.params file contains an example.
+
+
+ECJ's DE implementation (for now)
+---------------------------------
+
+ECJ implements Differential Evolution by largely by replacing the Breeder.
+The various DE breeders work like this: for each individual i in the 
+population, construct a new individual using a function called 
+createIndividual(..., i, ...).  Then replace the entire population with the
+newly constructed individuals only if they are superior to the parents
+from which they were derived.  The "only if" part is implemented by DEEvaluator,
+and if you don't use it, the children will directly replace their parents.
+
+In DE, all individuals are DoubleVectorIndividuals.
+
+DEBreeder has an additional method called crossover(...) which crosses the
+original parent into the child.  Some operators use this method, others
+do not.  You can override the method to perform your own custom kind of crossover;
+the default does a uniform crossover, while guaranteeing that at least one
+gene (chosen at random) from the child will be preserved.
+
+The different breeders differ largely based on how 
+createIndividual(..., i, ...) is implemented.  In all versions,
+createIndividual(..., i, ...) begins by choosing three random individuals
+r0, r1, and r2 which are different from one another and from i.  Let j
+be the new individual.
+
+There are four parameters which may affect the operation below:
+
+F:          scaling factor for mutating individuals
+CR:         the probability, per-gene, of crossing over
+F_NOISE:    Bounds on random noise added to F
+PF:         Probability of picking one of two subalgorithms for mutation
+
+
+The default version, implemented by
+
+	ec.de.DEBreeder
+
+... creates a new individual as follows.
+
+j[g] <-- r0[g] + F * (r1[g] - r2[g])
+
+This is the "classic" DE algorithm
+
+
+The next version, implemented by
+
+        ec.de.Best1BinDEBreeder
+
+... works like this.  We first determine the best individual in the
+population.  Then we say:
+
+j[g] <-- best[g] + (F + random(-F_NOISE / 2, F_NOISE / 2)) * (r1[g] - r2[g])
+
+
+The final version, implemented by
+
+	ec.de.Rand1EitherOrDEBreeder	`  
+
+... works like this.  First we flip a coin of probability PF.  If it comes
+up 'true', then we generate the individual as the classic form:
+
+j[g] <-- r0[g] + F * (r1[g] - r2[g])
+
+... else we generate the individual as:
+
+j[g] <-- r0[g] + 0.5 * (F + 1) * (r1[g] + r2[g] - 2 * r0[g])
+
+
+Don't like any of these?  It should be fairly straightforward to copy an
+existing one and modify it.   
+
+Note that DEBreeder is a subclass of Breeder and does NOT implement
+multithreaded breeding: but DEEvaluator, as a subclass of SimpleEvaluator,
+DOES implement multithreaded evaluation.
Index: branches/OKBJavaConnector/ECJClient/src/ec/de/Rand1EitherOrDEBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/de/Rand1EitherOrDEBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/de/Rand1EitherOrDEBreeder.java	(revision 6152)
@@ -0,0 +1,109 @@
+package ec.de;
+
+import ec.*;
+import ec.util.*;
+import ec.vector.*;
+
+/* 
+ * Rand1EitherOrDEBreeder.java
+ * 
+ * Created: Wed Apr 26 18:01:11 2006
+ * By: Liviu Panait
+ */
+
+/**
+ * Rand1EitherOrDEBreeder is a differential evolution breeding operator.
+ * The code is derived from a DE algorithm, known as DE/rand/1/either-or, 
+ * found on page 141 of
+ * "Differential Evolution: A Practical Approach to Global Optimization"
+ * by Kenneth Price, Rainer Storn, and Jouni Lampinen.
+ *
+ * <p>Rand1EitherOrDEBreeder requires that all individuals be DoubleVectorIndividuals.
+ *
+ * <p>In short, the algorithm is as follows.  For each individual in the population, we produce a child
+ * by selecting three (different) individuals, none the original individual, called r0, r1, and r2.
+ * We then create an individal c, defined either c = r0 + F * (r1 - r2), or as c = r0 + 0.5 * (F+1) * (r1 + r2 - 2 * r0),
+ * depending on a coin flip of probability "PF" (if 'true', the first equation is used, else the second).
+ * Unlike the other DEBreeders in this package, we do *not* cross over the child with the original individual.
+ * In fact, if the crossover probability is specified, Rand1EitherOrDEBreeder will issue a warning that it's
+ * not using it.
+ *
+ * <p>This class should be used in conjunction with 
+ * DEEvaluator, which allows the children to enter the population only if they're superior to their
+ * parents (the original individuals).  If so, they replace their parents.
+ * 
+ * <p><b>Parameters</b><br>
+ * <table>
+ * <tr><td valign=top><i>base.</i><tt>pf</tt><br>
+ * <font size=-1>0.0 &lt;= double &lt;= 1.0 </font></td>
+ * <td valign=top>The "PF" probability of mutation type</td></tr>
+ * </table>
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 2.0
+ */
+
+
+public class Rand1EitherOrDEBreeder extends DEBreeder
+    {
+    public double PF = 0.0;
+        
+    public static final String P_PF = "pf";
+        
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        super.setup(state,base);
+
+        PF = state.parameters.getDouble(base.push(P_PF),null,0.0);
+        if ( PF < 0.0 || PF > 1.0 )
+            state.output.fatal( "Parameter not found, or its value is outside of [0.0,1.0].", base.push(P_PF), null );
+                        
+        if (state.parameters.exists(base.push(P_Cr), null))
+            state.output.warning("Crossover parameter specified, but Rand1EitherOrDEBreeder does not use crossover.", base.push(P_Cr));
+        }
+        
+    public DoubleVectorIndividual createIndividual( final EvolutionState state,
+        int subpop,
+        int index,
+        int thread )
+        {
+        Individual[] inds = state.population.subpops[subpop].individuals;
+
+        DoubleVectorIndividual v = (DoubleVectorIndividual)(inds[index].clone());
+
+        do
+            {
+            // select three indexes different from each other and from that of the current parent
+            int r0, r1, r2;
+            do
+                {
+                r0 = state.random[thread].nextInt(inds.length);
+                }
+            while( r0 == index );
+            do
+                {
+                r1 = state.random[thread].nextInt(inds.length);
+                }
+            while( r1 == r0 || r1 == index );
+            do
+                {
+                r2 = state.random[thread].nextInt(inds.length);
+                }
+            while( r2 == r1 || r2 == r0 || r2 == index );
+
+            DoubleVectorIndividual g0 = (DoubleVectorIndividual)(inds[r0]);
+            DoubleVectorIndividual g1 = (DoubleVectorIndividual)(inds[r1]);
+            DoubleVectorIndividual g2 = (DoubleVectorIndividual)(inds[r2]);
+
+            for(int i = 0; i < v.genome.length; i++)
+                if (state.random[thread].nextBoolean(PF))
+                    v.genome[i] = g0.genome[i] + F * (g1.genome[i] - g2.genome[i]);
+                else
+                    v.genome[i] = g0.genome[i] + 0.5 * (F+1) * (g1.genome[i] + g2.genome[i] - 2 * g0.genome[i]);
+            }
+        while(!valid(v));
+
+        return v;       // no crossover is performed
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/de/de.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/de/de.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/de/de.params	(revision 6152)
@@ -0,0 +1,27 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../simple/simple.params
+
+eval = ec.de.DEEvaluator
+breed = ec.de.DEBreeder
+# Other breed choices: ec.de.Best1BinDEBreeder, ec.de.Rand1EitherOrDEBreeder
+
+# DE has certain parameters you must set.  Note that these parameters
+# are fairly sensitive to the problem at hand.
+
+# Scaling factor for mutation, used by all breeders:
+breed.f = 0.1
+
+# Gene-independent probability of crossover, used only by
+# DEBreeder and Best1BinDEBreeder
+breed.cr = 0.5
+
+# Scaling factor for noise on F, used only by Best1BinDEBreeder
+breed.f-noise = 0.001
+
+# Probability of picking the "classic" algorithm versus the alternate, 
+# only ud by Rand1EitherOrDEBreeder
+breed.pf = 0.5
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/Console.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/Console.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/Console.java	(revision 6152)
@@ -0,0 +1,1169 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Feb 3, 2005
+ *
+ */
+package ec.display;
+
+import java.awt.*;
+import javax.swing.*;
+import ec.util.*;
+
+import java.awt.BorderLayout;
+import java.awt.FileDialog;
+import java.awt.GraphicsConfiguration;
+import java.awt.HeadlessException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OptionalDataException;
+import java.util.Iterator;
+import java.util.Vector;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JSeparator;
+import javax.swing.JTabbedPane;
+import javax.swing.JToolBar;
+import javax.swing.JTree;
+import javax.swing.filechooser.FileFilter;
+
+import ec.EvolutionState;
+import ec.Evolve;
+import ec.util.BadParameterException;
+import ec.util.Checkpoint;
+import ec.util.MersenneTwisterFast;
+import ec.util.Output;
+import ec.util.ParamClassLoadException;
+import ec.util.Parameter;
+import ec.util.ParameterDatabase;
+import ec.util.Version;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.BoxLayout;
+/**
+ * @author spaus
+ *
+ */
+public class Console extends JFrame 
+    {
+    
+    static final int DEFAULT_HEIGHT = 500;
+    static final int DEFAULT_WIDTH = 975;
+    ParameterDatabase parameters = null;
+    EvolutionState state = null;
+    Thread playThread = null;
+    boolean playing = false;
+    boolean paused = false;
+    Object buttonLock = new Object();
+    Object cleanupLock = new Object();
+    int currentJob;
+    final String[] clArgs;
+    
+    javax.swing.JPanel jContentPane = null;
+    javax.swing.JMenuBar jJMenuBar = null;
+    javax.swing.JMenu fileMenu = null;
+    javax.swing.JMenu helpMenu = null;
+    javax.swing.JMenuItem exitMenuItem = null;
+    javax.swing.JMenuItem aboutMenuItem = null;
+    JTabbedPane jTabbedPane = null;
+    JToolBar jToolBar = null;
+    JButton playButton = null;
+    JButton pauseButton = null;
+    JButton stopButton = null;
+    
+    JButton stepButton = null;
+    JMenuItem loadParametersMenuItem = null;
+    ParametersPanel paramPanel = null;
+    ControlPanel conPanel = null;
+    /**
+     * @throws java.awt.HeadlessException
+     */
+    public Console(String[] clArgs) throws HeadlessException 
+        {
+        super();
+        initialize();
+        this.clArgs = clArgs;
+        }
+    
+    /**
+     * @param gc
+     */
+    public Console(GraphicsConfiguration gc, String[] clArgs) 
+        {
+        super(gc);
+        initialize();
+        this.clArgs = clArgs;
+        }
+    
+    /**
+     * @param title
+     * @throws java.awt.HeadlessException
+     */
+    public Console(String title, String[] clArgs) throws HeadlessException 
+        {
+        super(title);
+        initialize();
+        this.clArgs = clArgs;
+        }
+    
+    /**
+     * @param title
+     * @param gc
+     */
+    public Console(String title, GraphicsConfiguration gc, String[] clArgs) 
+        {
+        super(title, gc);
+        initialize();
+        this.clArgs = clArgs;
+        }
+    
+    /**
+     * This method initializes jTabbedPane      
+     *  
+     * @return javax.swing.JTabbedPane  
+     */    
+    JTabbedPane getJTabbedPane() 
+        {
+        if (jTabbedPane == null) 
+            {
+            jTabbedPane = new JTabbedPane();
+            conPanel = new ControlPanel(this);
+            conPanel.disableControls();
+            jTabbedPane.add("Control",conPanel);
+            paramPanel = new ParametersPanel(this);
+            jTabbedPane.add("Parameters",paramPanel);
+            jTabbedPane.addTab("Statistics", null, getStatisticsPane(), null);
+            jTabbedPane.addTab("Inspection", null, getInspectionPane(), null);
+            }
+        return jTabbedPane;
+        }
+    
+    /**
+     * This method initializes jToolBar 
+     *  
+     * @return javax.swing.JToolBar     
+     */    
+    JToolBar getJToolBar() 
+        {
+        if (jToolBar == null) 
+            {
+            jToolBar = new JToolBar();
+            jToolBar.add(getPlayButton());
+            jToolBar.add(getStepButton());
+            jToolBar.add(getPauseButton());
+            jToolBar.add(getStopButton());
+            }
+        return jToolBar;
+        }
+    
+    /**
+     * This method initializes jButton  
+     *  
+     * @return javax.swing.JButton      
+     */    
+    JButton getPlayButton() 
+        {
+        if (playButton == null) 
+            {
+            playButton = new JButton();
+            playButton.setIcon(new ImageIcon(getClass().getResource("/ec/display/Play.png")));
+            playButton.setEnabled(false);
+            playButton.setToolTipText("Play");
+            playButton.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {
+                    synchronized(buttonLock) 
+                        {
+                        if (!playing || (playing && paused)) 
+                            {
+                            if (!paused) 
+                                {
+                                currentJob = 0;
+                                spawnPlayThread(false);
+                                } else 
+                                {
+                                resumePlayThread();
+                                }
+                            playButton.setEnabled(false);
+                            stepButton.setEnabled(false);
+                            pauseButton.setEnabled(true);
+                            stopButton.setEnabled(true);
+                            conPanel.disableControls();
+                            paused = false;
+                            playing = true;
+                            }
+                        }
+                    }
+                });
+            }
+        return playButton;
+        }
+    /**
+     * This method initializes jButton1 
+     *  
+     * @return javax.swing.JButton      
+     */    
+    JButton getPauseButton() 
+        {
+        if (pauseButton == null) 
+            {
+            pauseButton = new JButton();
+            pauseButton.setIcon(new ImageIcon(getClass().getResource("/ec/display/Pause.png")));
+            pauseButton.setEnabled(false);
+            pauseButton.setToolTipText("Pause");
+            pauseButton.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {
+                    synchronized(buttonLock) 
+                        {
+                        if (playing && !paused) 
+                            {
+                            paused = true;
+                            pausePlayThread();
+                            stepButton.setEnabled(true);
+                            playButton.setEnabled(true);
+                            pauseButton.setEnabled(false);
+                            }
+                        }
+                    }
+                });
+            }
+        return pauseButton;
+        }
+    /**
+     * This method initializes jButton2 
+     *  
+     * @return javax.swing.JButton      
+     */    
+    JButton getStopButton() 
+        {
+        if (stopButton == null) 
+            {
+            stopButton = new JButton();
+            stopButton.setIcon(
+                new ImageIcon(
+                    getClass().getResource("/ec/display/Stop.png")));
+            stopButton.setEnabled(false);
+            stopButton.setToolTipText("Stop");
+            stopButton.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {
+                    synchronized(buttonLock) 
+                        {
+                        if (playing) 
+                            {
+                            killPlayThread();
+                            stopButton.setEnabled(false);
+                            pauseButton.setEnabled(false);
+                            stepButton.setEnabled(true);
+                            playButton.setEnabled(true);
+                            conPanel.enableControls();
+                            paused = false;
+                            playing = false;
+                            }
+                        }
+                    }
+                });
+            }
+        return stopButton;
+        }
+    /**
+     * This method initializes jButton  
+     *  
+     * @return javax.swing.JButton      
+     */    
+    JButton getStepButton() 
+        {
+        if (stepButton == null) 
+            {
+            stepButton = new JButton();
+            stepButton.setEnabled(false);
+            stepButton.setIcon(new ImageIcon(getClass().getResource("/ec/display/Step.png")));
+            stepButton.setPressedIcon(new ImageIcon(getClass().getResource("/ec/display/Stepping.png")));
+            stepButton.setToolTipText("Step");
+            stepButton.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {
+                    synchronized(buttonLock) 
+                        {
+                        paused = true;
+                        setStep(true);
+                        if (!playing) 
+                            {
+                            spawnPlayThread(false);
+                            stopButton.setEnabled(true);
+                            conPanel.disableControls();
+                            playing = true;
+                            }
+                        
+                        synchronized(playThread) 
+                            {
+                            playThread.notify();
+                            }
+                        }
+                    }
+                });
+            }
+        return stepButton;
+        }
+    /**
+     * This method initializes jMenuItem        
+     *  
+     * @return javax.swing.JMenuItem    
+     */    
+    JMenuItem getLoadParametersMenuItem() 
+        {
+        if (loadParametersMenuItem == null) 
+            {
+            final String PARAMFILE_EXT = "params";
+            this.getAboutMenuItem();
+            loadParametersMenuItem = new JMenuItem();
+            loadParametersMenuItem.setText("Load Parameters...");
+            loadParametersMenuItem.addActionListener(new java.awt.event.ActionListener() 
+                {
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {    
+                    FileDialog fileDialog = new FileDialog(Console.this,"Open...",FileDialog.LOAD);
+                    fileDialog.setDirectory(System.getProperty("user.dir"));
+                    fileDialog.setFile("*."+PARAMFILE_EXT);
+                    fileDialog.setVisible(true);
+                    String fileName = fileDialog.getFile();
+                    while (fileName != null && !fileName.endsWith("."+PARAMFILE_EXT)) 
+                        {
+                        JOptionPane optPane = new JOptionPane(fileDialog.getFile()+" is not a legal parameters file",JOptionPane.ERROR_MESSAGE);
+                        JDialog optDialog = optPane.createDialog(Console.this,"Error!");
+                        optDialog.setVisible(true);
+                        fileDialog.setFile("*."+PARAMFILE_EXT);
+                        fileDialog.setVisible(true);
+                        fileName = fileDialog.getFile();
+                        }
+                    
+                    if (fileName != null) 
+                        {    
+                        File f = new File(fileDialog.getDirectory(), fileName);
+                        Console.this.loadParameters(f);
+                        playButton.setEnabled(true);
+                        stepButton.setEnabled(true);
+                        conPanel.enableControls();
+                        }
+                    }
+                });
+            }
+        return loadParametersMenuItem;
+        }
+    
+    /**
+     * This method initializes jMenuItem        
+     *  
+     * @return javax.swing.JMenuItem    
+     */    
+    JMenuItem getLoadCheckpointMenuItem() 
+        {
+        if (loadCheckpointMenuItem == null) 
+            {
+            loadCheckpointMenuItem = new JMenuItem();
+            loadCheckpointMenuItem.setText("Load Checkpoint...");
+            loadCheckpointMenuItem.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {    
+                    JFileChooser chooser = new JFileChooser(
+                        System.getProperty("user.dir"));
+                    chooser.setFileFilter(new FileFilter() 
+                        {
+                        public boolean accept( File f )
+                            
+                            {
+                            if ( f.isDirectory() )
+                                return true;
+                            
+                            String extension = null;
+                            String filename = f.getName();
+                            int idx = filename.lastIndexOf( '.' );
+                            if ( idx > 0 && idx < filename.length() - 1 )
+                                
+                                {
+                                extension = filename.substring( idx + 1 ).toLowerCase();
+                                }
+                            
+                            if ( extension != null )
+                                
+                                {
+                                if ( extension.equals( "gz" ) )
+                                    return true;
+                                }
+                            
+                            return false;
+                            }
+                        
+                        public String getDescription()
+                            
+                            {
+                            return "Checkpoint Files";
+                            }
+                        });
+                    int option = chooser.showOpenDialog( Console.this );
+                    if ( option == JFileChooser.APPROVE_OPTION )
+                        
+                        {
+                        File f = chooser.getSelectedFile();
+                        Console.this.restoreFromCheckpoint(f);
+                        playButton.setEnabled(true);
+                        stepButton.setEnabled(true);
+                        }
+                    }
+                });
+            }
+        return loadCheckpointMenuItem;
+        }
+    
+    /**
+     * This method initializes jTabbedPane1     
+     *  
+     * @return javax.swing.JTabbedPane  
+     */    
+    JTabbedPane getStatisticsPane() 
+        {
+        if (statisticsPane == null) 
+            {
+            statisticsPane = new JTabbedPane();
+            }
+        return statisticsPane;
+        }
+    /**
+     * This method initializes jTabbedPane2     
+     *  
+     * @return javax.swing.JTabbedPane  
+     */    
+    JTabbedPane getInspectionPane() 
+        {
+        if (inspectionPane == null) 
+            {
+            inspectionPane = new JTabbedPane();
+            }
+        return inspectionPane;
+        }
+    
+    /**
+     * This method initializes jPanel       
+     *      
+     * @return javax.swing.JPanel   
+     */    
+    JPanel getStatusPane() 
+        {
+        if (statusPane == null) 
+            {
+            statusPane = new JPanel();
+            statusPane.setLayout(new BoxLayout(statusPane, BoxLayout.X_AXIS));
+            statusPane.add(getStatusField(), null);
+            }
+        return statusPane;
+        }
+    /**
+     * This method initializes jTextField   
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getStatusField() 
+        {
+        if (statusField == null) 
+            {
+            statusField = new JTextField();
+            statusField.setEditable(false);
+            }
+        return statusField;
+        }
+    public static void main(String[] args) 
+        {
+        Console application = new Console(args);
+        application.setVisible(true);
+        }
+    
+    /**
+     * This method initializes this
+     * 
+     * @return void
+     */
+    void initialize() 
+        {
+        this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+        this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
+        this.setJMenuBar(getJJMenuBar());
+        this.setContentPane(getJContentPane());
+        this.setJMenuBar(getJJMenuBar());
+        this.setContentPane(getJContentPane());
+        this.setTitle("ECJ Console");
+        }
+    /**
+     * This method initializes jContentPane
+     * 
+     * @return javax.swing.JPanel
+     */
+    javax.swing.JPanel getJContentPane() 
+        {
+        if(jContentPane == null) 
+            {
+            jContentPane = new javax.swing.JPanel();
+            jContentPane.setLayout(new BorderLayout());
+            jContentPane.add(getJTabbedPane(), java.awt.BorderLayout.CENTER);
+            jContentPane.add(getJToolBar(), java.awt.BorderLayout.NORTH);
+            jContentPane.add(getStatusPane(), java.awt.BorderLayout.SOUTH);
+            }
+        return jContentPane;
+        }
+    /**
+     * This method initializes jJMenuBar        
+     *  
+     * @return javax.swing.JMenuBar     
+     */    
+    javax.swing.JMenuBar getJJMenuBar() 
+        {
+        if (jJMenuBar == null) 
+            {
+            jJMenuBar = new javax.swing.JMenuBar();
+            jJMenuBar.add(getFileMenu());
+            jJMenuBar.add(getHelpMenu());
+            }
+        return jJMenuBar;
+        }
+    /**
+     * This method initializes jMenu    
+     *  
+     * @return javax.swing.JMenu        
+     */    
+    javax.swing.JMenu getFileMenu() 
+        {
+        if (fileMenu == null) 
+            {
+            fileMenu = new javax.swing.JMenu();
+            fileMenu.setText("File");
+            fileMenu.add(getLoadParametersMenuItem());
+            fileMenu.add(getLoadCheckpointMenuItem());
+            fileMenu.add(new JSeparator());
+            fileMenu.add(getExitMenuItem());
+            }
+        return fileMenu;
+        }
+    /**
+     * This method initializes jMenu    
+     *  
+     * @return javax.swing.JMenu        
+     */    
+    javax.swing.JMenu getHelpMenu() 
+        {
+        if (helpMenu == null) 
+            {
+            helpMenu = new javax.swing.JMenu();
+            helpMenu.setText("Help");
+            helpMenu.add(getAboutMenuItem());
+            }
+        return helpMenu;
+        }
+    /**
+     * This method initializes jMenuItem        
+     *  
+     * @return javax.swing.JMenuItem    
+     */    
+    javax.swing.JMenuItem getExitMenuItem() 
+        {
+        if (exitMenuItem == null) 
+            {
+            exitMenuItem = new javax.swing.JMenuItem();
+            exitMenuItem.setText("Exit");
+            exitMenuItem.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {    
+                    System.exit(0);
+                    }
+                });
+            }
+        return exitMenuItem;
+        }
+    
+    JFrame aboutFrame;
+    
+    /**
+     * This method initializes jMenuItem        
+     *  
+     * @return javax.swing.JMenuItem    
+     */    
+    javax.swing.JMenuItem getAboutMenuItem() 
+        {
+        if (aboutMenuItem == null) 
+            {
+            aboutMenuItem = new javax.swing.JMenuItem();
+            aboutMenuItem.setText("About ECJ");
+            aboutMenuItem.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    
+                    {    
+                    if (aboutFrame == null)
+                        
+                        {
+                        // construct the frame
+                        aboutFrame = new JFrame("About ECJ");
+                        JPanel p = new JPanel();  // 1.3.1 only has borders for JComponents, not Boxes
+                        p.setBorder(BorderFactory.createEmptyBorder(25,30,30,30));
+                        Box b = new Box(BoxLayout.Y_AXIS);
+                        p.add(b,BorderLayout.CENTER);
+                        aboutFrame.getContentPane().add(p,BorderLayout.CENTER);
+                        aboutFrame.setResizable(false);
+                        Font small = new Font("Dialog",0,10);
+
+                        // start dumping in text
+                        JLabel j = new JLabel("ECJ");
+                        j.setFont(new Font("Serif",0,36));
+                        b.add(j);
+                                
+                        j = new JLabel("An Evolutionary Computation System");
+                        b.add(j);
+                        j = new JLabel("Version " +Version.version);
+                        b.add(j);
+                        JLabel spacer = new JLabel(" ");
+                        spacer.setFont(new Font("Dialog",0,6));
+                        b.add(spacer);
+
+                        j = new JLabel("By " + Version.author);
+                        b.add(j);
+                        
+                        spacer = new JLabel(" ");
+                        spacer.setFont(new Font("Dialog",0,6));
+                        b.add(spacer);
+                        
+                        j = new JLabel("Contributors:");
+                        b.add(j);
+                        j = new JLabel("     " + Version.contributors);
+                        b.add(j);
+                        j = new JLabel("     " + Version.contributors2);
+                        b.add(j);
+                            
+                        spacer = new JLabel(" ");
+                        spacer.setFont(new Font("Dialog",0,6));
+                        b.add(spacer);
+                        
+                        // can't figure out why I need a second one...
+                        spacer = new JLabel(" ");
+                        spacer.setFont(new Font("Dialog",0,6));
+                        b.add(spacer);
+
+                        j = new JLabel("ECJ's homepage is " + Version.authorURL);
+                        j.setFont(small);
+                        b.add(j);
+
+                        j = new JLabel("For help, send mail to " + Version.authorEmail0 + "@" + 
+                            Version.authorEmail1);
+                        j.setFont(small);
+                        b.add(j);
+
+                        j = new JLabel("     " + Version.authorEmail2);
+                        j.setFont(small);
+                        b.add(j);
+
+                        spacer.setFont(new Font("Dialog",0,6));
+                        b.add(spacer);
+
+                        j = new JLabel("Version " + Version.version + " released on " + Version.date + ".");
+                        j.setFont(small);
+                        b.add(j);
+
+                        String javaVersion = System.getProperties().getProperty("java.version");
+                        j = new JLabel("Current Java: " + javaVersion);
+                        j.setFont(small);
+                        b.add(j);
+                        
+                        j = new JLabel("Minimum Java: " + Version.minimumJavaVersion);
+                        j.setFont(small);
+                        b.add(j);
+                                            
+                        aboutFrame.pack();
+                        }
+                        
+                    // if not on screen right now, move to center of screen
+                    if (!aboutFrame.isVisible())
+                        
+                        {
+                        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+                        d.width -= aboutFrame.getWidth();
+                        d.height -= aboutFrame.getHeight();
+                        d.width /= 2;
+                        d.height /= 2;
+                        if (d.width < 0) d.width = 0;
+                        if (d.height < 0) d.height = 0;
+                        aboutFrame.setLocation(d.width,d.height);
+                        }
+                    
+                    // show it!
+                    aboutFrame.setVisible(true);
+                    }
+                });
+            }
+        return aboutMenuItem;
+        }
+    /**
+     * @param f
+     */
+    void loadParameters(File f) 
+        {
+        try 
+            {
+            parameters = new ParameterDatabase(f,clArgs);
+            }
+        catch (FileNotFoundException ex) 
+            {
+            Output.initialError(
+                "A File Not Found Exception was generated upon " +
+                "reading the parameter file \"" + f.getPath() + 
+                "\".\nHere it is:\n" + ex);
+            }
+        catch (IOException ex) 
+            {
+            Output.initialError(
+                "An IO Exception was generated upon reading the " +
+                "parameter file \"" + f.getPath() + 
+                "\".\nHere it is:\n" + ex);
+            }
+        
+        if (parameters == null) 
+            {
+            Output.initialError("No parameter file was loaded");
+            } else 
+            {
+            paramPanel.loadParameters();
+            conPanel.loadParameters();
+            }
+        }
+    
+    void restoreFromCheckpoint(File checkpoint) 
+        {
+        try 
+            {
+            state=Checkpoint.restoreFromCheckpoint(checkpoint.getCanonicalPath());
+            parameters = state.parameters;
+            paramPanel.loadParameters();
+            conPanel.loadParameters();
+            paused = true;
+            setStep(false);
+            spawnPlayThread(true);
+            stopButton.setEnabled(true);
+            }
+        catch(OptionalDataException e) 
+            {
+            Output.initialError(
+                "A ClassNotFoundException was generated upon" +
+                "starting up from a checkpoint." +
+                "\nHere it is:\n" + e); 
+            }
+        catch(ClassNotFoundException e) 
+            {
+            Output.initialError(
+                "A ClassNotFoundException was generated upon" +
+                "starting up from a checkpoint." +
+                "\nHere it is:\n" + e); 
+            }
+        catch (IOException e) 
+            { 
+            Output.initialError(
+                "An IO Exception was generated upon" +
+                "starting up, probably in setting up a log" +
+                "\nHere it is:\n" + e); 
+            }
+        }
+    
+    boolean threadIsToStop;
+    
+    void tellThreadToStop() 
+        {
+        threadIsToStop = true;
+        }
+    
+    void setStep(boolean step) 
+        {
+        _step = step;
+        }
+    
+    boolean isThreadToStop() 
+        {
+        return threadIsToStop;
+        }
+    
+    boolean _step = false;
+    
+    boolean getStep() 
+        {
+        return _step;
+        }
+    
+    void setPaused(boolean paused) 
+        {
+        this.paused = paused;
+        }
+    
+    boolean isPaused() 
+        {
+        return paused;
+        }
+    
+    void spawnPlayThread(final boolean rfc) 
+        {
+        threadIsToStop = false;
+        
+        Runnable run = new Runnable() 
+            {
+            Vector listeners = new Vector();
+            boolean restoreFromCheckpoint = rfc;
+            
+            void addListener(EvolutionStateListener l) 
+                {
+                listeners.add(l);
+                }
+            
+
+            
+            void firePostEvolutionStep() 
+                {
+                EvolutionStateEvent evt = new EvolutionStateEvent(this);
+                Iterator it = listeners.iterator();
+                while (it.hasNext()) 
+                    {
+                    EvolutionStateListener l = (EvolutionStateListener)it.next();
+                    l.postEvolution(evt);
+                    }
+                }
+            
+            void restoreFromCheckpoint() 
+                {
+                state.startFromCheckpoint();
+                statisticsPane.removeAll();
+                setupChartPanes();
+                setupInspectionPanes();
+                }
+            
+            /**
+             * @throws BadParameterException
+             * @throws ParamClassLoadException
+             */
+            void initializeEvolutionState()
+                throws BadParameterException, ParamClassLoadException 
+                {
+                listeners.removeAllElements();
+                Output output = initializeOutput();
+                
+                // 2. set up thread values
+                /*
+                  int breedthreads = parameters.getInt(
+                  new Parameter(Evolve.P_BREEDTHREADS),null,1);
+                  if (breedthreads < 1)
+                  Output.initialError("Number of breeding threads should be an integer >0.",
+                  new Parameter(Evolve.P_BREEDTHREADS));
+                
+                  int evalthreads = parameters.getInt(
+                  new Parameter(Evolve.P_EVALTHREADS),null,1);
+                  if (evalthreads < 1)
+                  Output.initialError("Number of eval threads should be an integer >0.",
+                  new Parameter(Evolve.P_EVALTHREADS));
+                */
+                
+                int breedthreads = Evolve.determineThreads(output, parameters, new Parameter(Evolve.P_BREEDTHREADS));
+                int evalthreads = Evolve.determineThreads(output, parameters, new Parameter(Evolve.P_EVALTHREADS));
+                boolean auto = (Evolve.V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(Evolve.P_BREEDTHREADS),null)) ||
+                    Evolve.V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(Evolve.P_EVALTHREADS),null)));  // at least one thread is automatic.  Seeds may need to be dynamic.
+
+                // 3. create the Mersenne Twister random number generators,
+                // one per thread
+                MersenneTwisterFast[] random = new MersenneTwisterFast[breedthreads > evalthreads ? 
+                    breedthreads : evalthreads];
+                int[] seeds = new int[breedthreads > evalthreads ? 
+                    breedthreads : evalthreads];
+                
+                String seed_message = "Seed: ";
+                for (int x=0;x<random.length;x++)
+                    
+                    {
+                    seeds[x] = conPanel.getSeed(currentJob,x);
+                    seed_message = seed_message + seeds[x] + " ";
+                    }
+                
+                for (int x=0;x<random.length;x++)
+                    
+                    {
+                    for (int y=x+1;y<random.length;y++)
+                        if (seeds[x]==seeds[y])
+                            
+                            {
+                            Output.initialError(Evolve.P_SEED+"."+x+" ("+seeds[x]+") and "+Evolve.P_SEED+"."+y+" ("+seeds[y]+") ought not be the same seed."); 
+                            }
+                    random[x] = Evolve.primeGenerator(new MersenneTwisterFast(seeds[x]));   // we prime the generator to be more sure of randomness.
+                    }
+                
+                state = (EvolutionState)parameters.getInstanceForParameter(
+                    new Parameter(Evolve.P_STATE),null,EvolutionState.class);
+                
+                state.parameters = parameters;
+                state.random = random;
+                state.output = output;
+                String jobFilePrefix = Console.this.conPanel.getJobFilePrefix();
+                if (Console.this.conPanel.getNumJobs() > 1) 
+                    {
+                    if (jobFilePrefix == null || jobFilePrefix.length()<1) 
+                        {
+                        jobFilePrefix = "job";
+                        }
+                    jobFilePrefix = jobFilePrefix+"."+Console.this.currentJob+".";
+                    state.output.setFilePrefix(jobFilePrefix);
+                    }
+                
+                state.evalthreads = evalthreads;
+                state.breedthreads = breedthreads;
+                
+                output.systemMessage("Threads:  breed/" + breedthreads + " eval/" + evalthreads);
+                output.systemMessage(seed_message);
+                
+                state.startFresh();
+
+                if (Console.this.conPanel.getNumJobs() > 0) 
+                    {
+                    state.checkpointPrefix = jobFilePrefix+state.checkpointPrefix;
+                    }
+
+                if (currentJob == 0) 
+                    {
+                    statisticsPane.removeAll();
+                    }
+                
+                setupChartPanes();
+                setupInspectionPanes();
+                }
+            
+            /**
+             * @throws NumberFormatException
+             * @throws BadParameterException
+             */
+            void setupInspectionPanes()
+                throws NumberFormatException, BadParameterException 
+                {
+                inspectionPane.removeAll();
+                // Setup the Evolution State inspection pane
+                JScrollPane stateInspectionPane = new JScrollPane();
+                JTree stateInspectionTree = new JTree(
+                    new ReflectedObject(Console.this.state));
+                stateInspectionPane.setViewportView(stateInspectionTree);
+                inspectionPane.add("Evolution State", stateInspectionPane);
+                
+                // Setup the subpopulation inspection panes
+                Parameter p_subPops = new Parameter("pop.subpops");
+                int numSubPops = parameters.getInt(p_subPops,null);
+                for (int subPop = 0; subPop < numSubPops; ++subPop) 
+                    {
+                    SubpopulationPanel subPopPane = new SubpopulationPanel(Console.this, subPop);
+                    subPopPane.setup(Console.this.state,p_subPops.push(""+subPop));
+                    inspectionPane.add("SubPop "+subPop, subPopPane);
+                    addListener(subPopPane);
+                    }
+                }
+
+            /**
+             * @throws BadParameterException
+             */
+            void setupChartPanes()
+                throws BadParameterException 
+                {
+                // Set up statistics charts (if any)
+                StatisticsChartPane statPane = new StatisticsChartPane();
+                statPane.setup(state, new Parameter("stat"));
+                if (statPane.numCharts > 0)
+                    statisticsPane.addTab("Job "+currentJob, statPane);
+                }
+
+            public void run() 
+                {
+                
+                try 
+                    {
+                    while (currentJob < conPanel.getNumJobs()) 
+                        {
+                        if (!restoreFromCheckpoint)
+                            initializeEvolutionState();
+                        else
+                            restoreFromCheckpoint();
+                        state.output.message("\nJob "+currentJob);
+                        
+                        result = EvolutionState.R_NOTDONE;
+                        while (result == EvolutionState.R_NOTDONE &&
+                            !Thread.currentThread().isInterrupted() &&
+                            !isThreadToStop()) 
+                            {
+                            
+                            try 
+                                {
+                                synchronized (playThread) 
+                                    {
+                                    while (isPaused() && ! getStep()) 
+                                        {
+                                        playThread.wait();
+                                        }
+                                    }
+                                }
+                            catch (InterruptedException e) 
+                                {
+                                // This can happen if the play thread is stopped 
+                                // while paused
+                                }
+                            
+                            if (!Thread.currentThread().isInterrupted() &&
+                                !isThreadToStop()) 
+                                {
+                                result = state.evolve();
+                                firePostEvolutionStep();
+                                Console.this.getStatusField().setText("Job: "+currentJob+" Generation: "+state.generation);
+                                setStep(false);
+                                }
+                            }
+                        
+                        /*
+                         * If the play thread has been interrupted before the experiment
+                         * has completed, consider the experiment a failure.
+                         */
+                        if (result == EvolutionState.R_NOTDONE)
+                            result = EvolutionState.R_FAILURE;
+                        
+                        if (state != null && result != EvolutionState.R_NOTDONE) 
+                            {
+                            state.finish(result);
+                            }
+                        
+                        currentJob++;
+                        }
+                    }
+                catch (Exception e) 
+                    {
+                    System.err.println("Exception when running job:\n\t");
+                    e.printStackTrace();
+                    }
+                
+                conPanel.enableControls();
+                finishAndCleanup();
+                }
+            };
+        
+        playThread = new Thread(run);
+        playThread.start();
+        }
+    
+    /**
+     * @return
+     * @throws BadParameterException
+     */
+    Output initializeOutput()
+        throws BadParameterException 
+        {
+        // 1. create the output
+        //boolean store = parameters.getBoolean(new Parameter(Evolve.P_STORE),null,false);
+        
+        Output output = new Output(true);
+        //output.setFlush(
+        //    parameters.getBoolean(new Parameter(Evolve.P_FLUSH),null,false));
+        
+        
+        // stdout is always log #0.  stderr is always log #1.
+        // stderr accepts announcements, and both are fully verbose 
+        // by default.
+        output.addLog(ec.util.Log.D_STDOUT,false);
+        output.addLog(ec.util.Log.D_STDERR,true);
+        output.systemMessage(Version.message());
+        return output;
+        }
+    
+    /**
+     * Pauses the background play thread.
+     *
+     */
+    void pausePlayThread() 
+        {
+        setPaused(true);
+        }
+    
+    void resumePlayThread() 
+        {
+        synchronized (playThread) 
+            {
+            setPaused(false);
+            playThread.notify();
+            }
+        }
+    
+    /**
+     * 
+     */
+    void killPlayThread() 
+        {
+        tellThreadToStop();
+        
+        try 
+            {
+            if (playThread != null) 
+                {
+                while (playThread.isAlive()) 
+                    {
+                    try 
+                        {
+                        playThread.interrupt();
+                        } 
+                    // Ignore security exceptions resulting from
+                    // attempting to interrupt a thread.
+                    // TODO Explain this better.
+                    catch (SecurityException ex) { }
+                    playThread.join(50);
+                    }
+                
+                playThread = null;
+                }
+            }
+        catch (InterruptedException ex) 
+            {
+            System.out.println("Interrupted while killing the play thread.  Shouldn't happen.");
+            }
+        }
+    
+    /**
+     * 
+     */
+    void finishAndCleanup() 
+        {
+        synchronized(cleanupLock) 
+            {
+            stopButton.setEnabled(false);
+            pauseButton.setEnabled(false);
+            stepButton.setEnabled(true);
+            playButton.setEnabled(true);
+            paused = false;
+            playing = false;
+            _step = false;
+            currentJob = 0;
+            }
+        }
+    
+    int result;
+    JMenuItem loadCheckpointMenuItem = null;
+    JTabbedPane statisticsPane = null;
+    JTabbedPane inspectionPane = null;
+    JPanel statusPane = null;
+    JTextField statusField = null;
+    }  //  @jve:decl-index=0:visual-constraint="21,10"
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/ControlPanel.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/ControlPanel.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/ControlPanel.java	(revision 6152)
@@ -0,0 +1,1075 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Mar 6, 2005 12:48:58 PM
+ * 
+ * By: spaus
+ */
+package ec.display;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FileDialog;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ItemEvent;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.border.TitledBorder;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.DefaultTableModel;
+
+import ec.EvolutionState;
+import ec.Evolve;
+import ec.util.Parameter;
+
+/**
+ * @author spaus
+ */
+public class ControlPanel extends JPanel 
+    {
+
+    final Console console;
+
+    final static String P_JOBFILEPREFIX = "job-file-prefix";
+    
+    JLabel jLabel = null;
+    JTextField numGensField = null;
+    JCheckBox quitOnRunCompleteCheckbox = null;  //  @jve:decl-index=0:
+    JLabel jLabel1 = null;
+    JTextField numJobsField = null;  //  @jve:decl-index=0:
+    JLabel jLabel2 = null;
+    JLabel jLabel3 = null;
+    JTextField evalThreadsField = null;
+    JTextField breedThreadsField = null;
+    JPanel jPanel = null;
+    JRadioButton seedFileRadioButton = null;
+    JTextField seedFileField = null;
+    JButton seedFileButton = null;  //  @jve:decl-index=0:
+    JRadioButton randomSeedsRadioButton = null;
+    JTable seedsTable = null;
+    JScrollPane jScrollPane = null;
+    JLabel jLabel6 = null;
+    JCheckBox checkpointCheckBox = null;
+    JPanel checkpointPanel = null;
+    JLabel jLabel7 = null;
+    JTextField checkpointModuloField = null;
+    JLabel jLabel8 = null;
+    JTextField prefixField = null;
+    JLabel jLabel10 = null;
+
+    ButtonGroup seedButtonGroup;
+    JButton generateSeedsButton = null;
+    JRadioButton sequentialSeedsRadioButton = null;
+    JLabel jLabel5 = null;
+    JTextField jobFilePrefixField = null;
+    /**
+     * This is the default constructor
+     */
+    public ControlPanel(Console console) 
+        {
+        super();
+        this.console = console;
+        initialize();
+        }
+    
+    public void disableControls() 
+        {
+        breedThreadsField.setEnabled(false);
+        checkpointCheckBox.setEnabled(false);
+        checkpointModuloField.setEnabled(false);
+        evalThreadsField.setEnabled(false);
+        generateSeedsButton.setEnabled(false);
+        jobFilePrefixField.setEnabled(false);
+        numGensField.setEnabled(false);
+        numJobsField.setEnabled(false);
+        prefixField.setEnabled(false);
+        quitOnRunCompleteCheckbox.setEnabled(false);
+        sequentialSeedsRadioButton.setEnabled(false);
+        randomSeedsRadioButton.setEnabled(false);
+        seedFileRadioButton.setEnabled(false);
+        seedFileButton.setEnabled(false);
+        seedsTable.setEnabled(false);
+        }
+    
+    public void enableControls() 
+        {
+        breedThreadsField.setEnabled(true);
+        checkpointCheckBox.setEnabled(true);
+        if (checkpointCheckBox.isSelected()) 
+            {
+            checkpointModuloField.setEnabled(true);
+            prefixField.setEnabled(true);
+            }
+        evalThreadsField.setEnabled(true);
+        jobFilePrefixField.setEnabled(true);
+        numGensField.setEnabled(true);
+        numJobsField.setEnabled(true);
+        quitOnRunCompleteCheckbox.setEnabled(true);
+        sequentialSeedsRadioButton.setEnabled(true);
+        randomSeedsRadioButton.setEnabled(true);
+        if (randomSeedsRadioButton.isSelected()) 
+            {
+            generateSeedsButton.setEnabled(true);
+            }
+        seedFileRadioButton.setEnabled(true);
+        if (seedFileRadioButton.isSelected()) 
+            {
+            seedFileButton.setEnabled(true);
+            }
+        seedsTable.setEnabled(true);
+        }
+
+    /**
+     * This method initializes this
+     * 
+     * @return void
+     */
+    void initialize() 
+        {
+        jLabel5 = new JLabel();
+        GridBagConstraints gridBagConstraints28 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints37 = new GridBagConstraints();
+        jLabel10 = new JLabel();
+        GridBagConstraints gridBagConstraints45 = new GridBagConstraints();
+        jLabel6 = new JLabel();
+        jLabel3 = new JLabel();
+        jLabel2 = new JLabel();
+        jLabel1 = new JLabel();
+        jLabel = new JLabel();
+        GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints7 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints8 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints9 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints10 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints25 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints26 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints35 = new GridBagConstraints();
+        GridBagConstraints gridBagConstraints36 = new GridBagConstraints();
+        this.setLayout(new GridBagLayout());
+        this.setSize(975, 300);
+        this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        gridBagConstraints1.gridx = 1;
+        gridBagConstraints1.gridy = 2;
+        gridBagConstraints1.gridheight = 1;
+        gridBagConstraints1.gridwidth = 1;
+        gridBagConstraints1.anchor = java.awt.GridBagConstraints.WEST;
+        jLabel.setText("# Generations:");
+        gridBagConstraints2.gridx = 2;
+        gridBagConstraints2.gridy = 2;
+        gridBagConstraints2.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints2.weightx = 0.0D;
+        gridBagConstraints2.insets = new java.awt.Insets(0,5,0,0);
+        gridBagConstraints2.ipadx = 30;
+        gridBagConstraints4.gridx = 1;
+        gridBagConstraints4.gridy = 6;
+        gridBagConstraints4.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints4.gridwidth = 2;
+        gridBagConstraints5.gridx = 1;
+        gridBagConstraints5.gridy = 0;
+        gridBagConstraints5.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        jLabel1.setText("# Jobs:");
+        gridBagConstraints6.gridx = 2;
+        gridBagConstraints6.gridy = 0;
+        gridBagConstraints6.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints6.insets = new java.awt.Insets(0,5,0,0);
+        gridBagConstraints6.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        gridBagConstraints6.gridwidth = 1;
+        gridBagConstraints7.gridx = 1;
+        gridBagConstraints7.gridy = 3;
+        gridBagConstraints7.anchor = java.awt.GridBagConstraints.WEST;
+        jLabel2.setText("# Evaluation Threads:");
+        gridBagConstraints8.gridx = 1;
+        gridBagConstraints8.gridy = 4;
+        gridBagConstraints8.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints8.gridwidth = 1;
+        jLabel3.setText("# Breeder Threads:");
+        gridBagConstraints9.gridx = 2;
+        gridBagConstraints9.gridy = 3;
+        gridBagConstraints9.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints9.insets = new java.awt.Insets(0,5,0,0);
+        gridBagConstraints10.gridx = 2;
+        gridBagConstraints10.gridy = 4;
+        gridBagConstraints10.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints10.insets = new java.awt.Insets(0,5,0,0);
+        gridBagConstraints11.gridx = 11;
+        gridBagConstraints11.gridy = 0;
+        gridBagConstraints11.gridwidth = 6;
+        gridBagConstraints11.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints11.gridheight = 13;
+        gridBagConstraints11.weightx = 1.0D;
+        gridBagConstraints25.gridx = 1;
+        gridBagConstraints25.gridy = 5;
+        gridBagConstraints25.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints25.insets = new java.awt.Insets(0,0,0,0);
+        jLabel6.setText("Verbosity:");
+        gridBagConstraints26.gridx = 2;
+        gridBagConstraints26.gridy = 5;
+        gridBagConstraints26.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints26.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints26.weightx = 0.0D;
+        gridBagConstraints26.insets = new java.awt.Insets(0,5,0,0);
+        gridBagConstraints26.ipadx = 30;
+        gridBagConstraints35.gridx = 1;
+        gridBagConstraints35.gridy = 7;
+        gridBagConstraints35.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints35.gridwidth = 2;
+        gridBagConstraints35.gridheight = 1;
+        gridBagConstraints36.gridx = 1;
+        gridBagConstraints36.gridy = 8;
+        gridBagConstraints36.gridheight = 1;
+        gridBagConstraints36.gridwidth = 3;
+        gridBagConstraints36.anchor = java.awt.GridBagConstraints.NORTH;
+        gridBagConstraints36.ipadx = 107;
+        gridBagConstraints45.gridx = 5;
+        gridBagConstraints45.gridy = 8;
+        gridBagConstraints45.weighty = 1.0D;
+        jLabel10.setText("");
+        gridBagConstraints28.gridx = 1;
+        gridBagConstraints28.gridy = 1;
+        gridBagConstraints28.anchor = java.awt.GridBagConstraints.WEST;
+        jLabel5.setText("Job file prefix:");
+        gridBagConstraints37.gridx = 2;
+        gridBagConstraints37.gridy = 1;
+        gridBagConstraints37.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints37.insets = new java.awt.Insets(0,5,0,0);
+        gridBagConstraints37.gridwidth = 3;
+        this.add(jLabel, gridBagConstraints1);
+        this.add(getNumGensField(), gridBagConstraints2);
+        this.add(getQuitOnRunCompleteCheckbox(), gridBagConstraints4);
+        this.add(jLabel1, gridBagConstraints5);
+        this.add(getNumJobsField(), gridBagConstraints6);
+        this.add(jLabel2, gridBagConstraints7);
+        this.add(jLabel3, gridBagConstraints8);
+        this.add(getEvalThreadsField(), gridBagConstraints9);
+        this.add(getBreedThreadsField(), gridBagConstraints10);
+        this.add(getJPanel(), gridBagConstraints11);
+        this.add(jLabel6, gridBagConstraints25);
+        //this.add(getVerbosityField(), gridBagConstraints26);
+        this.add(getCheckpointCheckBox(), gridBagConstraints35);
+        this.add(getCheckpointPanel(), gridBagConstraints36);
+        this.add(jLabel10, gridBagConstraints45);
+        this.add(jLabel5, gridBagConstraints28);
+        this.add(getJobFilePrefixField(), gridBagConstraints37);
+        this.add(Box.createRigidArea(new Dimension(5,0)));
+        }
+    /**
+     * This method initializes jTextField   
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getNumGensField() 
+        {
+        if (numGensField == null) 
+            {
+            numGensField = new JTextField();
+            numGensField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(KeyEvent e) 
+                    {
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        console.parameters.set(new Parameter(EvolutionState.P_GENERATIONS), ((JTextField)e.getSource()).getText());
+                        } 
+                    else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 
+                        {
+                        ((JTextField)e.getSource()).setText(console.parameters.getString(new Parameter(EvolutionState.P_GENERATIONS),null));
+                        }
+                    }
+                });
+            }
+        return numGensField;
+        }
+    /**
+     * This method initializes jCheckBox    
+     *      
+     * @return javax.swing.JCheckBox        
+     */    
+    JCheckBox getQuitOnRunCompleteCheckbox() 
+        {
+        if (quitOnRunCompleteCheckbox == null) 
+            {
+            quitOnRunCompleteCheckbox = new JCheckBox();
+            quitOnRunCompleteCheckbox.setText("Quit on Run Complete");
+            quitOnRunCompleteCheckbox.addItemListener(new java.awt.event.ItemListener() 
+                { 
+                public void itemStateChanged(java.awt.event.ItemEvent e) 
+                    {    
+                    console.parameters.set(new Parameter(EvolutionState.P_QUITONRUNCOMPLETE),
+                        "" + ((JCheckBox)e.getSource()).isSelected());
+                    }
+                });
+            }
+        return quitOnRunCompleteCheckbox;
+        }
+    /**
+     * This method initializes jTextField1  
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getNumJobsField() 
+        {
+        if (numJobsField == null) 
+            {
+            numJobsField = new JTextField();
+            numJobsField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(java.awt.event.KeyEvent e) 
+                    {
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        resizeSeedTable();
+                        }
+                    }
+                });
+            }
+        return numJobsField;
+        }
+    
+    public int getNumJobs() 
+        {
+        return Integer.valueOf(getNumJobsField().getText()).intValue();
+        }
+
+    public int getThreadCount(String text)
+        {
+        if (text.toLowerCase().trim().equals("auto"))
+            return Runtime.getRuntime().availableProcessors();
+        else return Integer.valueOf(text).intValue();
+        }
+
+
+    /**
+     * @throws NumberFormatException
+     */
+    void resizeSeedTable()
+        throws NumberFormatException 
+        {
+        int numJobs = Integer.valueOf(numJobsField.getText()).intValue();
+        int breedThreads = getThreadCount(breedThreadsField.getText());
+        int evalThreads = getThreadCount(evalThreadsField.getText());
+        
+        int numThreads = Math.max(breedThreads, evalThreads);
+        
+        DefaultTableModel model =(DefaultTableModel)seedsTable.getModel(); 
+        model.setColumnCount(numThreads);
+        String[] columnHeaders = new String[numThreads];
+        for (int i = 0; i < numThreads; ++i) 
+            {
+            columnHeaders[i] = "Thread "+i;
+            }
+
+        model.setColumnIdentifiers(columnHeaders);
+        model.setRowCount(numJobs);
+
+        if (seedFileRadioButton.isSelected()) 
+            {
+            File f = new File(seedFileField.getText());
+            try 
+                {
+                loadSeeds(f);
+                } 
+            catch (IOException ex) 
+                {
+                System.err.println(ex.getMessage());
+                }
+            } 
+        else if (randomSeedsRadioButton.isSelected()) 
+            {
+            generateRandomSeeds();
+            } 
+        else if (sequentialSeedsRadioButton.isSelected()) 
+            {
+            int seed;
+            int i = 0;
+            for (int thread = 0; thread < numThreads; ++thread) 
+                {
+                try 
+                    {
+                    seed = console.parameters.getInt(new Parameter("seed."+thread),null);
+                    }
+                catch (NumberFormatException ex) 
+                    {
+                    seed = getSeed(0,thread-1)+1;
+                    }
+                for (int job = 0; job < numJobs; ++job)
+                    setSeed(""+(seed+(i++)),job,thread);
+                }
+            }
+        else
+            {
+            for (int job = 0; job < numJobs; ++job) 
+                {
+                for (int thread = 0; thread < numThreads; ++thread) 
+                    {
+                    setSeed(console.parameters.getString(new Parameter("seed."+thread),null),job,thread);
+                    }
+                }
+            }
+        }
+
+    /**
+     * @throws NumberFormatException
+     */
+    void generateRandomSeeds()
+        throws NumberFormatException 
+        {
+        int numJobs = Integer.valueOf(numJobsField.getText()).intValue();
+        int breedThreads = getThreadCount(breedThreadsField.getText());
+        int evalThreads = getThreadCount(evalThreadsField.getText());
+        int numThreads = Math.max(breedThreads, evalThreads);
+        
+        int seed = (int)(System.currentTimeMillis());
+        for (int job = 0; job < numJobs; ++job) 
+            {
+            for (int thread = 0; thread < numThreads; ++thread) 
+                {
+                seed = seed+(job*Math.min(breedThreads, evalThreads))+(thread*Math.max(breedThreads, evalThreads));
+                setSeed(""+seed,job,thread);
+                }
+            }
+        }
+                
+    public int getSeed(int experimentNum, int threadNum) 
+        {
+        try { return Integer.valueOf((String)seedsTable.getValueAt(experimentNum, threadNum)).intValue(); }
+        catch (RuntimeException e)
+            {
+            javax.swing.JOptionPane.showMessageDialog(null, "Value of seed for experiment " + experimentNum + 
+                " and thread " + threadNum + " not a fixed number: probably 'time'.  Rebuilding random number seeds.", "Adjusting Seeds", 
+                javax.swing.JOptionPane.INFORMATION_MESSAGE);
+            generateRandomSeeds();
+            return Integer.valueOf((String)seedsTable.getValueAt(experimentNum, threadNum)).intValue();
+            }
+        }
+    
+    public void setSeed(String seed, int experimentNum, int threadNum) 
+        {
+        seedsTable.setValueAt(seed, experimentNum, threadNum);
+        }
+    /**
+     * This method initializes jTextField2  
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getEvalThreadsField() 
+        {
+        if (evalThreadsField == null) 
+            {
+            evalThreadsField = new JTextField();
+            evalThreadsField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(java.awt.event.KeyEvent e) 
+                    {
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        console.parameters.set(new Parameter(Evolve.P_EVALTHREADS), ((JTextField)e.getSource()).getText());
+                        resizeSeedTable();
+                        } 
+                    else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 
+                        {
+                        ((JTextField)e.getSource()).setText(console.parameters.getString(new Parameter(Evolve.P_EVALTHREADS),null));
+                        }
+                    }
+                });
+            }
+        return evalThreadsField;
+        }
+    /**
+     * This method initializes jTextField3  
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getBreedThreadsField() 
+        {
+        if (breedThreadsField == null) 
+            {
+            breedThreadsField = new JTextField();
+            breedThreadsField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(java.awt.event.KeyEvent e) 
+                    {    
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        console.parameters.set(new Parameter(Evolve.P_BREEDTHREADS), ((JTextField)e.getSource()).getText());
+                        resizeSeedTable();
+                        } 
+                    else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 
+                        {
+                        ((JTextField)e.getSource()).setText(console.parameters.getString(new Parameter(Evolve.P_BREEDTHREADS),null));
+                        }
+                    }
+                });
+            }
+        return breedThreadsField;
+        }
+    /**
+     * This method initializes jPanel       
+     *      
+     * @return javax.swing.JPanel   
+     */    
+    JPanel getJPanel() 
+        {
+        if (jPanel == null) 
+            {
+            GridBagConstraints gridBagConstraints15 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints81 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints14 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints13 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints12 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints19 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints21 = new GridBagConstraints();
+            TitledBorder titledBorder28 = javax.swing.BorderFactory.createTitledBorder(null, "Random Seed(s)", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, null, null);
+            jPanel = new JPanel();
+            jPanel.setLayout(new GridBagLayout());
+            gridBagConstraints12.gridx = 0;
+            gridBagConstraints12.gridy = 1;
+            gridBagConstraints12.fill = java.awt.GridBagConstraints.HORIZONTAL;
+            gridBagConstraints12.anchor = java.awt.GridBagConstraints.EAST;
+            gridBagConstraints12.gridwidth = 5;
+            gridBagConstraints12.insets = new java.awt.Insets(0,20,0,0);
+            gridBagConstraints12.weightx = 1.0D;
+            gridBagConstraints13.gridx = 5;
+            gridBagConstraints13.gridy = 1;
+            gridBagConstraints13.anchor = java.awt.GridBagConstraints.WEST;
+            gridBagConstraints13.insets = new java.awt.Insets(0,5,0,0);
+            gridBagConstraints14.gridx = 0;
+            gridBagConstraints14.gridy = 3;
+            gridBagConstraints14.gridwidth = 1;
+            gridBagConstraints14.anchor = java.awt.GridBagConstraints.WEST;
+            gridBagConstraints19.gridwidth = 6;
+            gridBagConstraints19.anchor = java.awt.GridBagConstraints.WEST;
+            gridBagConstraints21.gridx = 0;
+            gridBagConstraints21.gridy = 7;
+            gridBagConstraints21.fill = java.awt.GridBagConstraints.BOTH;
+            gridBagConstraints21.gridwidth = 6;
+            gridBagConstraints21.gridheight = 1;
+            gridBagConstraints21.weighty = 1.0D;
+            gridBagConstraints21.weightx = 1.0D;
+            jPanel.setBorder(titledBorder28);
+            titledBorder28.setBorder(javax.swing.BorderFactory.createEtchedBorder(javax.swing.border.EtchedBorder.LOWERED));
+            gridBagConstraints81.gridx = 1;
+            gridBagConstraints81.gridy = 3;
+            gridBagConstraints15.gridx = 0;
+            gridBagConstraints15.gridy = 2;
+            gridBagConstraints15.anchor = java.awt.GridBagConstraints.WEST;
+            jPanel.add(getSeedFileRadioButton(), gridBagConstraints19);
+            jPanel.add(getSeedFileField(), gridBagConstraints12);
+            jPanel.add(getSeedFileButton(), gridBagConstraints13);
+            jPanel.add(getRandomSeedsRadioButton(), gridBagConstraints14);
+            jPanel.add(getJScrollPane(), gridBagConstraints21);
+            seedButtonGroup = new ButtonGroup();
+            seedButtonGroup.add(getRandomSeedsRadioButton());
+            seedButtonGroup.add(getSeedFileRadioButton());
+            seedButtonGroup.add(getSequentialSeedsRadioButton());
+            jPanel.add(getGenerateSeedsButton(), gridBagConstraints81);
+            jPanel.add(getSequentialSeedsRadioButton(), gridBagConstraints15);
+            }
+        return jPanel;
+        }
+    /**
+     * This method initializes jRadioButton 
+     *      
+     * @return javax.swing.JRadioButton     
+     */    
+    JRadioButton getSeedFileRadioButton() 
+        {
+        if (seedFileRadioButton == null) 
+            {
+            seedFileRadioButton = new JRadioButton();
+            seedFileRadioButton.setText("Seeds from file:");
+            final ControlPanel cp = this;
+            seedFileRadioButton.addItemListener(new java.awt.event.ItemListener() 
+                { 
+                public void itemStateChanged(java.awt.event.ItemEvent e) 
+                    {
+                    if (e.getStateChange() == ItemEvent.SELECTED) 
+                        {
+                        seedFileField.setEnabled(true);
+                        seedFileButton.setEnabled(true);
+
+                        String seedFileName = seedFileField.getText();
+                        File seedFile = null;
+                        if ( seedFileName == null ||
+                            seedFileName.length() == 0) 
+                            {
+                            FileDialog fileDialog = new FileDialog(ControlPanel.this.console,"Load...",FileDialog.LOAD);
+                            fileDialog.setDirectory(System.getProperty("user.dir"));
+                            fileDialog.setFile("*.seed");
+                            fileDialog.setVisible(true);
+                            String fileName = fileDialog.getFile();
+                            if ( fileName != null )
+                                
+                                {
+                                seedFile = new File(fileDialog.getDirectory(),fileName);
+                                }
+                            }
+                        else
+                            {
+                            seedFile = new File(seedFileName);
+                            }
+
+                        if (seedFile != null) 
+                            {
+                            try 
+                                {
+                                cp.loadSeeds(seedFile);
+                                } 
+                            catch (IOException ex) 
+                                {
+                                System.err.println(ex.getMessage());
+                                }
+                            }
+                        }
+                    else
+                        {
+                        seedFileField.setEnabled(false);
+                        seedFileButton.setEnabled(false);
+                        }
+                    }
+                });
+            }
+        return seedFileRadioButton;
+        }
+    /**
+     * This method initializes jTextField4  
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getSeedFileField() 
+        {
+        if (seedFileField == null) 
+            {
+            seedFileField = new JTextField();
+            seedFileField.setEnabled(false);
+            seedFileField.setEditable(false);
+            }
+        return seedFileField;
+        }
+    /**
+     * This method initializes jButton      
+     *      
+     * @return javax.swing.JButton  
+     */    
+    JButton getSeedFileButton() 
+        {
+        if (seedFileButton == null) 
+            {
+            seedFileButton = new JButton();
+            seedFileButton.setText("...");
+            seedFileButton.setEnabled(false);
+            final ControlPanel cp = this;
+            seedFileButton.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {
+                    File seedFile = null;
+                    FileDialog fileDialog = new FileDialog(ControlPanel.this.console,"Load...",FileDialog.LOAD);
+                    fileDialog.setDirectory(System.getProperty("user.dir"));
+                    fileDialog.setFile("*.seed");
+                    fileDialog.setVisible(true);
+                    String fileName = fileDialog.getFile();
+                    if ( fileName != null )
+                        
+                        {
+                        seedFile = new File(fileDialog.getDirectory(),fileName);
+                        }
+
+                    if (seedFile != null) 
+                        {
+                        try 
+                            {
+                            cp.loadSeeds(seedFile);
+                            } 
+                        catch (IOException ex) 
+                            {
+                            System.err.println(ex.getMessage());
+                            }
+                        }
+                    }
+                });
+            }
+        return seedFileButton;
+        }
+    /**
+     * This method initializes jRadioButton1        
+     *      
+     * @return javax.swing.JRadioButton     
+     */    
+    JRadioButton getRandomSeedsRadioButton() 
+        {
+        if (randomSeedsRadioButton == null) 
+            {
+            randomSeedsRadioButton = new JRadioButton();
+            randomSeedsRadioButton.setText("Random Seeds");
+            randomSeedsRadioButton.addItemListener(new java.awt.event.ItemListener() 
+                { 
+                public void itemStateChanged(java.awt.event.ItemEvent e) 
+                    {    
+                    if (e.getStateChange() == ItemEvent.SELECTED) 
+                        {
+                        generateSeedsButton.setEnabled(true);
+                        }
+                    else
+                        {
+                        generateSeedsButton.setEnabled(false);
+                        }
+                    }
+                });
+            }
+        return randomSeedsRadioButton;
+        }
+    /**
+     * This method initializes jTable       
+     *      
+     * @return javax.swing.JTable   
+     */    
+    JTable getSeedsTable() 
+        {
+        if (seedsTable == null) 
+            {
+            seedsTable = new JTable();
+            seedsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
+            }
+        return seedsTable;
+        }
+    /**
+     * This method initializes jScrollPane  
+     *      
+     * @return javax.swing.JScrollPane      
+     */    
+    JScrollPane getJScrollPane() 
+        {
+        if (jScrollPane == null) 
+            {
+            jScrollPane = new JScrollPane();
+            jScrollPane.setViewportView(getSeedsTable());
+            jScrollPane.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+            }
+        return jScrollPane;
+        }
+        
+    /**
+     * @param panel TODO
+     * @param enabled TODO
+     * 
+     */
+    void setEnabled(JPanel panel, boolean enabled) 
+        {
+        Component[] components = panel.getComponents();
+        for (int i = 0; i < components.length; ++i) 
+            {
+            components[i].setEnabled(enabled);
+            }
+        }
+    /**
+     * This method initializes jCheckBox10  
+     *      
+     * @return javax.swing.JCheckBox        
+     */    
+    JCheckBox getCheckpointCheckBox() 
+        {
+        if (checkpointCheckBox == null) 
+            {
+            checkpointCheckBox = new JCheckBox();
+            checkpointCheckBox.setText("Checkpoint");
+            checkpointCheckBox.addItemListener(new java.awt.event.ItemListener() 
+                { 
+                public void itemStateChanged(java.awt.event.ItemEvent e) 
+                    {    
+                    if (e.getStateChange() == ItemEvent.SELECTED) 
+                        {
+                        setEnabled(checkpointPanel, true);
+                        }
+                    else
+                        {
+                        setEnabled(checkpointPanel, false);
+                        }
+                    
+                    console.parameters.set(new Parameter(EvolutionState.P_CHECKPOINT),"" + ((JCheckBox)e.getSource()).isSelected());
+                    }
+                });
+            }
+        return checkpointCheckBox;
+        }
+    /**
+     * This method initializes jPanel2      
+     *      
+     * @return javax.swing.JPanel   
+     */    
+    JPanel getCheckpointPanel() 
+        {
+        if (checkpointPanel == null) 
+            {
+            GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
+            jLabel8 = new JLabel();
+            jLabel7 = new JLabel();
+            GridBagConstraints gridBagConstraints39 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints40 = new GridBagConstraints();
+            GridBagConstraints gridBagConstraints41 = new GridBagConstraints();
+            checkpointPanel = new JPanel();
+            checkpointPanel.setLayout(new GridBagLayout());
+            jLabel7.setText("Frequency:");
+            jLabel7.setEnabled(false);
+            gridBagConstraints39.fill = java.awt.GridBagConstraints.HORIZONTAL;
+            gridBagConstraints39.gridx = 1;
+            gridBagConstraints39.gridy = 0;
+            gridBagConstraints39.ipady = 0;
+            gridBagConstraints39.ipadx = 0;
+            gridBagConstraints39.weightx = 0.0D;
+            gridBagConstraints39.insets = new java.awt.Insets(0,5,0,0);
+            checkpointPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(javax.swing.border.EtchedBorder.LOWERED), "Checkpointing", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, null, null));
+            jLabel8.setText("File Prefix:");
+            jLabel8.setEnabled(false);
+            gridBagConstraints40.gridx = 0;
+            gridBagConstraints40.gridy = 1;
+            gridBagConstraints40.anchor = java.awt.GridBagConstraints.WEST;
+            gridBagConstraints41.gridx = 1;
+            gridBagConstraints41.gridy = 1;
+            gridBagConstraints41.fill = java.awt.GridBagConstraints.HORIZONTAL;
+            gridBagConstraints41.insets = new java.awt.Insets(0,5,0,0);
+            gridBagConstraints41.gridwidth = 2;
+            gridBagConstraints41.weightx = 0.5D;
+            gridBagConstraints3.anchor = java.awt.GridBagConstraints.WEST;
+            checkpointPanel.add(jLabel7, gridBagConstraints3);
+            checkpointPanel.add(getCheckpointModuloField(), gridBagConstraints39);
+            checkpointPanel.add(jLabel8, gridBagConstraints40);
+            checkpointPanel.add(getPrefixField(), gridBagConstraints41);
+            }
+        return checkpointPanel;
+        }
+    /**
+     * This method initializes jTextField8  
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getCheckpointModuloField() 
+        {
+        if (checkpointModuloField == null) 
+            {
+            checkpointModuloField = new JTextField();
+            checkpointModuloField.setPreferredSize(new java.awt.Dimension(35,20));
+            checkpointModuloField.setEnabled(false);
+            checkpointModuloField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(java.awt.event.KeyEvent e) 
+                    {    
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        console.parameters.set(new Parameter(EvolutionState.P_CHECKPOINTMODULO), ((JTextField)e.getSource()).getText());
+                        } 
+                    else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 
+                        {
+                        ((JTextField)e.getSource()).setText(console.parameters.getString(new Parameter(EvolutionState.P_CHECKPOINTMODULO),null));
+                        }
+                    }
+                });
+            }
+        return checkpointModuloField;
+        }
+    /**
+     * This method initializes jTextField9  
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getPrefixField() 
+        {
+        if (prefixField == null) 
+            {
+            prefixField = new JTextField();
+            prefixField.setEnabled(false);
+            prefixField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(java.awt.event.KeyEvent e) 
+                    {    
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        console.parameters.set(new Parameter(EvolutionState.P_CHECKPOINTPREFIX), ((JTextField)e.getSource()).getText());
+                        } 
+                    else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 
+                        {
+                        ((JTextField)e.getSource()).setText(console.parameters.getString(new Parameter(EvolutionState.P_CHECKPOINTPREFIX),null));
+                        }
+                    }
+                });
+            }
+        return prefixField;
+        }
+    public void loadParameters() 
+        {
+        numGensField.setText(console.parameters.getStringWithDefault(
+                new Parameter(EvolutionState.P_GENERATIONS),null,"1"));
+        quitOnRunCompleteCheckbox.setSelected(console.parameters.getBoolean(new Parameter(EvolutionState.P_QUITONRUNCOMPLETE),null,true));
+        evalThreadsField.setText(console.parameters.getStringWithDefault(new Parameter(Evolve.P_EVALTHREADS),null,"1"));
+        breedThreadsField.setText(console.parameters.getStringWithDefault(new Parameter(Evolve.P_BREEDTHREADS),null,"1"));
+        checkpointCheckBox.setSelected(console.parameters.getBoolean(new Parameter(EvolutionState.P_CHECKPOINT),null,false));
+        checkpointModuloField.setText(console.parameters.getStringWithDefault(new Parameter(EvolutionState.P_CHECKPOINTMODULO),null,"10"));
+        prefixField.setText(console.parameters.getStringWithDefault(new Parameter(EvolutionState.P_CHECKPOINTPREFIX),null,"gc"));
+        numJobsField.setText("1");
+        jobFilePrefixField.setText(console.parameters.getStringWithDefault(new Parameter(P_JOBFILEPREFIX),null,""));
+        
+        resizeSeedTable();
+        }
+    
+    void loadSeeds(File f)
+        throws IOException 
+        {
+        LineNumberReader in = new LineNumberReader(new InputStreamReader(new FileInputStream(f)));
+        
+        seedFileField.setText(f.getAbsolutePath());
+        // whether a seed is used for a particular thread or job depends
+        // upon how many of each there are.  Just read seeds, one per line, until
+        // numJobs * numThreads seeds are read.  If there are not enough seeds,
+        // print a warning and generate the remaining necessary.
+        int numJobs = Integer.valueOf(numJobsField.getText()).intValue();
+        int evalThreads = getThreadCount(console.parameters.getString(new Parameter(Evolve.P_EVALTHREADS),null));
+        int breedThreads = getThreadCount(console.parameters.getString(new Parameter(Evolve.P_BREEDTHREADS),null));
+        int numThreads = Math.max(evalThreads, breedThreads);
+        
+        // Read seeds for threads first
+        // TODO Make this more robust (i.e. ensure we're reading integers).
+        int job = 0;
+        int thread = 0;
+        String lastSeed = null;
+        for (; job < numJobs; ++job) 
+            {
+            String seed = null;
+            for (; thread < numThreads; ++thread) 
+                {
+                seed = in.readLine();
+                if (seed != null) 
+                    {
+                    setSeed(seed, job, thread);
+                    lastSeed = seed;
+                    }
+                else                   break;
+                }
+            if (seed == null)
+                break;
+            thread = 0;
+            }
+
+        // Finish filling out the table with sequential numbers starting from
+        // the last good seed.
+        // TODO Determine if this is reasonable.  Should we instead generate
+        // random seeds?  Alternatively, should we indicate this as an error
+        // to the user and abort?
+        if ((job)*(thread) != (numJobs)*(numThreads)) 
+            {
+            int seedNum = Integer.valueOf(lastSeed).intValue();
+            for (;job < numJobs; ++job) 
+                {
+                for (;thread < numThreads; ++thread) 
+                    {
+                    String seed = ""+(++seedNum);
+                    setSeed(seed,job,thread);
+                    }
+                thread = 0;
+                }
+            }
+        }
+    /**
+     * This method initializes jButton      
+     *      
+     * @return javax.swing.JButton  
+     */    
+    JButton getGenerateSeedsButton() 
+        {
+        if (generateSeedsButton == null) 
+            {
+            generateSeedsButton = new JButton();
+            generateSeedsButton.setText("Generate");
+            generateSeedsButton.setEnabled(false);
+            generateSeedsButton.addActionListener(new java.awt.event.ActionListener() 
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e) 
+                    {    
+                    generateRandomSeeds();
+                    }
+                });
+            }
+        return generateSeedsButton;
+        }
+    /**
+     * This method initializes jRadioButton 
+     *      
+     * @return javax.swing.JRadioButton     
+     */    
+    JRadioButton getSequentialSeedsRadioButton() 
+        {
+        if (sequentialSeedsRadioButton == null) 
+            {
+            sequentialSeedsRadioButton = new JRadioButton();
+            sequentialSeedsRadioButton.setText("Sequential");
+            sequentialSeedsRadioButton.addItemListener(new java.awt.event.ItemListener() 
+                { 
+                public void itemStateChanged(java.awt.event.ItemEvent e) 
+                    {    
+                    if (e.getStateChange() == ItemEvent.SELECTED) 
+                        {
+                        resizeSeedTable();
+                        }
+                    }
+                });
+            }
+        return sequentialSeedsRadioButton;
+        }
+    /**
+     * This method initializes jTextField   
+     *      
+     * @return javax.swing.JTextField       
+     */    
+    JTextField getJobFilePrefixField() 
+        {
+        if (jobFilePrefixField == null) 
+            {
+            jobFilePrefixField = new JTextField();
+            jobFilePrefixField.addKeyListener(new java.awt.event.KeyAdapter() 
+                { 
+                public void keyPressed(java.awt.event.KeyEvent e) 
+                    {    
+                    if (e.getKeyCode() == KeyEvent.VK_ENTER) 
+                        {
+                        console.parameters.set(new Parameter(P_JOBFILEPREFIX), ((JTextField)e.getSource()).getText());
+                        } 
+                    else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) 
+                        {
+                        ((JTextField)e.getSource()).setText(console.parameters.getStringWithDefault(new Parameter(P_JOBFILEPREFIX),null,""));
+                        }
+                    }
+                });
+            }
+        return jobFilePrefixField;
+        }
+    
+    public String getJobFilePrefix() 
+        {
+        return jobFilePrefixField.getText();
+        }
+    }  //  @jve:decl-index=0:visual-constraint="66,13"
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/EvolutionStateEvent.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/EvolutionStateEvent.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/EvolutionStateEvent.java	(revision 6152)
@@ -0,0 +1,31 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 14, 2005 9:11:13 PM
+ * 
+ * By: spaus
+ */
+package ec.display;
+
+import java.util.EventObject;
+
+/**
+ * @author spaus
+ */
+public class EvolutionStateEvent
+    extends EventObject 
+    {
+
+    /**
+     * @param source
+     */
+    public EvolutionStateEvent(Object source) 
+        {
+        super(source);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/EvolutionStateListener.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/EvolutionStateListener.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/EvolutionStateListener.java	(revision 6152)
@@ -0,0 +1,24 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 14, 2005 9:08:47 PM
+ * 
+ * By: spaus
+ */
+package ec.display;
+
+/**
+ * @author spaus
+ */
+public interface EvolutionStateListener 
+    {
+    /**
+     * @param evt
+     */
+    public void postEvolution(EvolutionStateEvent evt);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/ParameterValue.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/ParameterValue.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/ParameterValue.java	(revision 6152)
@@ -0,0 +1,37 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 19, 2005 10:30:19 PM
+ * 
+ * By: spaus
+ */
+package ec.display;
+
+/**
+ * @author spaus
+ */
+public class ParameterValue 
+    {
+    
+    final String value;
+    
+    public ParameterValue(String value) 
+        {
+        this.value = value;
+        }
+    
+    public String getValue() 
+        {
+        return value;
+        }
+    
+    public String toString() 
+        {
+        return "*"+value+"*";
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/ParametersPanel.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/ParametersPanel.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/ParametersPanel.java	(revision 6152)
@@ -0,0 +1,259 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.display;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.tree.*;
+import ec.util.*;
+
+/*
+ * Created on Apr 4, 2005 8:54:38 PM
+ * 
+ * By: spaus
+ */
+
+/**
+ * @author spaus
+ */
+public class ParametersPanel
+    extends JPanel
+    {
+    
+    private final Console console;
+    
+    private JScrollPane parameterTreeScrollPane = null;
+    private JTree parameterTree = null;
+    
+    private JScrollPane parameterTableScrollPane = null;
+    private JTable parameterTable = null;
+    private JSplitPane jSplitPane = null;
+    
+
+    
+    /**
+     * This method initializes jScrollPane      
+     *  
+     * @return javax.swing.JScrollPane  
+     */    
+    private JScrollPane getParameterTreeScrollPane()
+        {
+        if (parameterTreeScrollPane == null)
+            {
+            parameterTreeScrollPane = new JScrollPane();
+            parameterTreeScrollPane.setViewportView(getParameterTree());
+            parameterTreeScrollPane.setPreferredSize(new java.awt.Dimension(150,363));
+            }
+        return parameterTreeScrollPane;
+        }
+    /**
+     * This method initializes jTree    
+     *  
+     * @return javax.swing.JTree        
+     */    
+    private JTree getParameterTree()
+        {
+        if (parameterTree == null)
+            {
+            DefaultMutableTreeNode root = new DefaultMutableTreeNode();
+            DefaultTreeModel model = new DefaultTreeModel(root);
+            parameterTree = new JTree(model);
+            parameterTree.setRootVisible(false);
+            parameterTree.setShowsRootHandles(false);
+            parameterTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener()
+                { 
+                public void valueChanged(javax.swing.event.TreeSelectionEvent e)
+                    {
+                    DefaultTableModel tableModel = (DefaultTableModel)parameterTable.getModel();
+                    int rows = tableModel.getRowCount();
+                    for (int row = rows-1; row >= 0; --row)
+                        {
+                        tableModel.removeRow(row);
+                        }
+
+                    TreePath path = e.getPath();
+                    Object[] oPath = path.getPath();
+                    StringBuffer sBuff = new StringBuffer();
+                    // Ignore the root node.
+                    for (int i = 1; i < oPath.length; ++i)
+                        {
+                        sBuff.append(oPath[i]);
+                        if (i < oPath.length-1)
+                            {
+                            sBuff.append('.');
+                            }
+                        }
+
+                    String[] newRow =
+                        {"", "", ""};
+                    DefaultMutableTreeNode selected = (DefaultMutableTreeNode)oPath[oPath.length-1];
+                    if (!selected.equals(oPath[0]))
+                        {
+                        newRow[0] = sBuff.toString();
+                        Parameter param = new Parameter(newRow[0]);
+                        newRow[1] = console.parameters.getString(param,null);
+                        newRow[2] = console.parameters.getLocation(param);
+                        
+                        if (newRow[1] != null)
+                            {
+                            tableModel.addRow(newRow);
+                            }
+                        }
+
+                    if (!newRow[0].equals(""))
+                        {
+                        newRow[0] = newRow[0]+".";
+                        }
+                    
+                    if(!selected.isLeaf())
+                        {
+                        int children = selected.getChildCount();
+                        for (int ch = 0; ch < children; ++ch)
+                            {
+                            TreeNode child = selected.getChildAt(ch);
+                            String childRow[] = new String[3];
+                            childRow[0] = newRow[0]+child;
+                            Parameter param = new Parameter(childRow[0]);
+                            childRow[1] = console.parameters.getString(param,null);
+                            childRow[2] = console.parameters.getLocation(param);
+                                                        
+                            if (childRow[1] != null)
+                                {
+                                tableModel.addRow(childRow);
+                                }
+                            }
+                        }
+                    }
+                });
+            }
+        return parameterTree;
+        }
+    /**
+     * This method initializes jScrollPane1     
+     *  
+     * @return javax.swing.JScrollPane  
+     */    
+    private JScrollPane getParameterTableScrollPane()
+        {
+        if (parameterTableScrollPane == null)
+            {
+            parameterTableScrollPane = new JScrollPane();
+            parameterTableScrollPane.setViewportView(getParameterTable());
+            }
+        return parameterTableScrollPane;
+        }
+    /**
+     * This method initializes jTable   
+     *  
+     * @return javax.swing.JTable       
+     */    
+    private JTable getParameterTable()
+        {
+        if (parameterTable == null)
+            {
+            String[] cn =
+                {"Parameter", "Value", "Source"};
+            DefaultTableModel model = new DefaultTableModel(cn,0);
+            model.addTableModelListener(new TableModelListener()
+                {
+                public void tableChanged(TableModelEvent evt)
+                    {
+                    if (evt.getColumn() == 1 && 
+                        evt.getType() == TableModelEvent.UPDATE)
+                        {
+
+                        int row = evt.getFirstRow();
+                        DefaultTableModel model = (DefaultTableModel)evt.getSource();
+                        String key = (String)model.getValueAt(row,0);
+                        String value = (String)model.getValueAt(row,1);
+                        Parameter parameter = new Parameter(key);
+                        if (!console.parameters.getString(parameter,null).equals(value))
+                            {
+                            System.out.println("setting parameter "+parameter+" to "+value);
+                            console.parameters.set(parameter, value);
+                            }
+                        }
+                    }
+                });
+            
+            parameterTable = new JTable(model);
+            parameterTable.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
+            parameterTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
+            parameterTable.getColumnModel().getColumn(0).setPreferredWidth(150);
+            parameterTable.getColumnModel().getColumn(1).setPreferredWidth(150);
+            parameterTable.getColumnModel().getColumn(2).setPreferredWidth(450);
+
+            final JComboBox valueEditor = new JComboBox();
+//            valueEditor.setEditable(true);
+            parameterTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(valueEditor));
+            valueEditor.addFocusListener(new FocusAdapter()
+                {
+                public void focusGained(FocusEvent evt)
+                    {
+                    int row = parameterTable.getSelectedRow();
+                    String pName = (String)parameterTable.getValueAt(row,0);
+                    Set values = console.parameters.getShadowedValues(new Parameter(pName));
+                    DefaultComboBoxModel model = new DefaultComboBoxModel(values.toArray());
+                    valueEditor.setModel(model);
+                    }
+                });
+            }
+        
+        return parameterTable;
+        }
+    /**
+     * This method initializes jSplitPane   
+     *      
+     * @return javax.swing.JSplitPane       
+     */    
+    private JSplitPane getJSplitPane()
+        {
+        if (jSplitPane == null)
+            {
+            jSplitPane = new JSplitPane();
+            jSplitPane.setLeftComponent(getParameterTreeScrollPane());
+            jSplitPane.setRightComponent(getParameterTableScrollPane());
+            jSplitPane.setDividerSize(5);
+            jSplitPane.setDividerLocation(200);
+            }
+        return jSplitPane;
+        }
+    
+    /**
+     * This is the default constructor
+     */
+    public ParametersPanel(Console console)
+        {
+        super();
+        initialize();
+        this.console = console;
+        }
+    /**
+     * This method initializes this
+     * 
+     * @return void
+     */
+    private void initialize()
+        {
+        this.setLayout(new BorderLayout());
+        this.setSize(645, 321);
+        this.add(getJSplitPane(), java.awt.BorderLayout.CENTER);
+        }
+    
+    void loadParameters()
+        {
+        parameterTree.setModel(console.parameters.buildTreeModel());
+        parameterTree.setRootVisible(true);
+        }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/StatisticsChartPane.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/StatisticsChartPane.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/StatisticsChartPane.java	(revision 6152)
@@ -0,0 +1,117 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 17, 2005 11:20:52 AM
+ * 
+ * By: spaus
+ */
+package ec.display;
+
+import java.awt.Color;
+
+import javax.swing.JTabbedPane;
+
+
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+
+import ec.EvolutionState;
+import ec.Setup;
+import ec.Statistics;
+import ec.display.chart.ChartableStatistics;
+import ec.display.chart.StatisticsChartPaneTab;
+import ec.util.Parameter;
+
+/**
+ * @author spaus
+ */
+public class StatisticsChartPane
+    extends JTabbedPane
+    implements Setup
+    {
+    public int numCharts;
+    
+    /**
+     * 
+     */
+    public StatisticsChartPane()
+        {
+        super();
+        initialize();
+        }
+    
+    /**
+     * @param tabPlacement
+     */
+    public StatisticsChartPane(int tabPlacement)
+        {
+        super(tabPlacement);
+        initialize();
+        }
+    
+    /**
+     * @param tabPlacement
+     * @param tabLayoutPolicy
+     */
+    public StatisticsChartPane(int tabPlacement, int tabLayoutPolicy)
+        {
+        super(tabPlacement, tabLayoutPolicy);
+        initialize();
+        }
+    
+    private void createCharts(Statistics statistics)
+        {
+        if (statistics instanceof ChartableStatistics)
+            {
+            ChartableStatistics chartStats = (ChartableStatistics)statistics;
+            
+            JFreeChart chart = chartStats.makeChart();
+
+            chart.setBackgroundPaint(Color.white);
+            ChartPanel chartPanel = new ChartPanel(chart);
+            StatisticsChartPaneTab chartPaneTab = new StatisticsChartPaneTab(chartPanel);
+            this.addTab("Chart "+(numCharts++),chartPaneTab);
+            }
+        
+        if (statistics.children != null)
+            {
+            for (int i = 0; i < statistics.children.length; ++i)
+                createCharts(statistics.children[i]);
+            }
+        }
+    
+    /* (non-Javadoc)
+     * @see ec.Setup#setup(ec.EvolutionState, ec.util.Parameter)
+     */
+    public void setup(EvolutionState state, Parameter base)
+        {
+        numCharts = 0;
+        createCharts(state.statistics);
+        }
+    
+    /**
+     * This method initializes this
+     * 
+     * @return void
+     */
+    private  void initialize()
+        {
+        this.setSize(300,200);
+        this.addContainerListener(new java.awt.event.ContainerAdapter()
+            { 
+            public void componentRemoved(java.awt.event.ContainerEvent e)
+                {    
+                StatisticsChartPane pane = (StatisticsChartPane)e.getSource();
+                if (pane.getTabCount() < 1)
+                    {
+                    pane.getParent().remove(pane);
+                    }
+                }
+            });
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/SubpopulationPanel.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/SubpopulationPanel.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/SubpopulationPanel.java	(revision 6152)
@@ -0,0 +1,226 @@
+/*
+  Copyright 2006 by Sean Paus
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 14, 2005 7:39:29 PM
+ * 
+ * By: spaus
+ */
+package ec.display;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JList;
+
+import ec.EvolutionState;
+import ec.Setup;
+import ec.display.portrayal.IndividualPortrayal;
+import ec.display.portrayal.SimpleIndividualPortrayal;
+import ec.util.ParamClassLoadException;
+import ec.util.Parameter;
+import ec.util.ReflectedObject;
+
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import javax.swing.JTree;
+/**
+ * @author spaus
+ */
+public class SubpopulationPanel
+    extends JPanel
+    implements EvolutionStateListener, Setup
+    {
+    
+    private final Console console;
+    private final int subPopNum;
+    private JList individualsList = null;
+    private JScrollPane individualListPane = null;
+    private JSplitPane subpopPane = null;
+    private JSplitPane individualDisplayPane = null;
+    private IndividualPortrayal portrayal = null;
+    private JScrollPane inspectionPane = null;
+    private JTree inspectionTree = null;
+    /**
+     * 
+     */
+    public SubpopulationPanel(Console console, int subPopNum)
+        {
+        super();
+        this.console = console;
+        this.subPopNum = subPopNum;
+        
+        initialize();
+        }
+    
+    /**
+     * @param isDoubleBuffered
+     */
+    public SubpopulationPanel(Console console, int subPopNum, boolean isDoubleBuffered)
+        {
+        super(isDoubleBuffered);
+        this.console = console;
+        this.subPopNum = subPopNum;
+        
+        initialize();
+        }
+    
+    /**
+     * This method initializes this
+     * 
+     * @return void
+     */
+    private  void initialize()
+        {
+        this.setLayout(new BorderLayout());
+        this.setSize(300,200);
+        this.add(getSubpopPane(), java.awt.BorderLayout.CENTER);
+        }
+    
+    /**
+     * This method initializes jList    
+     *  
+     * @return javax.swing.JList        
+     */    
+    private JList getIndividualsList()
+        {
+        if (individualsList == null)
+            {
+            individualsList = new JList();
+            individualsList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+            int size = console.parameters.getInt(new Parameter("pop.subpop."+subPopNum+".size"),null);
+            DefaultListModel model = new DefaultListModel();
+            for (int i = 0; i < size; ++i)
+                {
+                model.add(i,new Integer(i));
+                }
+            individualsList.setModel(model);
+            individualsList.addListSelectionListener(new ListSelectionListener()
+                {
+                public void valueChanged(ListSelectionEvent evt)
+                    {
+                    if (evt.getValueIsAdjusting() == false)
+                        {
+                        JList source = (JList)evt.getSource();
+                        int idx = source.getSelectedIndex();
+                        inspectionTree.setModel(new ReflectedObject(console.state.population.subpops[subPopNum].individuals[idx]));
+                        portrayal.portrayIndividual(console.state,console.state.population.subpops[subPopNum].individuals[idx]);
+                        }
+                    }
+                });
+            }
+        return individualsList;
+        }
+    
+    public void postEvolution(EvolutionStateEvent evt)
+        {
+        int idx = individualsList.getSelectedIndex();
+        if (idx >= 0)
+            {
+            inspectionTree.setModel(new ReflectedObject(console.state.population.subpops[subPopNum].individuals[idx]));
+            portrayal.portrayIndividual(console.state,console.state.population.subpops[subPopNum].individuals[idx]);
+            }
+        }
+    /**
+     * This method initializes jScrollPane      
+     *  
+     * @return javax.swing.JScrollPane  
+     */    
+    private JScrollPane getIndividualListPane()
+        {
+        if (individualListPane == null)
+            {
+            individualListPane = new JScrollPane();
+            individualListPane.setViewportView(getIndividualsList());
+            individualListPane.setPreferredSize(new java.awt.Dimension(75,131));
+            }
+        return individualListPane;
+        }
+    /**
+     * This method initializes jSplitPane       
+     *  
+     * @return javax.swing.JSplitPane   
+     */    
+    private JSplitPane getSubpopPane()
+        {
+        if (subpopPane == null)
+            {
+            subpopPane = new JSplitPane();
+            subpopPane.setLeftComponent(getIndividualListPane());
+            subpopPane.setRightComponent(getIndividualDisplayPane());
+            subpopPane.setResizeWeight(0.0D);
+            subpopPane.setDividerLocation(100);
+            }
+        return subpopPane;
+        }
+    
+    /**
+     * This method initializes jSplitPane1  
+     *      
+     * @return javax.swing.JSplitPane       
+     */    
+    private JSplitPane getIndividualDisplayPane()
+        {
+        if (individualDisplayPane == null)
+            {
+            individualDisplayPane = new JSplitPane();
+            individualDisplayPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
+            individualDisplayPane.setTopComponent(getInspectionPane());
+            individualDisplayPane.setResizeWeight(0.5D);
+            }
+        return individualDisplayPane;
+        }
+
+    public void setup(EvolutionState state, Parameter base)
+        {
+        try
+            {
+            portrayal = (IndividualPortrayal)state.parameters.getInstanceForParameter(base.push("portrayal"),null,IndividualPortrayal.class);
+            }
+        catch (ParamClassLoadException ex)
+            {
+            // default to SimpleIndividualPortrayal
+            portrayal = new SimpleIndividualPortrayal();
+            }
+        portrayal.setup(state, base);
+        individualDisplayPane.setBottomComponent(new JScrollPane((JComponent)portrayal));
+        }
+    /**
+     * This method initializes jScrollPane  
+     *      
+     * @return javax.swing.JScrollPane      
+     */    
+    private JScrollPane getInspectionPane()
+        {
+        if (inspectionPane == null)
+            {
+            inspectionPane = new JScrollPane();
+            inspectionPane.setViewportView(getInspectionTree());
+            }
+        return inspectionPane;
+        }
+    /**
+     * This method initializes jTree        
+     *      
+     * @return javax.swing.JTree    
+     */    
+    private JTree getInspectionTree()
+        {
+        if (inspectionTree == null)
+            {
+            Object[] emptyTreeModel = new Object[0];
+            inspectionTree = new JTree(emptyTreeModel);
+            }
+        return inspectionTree;
+        }
+    }  //  @jve:decl-index=0:visual-constraint="423,73"
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/chart/BarChartStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/chart/BarChartStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/chart/BarChartStatistics.java	(revision 6152)
@@ -0,0 +1,55 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 16, 2005 12:25:57 PM
+ * 
+ * By: spaus, Hovden
+ */
+ package ec.display.chart;
+ 
+ import org.jfree.chart.ChartFactory;
+ import org.jfree.chart.JFreeChart;
+ import org.jfree.chart.plot.PlotOrientation;
+ import org.jfree.data.category.DefaultCategoryDataset;
+ 
+ import ec.EvolutionState;
+ import ec.util.Parameter;
+ 
+ /**
+  * @author spaus
+  */
+ public class BarChartStatistics
+     extends ChartableStatistics
+     {
+     
+     public DefaultCategoryDataset dataset;
+     
+     public void setup(EvolutionState state, Parameter base)
+         {
+         super.setup(state, base);
+             dataset = new DefaultCategoryDataset();
+                 
+                 }
+     
+     public JFreeChart makeChart(){
+         JFreeChart chart = ChartFactory.createBarChart(this.title,
+             this.xlabel,this.ylabel, this.dataset, PlotOrientation.VERTICAL,
+             false, true, false);
+             
+             return chart;
+                 }
+     
+     public void makeBar(int seriesID, double[] genes)
+         {
+         for (int i = 0; i < genes.length; i++)
+             {
+             dataset.setValue(genes[i], "Genome "+seriesID, String.valueOf(i));
+                 }
+             }
+     
+     }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/chart/ChartableStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/chart/ChartableStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/chart/ChartableStatistics.java	(revision 6152)
@@ -0,0 +1,47 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 16, 2005 12:25:57 PM
+ * 
+ * By: spaus
+ */
+package ec.display.chart;
+
+import org.jfree.chart.JFreeChart;
+
+import ec.EvolutionState;
+import ec.Statistics;
+import ec.util.Parameter;
+
+/**
+ * @author spaus
+ */
+public abstract class ChartableStatistics
+    extends Statistics
+    {
+    
+    public static final String P_TITLE = "title";
+    public static final String P_XAXIS = "x-axis-label";
+    public static final String P_YAXIS = "y-axis-label";
+    
+    public String title;
+    public String xlabel;
+    public String ylabel;
+    
+    public void setup(EvolutionState state, Parameter base)
+        {
+        super.setup(state, base);
+        
+        title = state.parameters.getStringWithDefault(base.push(P_TITLE),null,"Title");
+        xlabel = state.parameters.getStringWithDefault(base.push(P_XAXIS),null,"x");
+        ylabel = state.parameters.getStringWithDefault(base.push(P_YAXIS),null,"y");
+        }
+    
+    public abstract JFreeChart makeChart();
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/chart/StatisticsChartPaneTab.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/chart/StatisticsChartPaneTab.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/chart/StatisticsChartPaneTab.java	(revision 6152)
@@ -0,0 +1,185 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 17, 2005 12:29:01 PM
+ * 
+ * By: spaus
+ */
+package ec.display.chart;
+
+import javax.swing.JPanel;
+
+import java.awt.BorderLayout;
+import java.awt.FileDialog;
+import java.awt.Frame;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.FileOutputStream;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.pdf.DefaultFontMapper;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfTemplate;
+import com.lowagie.text.pdf.PdfWriter;
+
+import ec.display.StatisticsChartPane;
+/**
+ * @author spaus
+ */
+public class StatisticsChartPaneTab
+    extends JPanel
+    {
+    
+    private JPanel jPanel = null;
+    private JButton printButton = null;
+    private JButton closeButton = null;
+    private final ChartPanel chartPane;
+    /**
+     * 
+     */
+    public StatisticsChartPaneTab(ChartPanel chartPane)
+        {
+        super();
+        this.chartPane = chartPane;
+        initialize();
+        this.add(chartPane,BorderLayout.CENTER);
+        }
+    
+    /**
+     * @param isDoubleBuffered
+     */
+    public StatisticsChartPaneTab(ChartPanel chartPane, boolean isDoubleBuffered)
+        {
+        super(isDoubleBuffered);
+        this.chartPane = chartPane;
+        initialize();
+        this.add(chartPane,BorderLayout.CENTER);
+        }
+    
+    /**
+     * This method initializes this
+     * 
+     * @return void
+     */
+    private  void initialize()
+        {
+        this.setLayout(new BorderLayout());
+        this.setSize(300,200);
+        this.add(getJPanel(), java.awt.BorderLayout.SOUTH);
+        }
+    
+    /**
+     * This method initializes jPanel   
+     *  
+     * @return javax.swing.JPanel       
+     */    
+    private JPanel getJPanel()
+        {
+        if (jPanel == null)
+            {
+            jPanel = new JPanel();
+            jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.X_AXIS));
+            jPanel.add(Box.createHorizontalGlue());
+            jPanel.add(getPrintButton(), null);
+            jPanel.add(getCloseButton(), null);
+            }
+        return jPanel;
+        }
+    
+    /**
+     * This method initializes jButton  
+     *  
+     * @return javax.swing.JButton      
+     */    
+    private JButton getPrintButton()
+        {
+        if (printButton == null)
+            {
+            printButton = new JButton();
+            printButton.setText("Export to PDF...");
+            final JFreeChart chart = chartPane.getChart(); 
+            printButton.addActionListener(new java.awt.event.ActionListener()
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e)
+                    {    
+                    try
+                       
+                        {
+                        int width = chartPane.getWidth();
+                        int height = chartPane.getHeight();
+                        
+                        FileDialog fileDialog = new FileDialog(new Frame(),"Export...",FileDialog.SAVE);
+                        fileDialog.setDirectory(System.getProperty("user.dir"));
+                        fileDialog.setFile("*.pdf");
+                        fileDialog.setVisible(true);
+                        String fileName = fileDialog.getFile();
+                        if ( fileName != null )
+                           
+                            {
+                            if (!fileName.endsWith(".pdf"))
+                                {
+                                fileName = fileName+".pdf";
+                                }
+                            File f = new File(fileDialog.getDirectory(), fileName);
+                            Document document = new Document(new com.lowagie.text.Rectangle(width,height));
+                            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(f));
+                            document.addAuthor("ECJ Console");
+                            document.open();
+                            PdfContentByte cb = writer.getDirectContent();
+                            PdfTemplate tp = cb.createTemplate(width, height);
+                            Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper());
+                            Rectangle2D rectangle2D = new Rectangle2D.Double(0, 0, width, height);
+                            chart.draw(g2, rectangle2D);
+                            g2.dispose();
+                            cb.addTemplate(tp, 0, 0);
+                            document.close();
+                            }
+                        }
+                    catch( Exception ex )
+                       
+                        {
+                        ex.printStackTrace();
+                        }
+                    }
+                });
+            }
+        return printButton;
+        }
+    
+    /**
+     * This method initializes jButton1 
+     *  
+     * @return javax.swing.JButton      
+     */    
+    private JButton getCloseButton()
+        {
+        if (closeButton == null)
+            {
+            closeButton = new JButton();
+            closeButton.setText("Close");
+            final StatisticsChartPaneTab pane = this;
+            closeButton.addActionListener(new java.awt.event.ActionListener()
+                { 
+                public void actionPerformed(java.awt.event.ActionEvent e)
+                    {
+                    StatisticsChartPane parent = (StatisticsChartPane)pane.getParent();
+                    parent.removeTabAt(parent.indexOfComponent(pane));
+                    }
+                });
+            }
+        return closeButton;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/chart/XYSeriesChartStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/chart/XYSeriesChartStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/chart/XYSeriesChartStatistics.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 16, 2005 12:25:57 PM
+ * 
+ * By: spaus, Hovden
+ */
+ package ec.display.chart;
+ 
+ import org.jfree.chart.ChartFactory;
+ import org.jfree.chart.JFreeChart;
+ import org.jfree.chart.plot.PlotOrientation;
+ import org.jfree.data.xy.XYSeries;
+ import org.jfree.data.xy.XYSeriesCollection;
+ 
+ import ec.EvolutionState;
+ import ec.util.Parameter;
+ 
+ /**
+  * @author spaus
+  */
+ public abstract class XYSeriesChartStatistics
+     extends ChartableStatistics 
+     {
+     
+     public XYSeriesCollection seriesCollection;
+     
+     public void setup(EvolutionState state, Parameter base)
+         {
+         super.setup(state, base);
+             
+             seriesCollection = new XYSeriesCollection();
+                 
+                 }
+     
+     public JFreeChart makeChart(){
+         JFreeChart chart = ChartFactory.createXYLineChart(this.title,this.xlabel,this.ylabel,this.seriesCollection,PlotOrientation.VERTICAL,true,false,false);
+             
+             return chart;
+                 }
+     
+     public int addSeries(String name)
+         {
+         seriesCollection.addSeries(new XYSeries(name));
+             return seriesCollection.getSeriesCount()-1;
+                 }
+     
+     public void addDataPoint(int seriesID, double x, double y)
+         {
+         seriesCollection.getSeries(seriesID).add(x,y);
+             }
+     }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/portrayal/IndividualPortrayal.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/portrayal/IndividualPortrayal.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/portrayal/IndividualPortrayal.java	(revision 6152)
@@ -0,0 +1,36 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 17, 2005 8:30:36 PM
+ * 
+ * By: spaus
+ */
+package ec.display.portrayal;
+
+import java.awt.LayoutManager;
+
+import javax.swing.JPanel;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Setup;
+
+/**
+ * @author spaus
+ */
+public abstract class IndividualPortrayal
+    extends JPanel
+    implements Setup
+    {
+    IndividualPortrayal(LayoutManager layout)
+        {
+        super(layout);
+        }
+    
+    public abstract void portrayIndividual(EvolutionState state, Individual individual);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/display/portrayal/SimpleIndividualPortrayal.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/display/portrayal/SimpleIndividualPortrayal.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/display/portrayal/SimpleIndividualPortrayal.java	(revision 6152)
@@ -0,0 +1,78 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 14, 2005 7:38:51 PM
+ * 
+ * By: spaus
+ */
+package ec.display.portrayal;
+
+import java.awt.BorderLayout;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+
+import javax.swing.JTextPane;
+
+import ec.EvolutionState;
+import ec.Individual;
+import ec.util.Log;
+import ec.util.LogRestarter;
+import ec.util.Output;
+import ec.util.Parameter;
+/**
+ * This portrayal uses a text pane to display the results of 
+ * <code>printIndividualForHumans()</code>.  It is the default portrayal.
+ * 
+ * @author spaus
+ */
+public class SimpleIndividualPortrayal
+    extends IndividualPortrayal
+    {
+    
+    private static final LogRestarter restarter = new LogRestarter()
+        {
+        public Log reopen(Log l)
+            throws IOException
+            {
+            return null;
+            }
+        
+        public Log restart(Log l)
+            throws IOException
+            {
+            return null;
+            }
+        };
+    
+    final JTextPane textPane;
+    private CharArrayWriter printIndividualWriter;
+    
+    public SimpleIndividualPortrayal()
+        {
+        super(new BorderLayout());
+        textPane = new JTextPane();
+        textPane.setEditable(false);
+        this.add(textPane,BorderLayout.CENTER);
+        printIndividualWriter = new CharArrayWriter();
+        }
+    
+    public void portrayIndividual(EvolutionState state, Individual individual)
+        {
+        int printIndividualLog = state.output.addLog(printIndividualWriter,restarter,false,false);
+        
+        individual.printIndividualForHumans(state,printIndividualLog);
+        textPane.setText(printIndividualWriter.toString());
+        textPane.setCaretPosition(0);
+        state.output.removeLog(printIndividualLog);
+        printIndividualWriter.reset();
+        }
+    
+    public void setup(EvolutionState state, Parameter base)
+        {
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/ec.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/ec.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/ec.params	(revision 6152)
@@ -0,0 +1,96 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# Some rules about Java Property Lists, which is what the
+# system uses for parameters.  Java property lists are a little weird:
+# 
+# 1. Lines with only whitespace are ignored.
+# 2. Lines beginning with a # are ignored.
+# 3. Initial whitespace is trimmed.  The property is everything up to 
+#    the next chunk of whitespace or a '='
+# 4. A following '=' is *optional*
+# 5. After the chunk of whitespace and the optional '=', the next
+#    whitespace is trimmed.
+# 6. Typically, EVERYTHING after that is the value of the property, 
+#    up to but not including a '\n'. However, my version trims off
+#    the final bit of whitespace if any.
+# 7. If two parameters of the same name are found, the later one
+#    is used.
+#
+# Some examples and warnings:
+#
+# LINE (begins at | )          PROPERTY(between /'s)  VALUE(between /'s)
+#
+# |yo.yo.yo! = heave ho               /yo.yo.yo!/            /heave ho/
+# |my parameter                       /my/                   /parameter/
+# |my=parameter                       /my/                   /parameter/
+# |my= parameter                      /my/                   /parameter/
+# |
+# |#this is a comment
+# |    # this is NOT                  /#/                    /this is NOT/
+# |
+# |   my    =parameter                /my/                   /parameter/
+# |my parameter = this                /my/                   /parameter = this/
+# |myparameter=                       /myparameter/          //
+# |myparameter                        /myparameter/          //
+# |=myparameter                       //                     /myparameter/
+# |watch out here!                    /watch/                /out here!/
+# |comments=don't work  #see?         /comments/             /don't work  #see?/
+#
+#
+# The '.' is the delimiter for hierarchical elements.  
+# You generally shouldn't begin or end a property with an '.'
+#
+# If you want a list to first load some parent lists, include them as parameters:
+#
+#    parent.0 = filename for 0
+#    parent.1 = filename for 1
+#    ....
+#
+# The parameters will load as follows: your parameters will get checked first,
+# Then parent 0 (and all its ancestors), then parent 1 (and all its ancestors),
+# and so on.
+#
+
+
+
+
+
+#
+# Here are a few default values for administration stuff -- you can
+# find some basic evolution parameters in simple/params
+
+
+
+# ec.Evolve
+# ==============================
+
+# This parameter has been deprecated
+# verbosity = 				0
+
+# one thread
+evalthreads = 				1
+breedthreads = 				1
+
+# ECJ used to use this as its initial random seed by default.  No longer, now
+# it's assumed to be the wall clock time by default.
+# seed.0 = 				4357
+seed.0 =				time
+
+
+
+
+# ec.EvolutionState
+# ==============================
+
+# We're not writing checkpoint files.  If we were, we'd do it every
+# generation, and the prefix to all the files would be "ec.*"
+checkpoint =				false
+checkpoint-modulo =                     1
+prefix = 				ec
+
+
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/es/ESDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/es/ESDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/es/ESDefaults.java	(revision 6152)
@@ -0,0 +1,33 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.es;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * ESDefaults.java
+ * 
+ * Created: Thu Sep  7 19:08:19 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class ESDefaults implements DefaultsForm 
+    {
+    public static final String P_ES = "es";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_ES);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/es/ESSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/es/ESSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/es/ESSelection.java	(revision 6152)
@@ -0,0 +1,120 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.es;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * ESSelection.java
+ * 
+ * Created: Thu Sep  7 19:08:19 2000
+ * By: Sean Luke
+ */
+
+/**
+ * ESSelection is a special SelectionMethod designed to be used with 
+ * evolutionary strategies-type breeders.
+ *
+ * <p>To do evolution strategies evolution, the
+ * breeding pipelines should contain at least one ESSelection selection method.
+ * While a child is being generated by the pipeline, the ESSelection object will return a parent
+ * from the pool of mu parents.  The particular parent is chosen round-robin, so all the parents
+ * will have an equal number of children.  It's perfectly fine to have more than one ESSelection
+ * object in the tree, or to call the same one repeatedly during the course of generating a child;
+ * all such objects will consistently return the same parent.  They only increment to the nex
+ * parent in the pool of mu parents after the child has been created from the pipeline.  You can
+ * also mix ESSelection operators with other operators (like Tournament Selection).  But you ought
+ * to have <b>at least one</b> ESSelection operator in the pipeline -- else it wouldn't be Evolution
+ * Strategies, would it?
+
+ <p><b>Default Base</b><br>
+ es.select
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ESSelection extends SelectionMethod 
+    {
+    public static final String P_ESSELECT = "select";
+
+    public Parameter defaultBase()
+        {
+        return ESDefaults.base().push(P_ESSELECT);
+        }
+
+    // MuCommaLambdaBreeder expects us to set the count to nonzero to indicate our existence
+    public void prepareToProduce(final EvolutionState state,
+        final int subpopulation,
+        final int thread)
+        {
+        super.prepareToProduce(state, subpopulation, thread);
+        if (!(state.breeder instanceof MuCommaLambdaBreeder))
+            state.output.fatal("ESSelection was handed a Breeder that's not either MuCommaLambdaBreeder or MuCommaPlusLambdaBreeder.");
+        MuCommaLambdaBreeder breeder = (MuCommaLambdaBreeder)(state.breeder);
+
+        breeder.count[thread] = 1;
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        if (!(state.breeder instanceof MuCommaLambdaBreeder))
+            state.output.fatal("ESSelection was handed a Breeder that's not either MuCommaLambdaBreeder or MuCommaPlusLambdaBreeder.");
+        MuCommaLambdaBreeder breeder = (MuCommaLambdaBreeder)(state.breeder);
+        
+        // determine my position in the array
+        int pos = (breeder.lambda[subpopulation] % state.breedthreads == 0 ? 
+            breeder.lambda[subpopulation]/state.breedthreads :
+            breeder.lambda[subpopulation]/state.breedthreads + 1) * 
+            thread + breeder.count[thread];  // note integer division
+        
+        // determine the parent
+        int parent = pos / breeder.mu[subpopulation]; // note integer division
+
+        // increment our count
+        //breeder.count[thread]++;
+        
+        return parent;
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        if (min>1) // uh oh
+            state.output.fatal("ESSelection used, but it's being asked to produce more than one individual.");
+        if (!(state.breeder instanceof MuCommaLambdaBreeder))
+            state.output.fatal("ESSelection was handed a Breeder that's not either MuCommaLambdaBreeder or MuCommaPlusLambdaBreeder.");
+        MuCommaLambdaBreeder breeder = (MuCommaLambdaBreeder)(state.breeder);
+        
+        // determine my position in the array
+        int pos = (breeder.lambda[subpopulation] % state.breedthreads == 0 ? 
+            breeder.lambda[subpopulation]/state.breedthreads :
+            breeder.lambda[subpopulation]/state.breedthreads + 1) * 
+            thread + breeder.count[thread];  // note integer division
+        
+        // determine the parent
+        int parent = pos / (breeder.lambda[subpopulation] / breeder.mu[subpopulation]); // note outer integer division
+
+        // increment our count
+        //breeder.count[thread]++;
+
+        // and so we return the parent
+        inds[start] = state.population.subpops[subpopulation].individuals[parent];
+
+        // and so we return the parent
+        return 1;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/es/MuCommaLambdaBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/es/MuCommaLambdaBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/es/MuCommaLambdaBreeder.java	(revision 6152)
@@ -0,0 +1,354 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.es;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * MuCommaLambdaBreeder.java
+ * 
+ * Created: Thu Sep  7 17:27:47 2000
+ * By: Sean Luke
+ */
+
+/**
+ * MuCommaLambdaBreeder is a Breeder which, together with
+ * ESSelection, implements the (mu,lambda) breeding strategy and gathers
+ * the comparison data you can use to implement a 1/5-rule mutation mechanism.
+ * 
+ * <p>Evolution strategies breeders require a "mu" parameter and a "lambda"
+ * parameter for each subpopulation.  "mu" refers to the number of parents
+ * from which the new population will be built.  "lambda" refers to the
+ * number of children generated by the mu parents.  Subpopulation sizes
+ * will change as necessary to accommodate this fact in later generations.
+ * The only rule for initial subpopulation sizes is that they must be
+ * greater than or equal to the mu parameter for that subpopulation.
+ *
+ * <p>You can now set your initial subpopulation
+ * size to whatever you like, totally independent of lambda and mu,
+ * as long as it is &gt;= mu.
+ *
+ * <p>MuCommaLambdaBreeder stores mu and lambda values for each subpopulation
+ * in the population, as well as comparisons.  A comparison tells you
+ * if &gt;1/5, &lt;1/5 or =1/5 of the new population was better than its
+ * parents (the so-called evolution strategies "one-fifth rule".
+ * Although the comparisons are gathered, no mutation objects are provided
+ * which actually <i>use</i> them -- you're free to use them in any mutation
+ * objects you care to devise which requires them.
+ *
+ * <p>To do evolution strategies evolution, the
+ * breeding pipelines should contain at least one ESSelection selection method.
+ * While a child is being generated by the pipeline, the ESSelection object will return a parent
+ * from the pool of mu parents.  The particular parent is chosen round-robin, so all the parents
+ * will have an equal number of children.  It's perfectly fine to have more than one ESSelection
+ * object in the tree, or to call the same one repeatedly during the course of generating a child;
+ * all such objects will consistently return the same parent.  They only increment to the next
+ * parent in the pool of mu parents after the child has been created from the pipeline.  You can
+ * also mix ESSelection operators with other operators (like Tournament Selection).  But you ought
+ * to have <b>at least one</b> ESSelection operator in the pipeline -- else it wouldn't be Evolution
+ * Strategies, would it?
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top>es.lambda.<i>subpop-num</i><br>
+ <font size=-1>int >= 0</font></td><td>Specifies the 'lambda' parameter for the subpopulation.</td>
+ </tr>
+ <tr><td valign=top>es.mu.<i>subpop-num</i><br>
+ <font size=-1>int:  a multiple of "lambda"</font></td><td>Specifies the 'mu' parameter for the subpopulation.</td>
+ </tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MuCommaLambdaBreeder extends Breeder
+    {    
+    public static final String P_MU = "mu";
+    public static final String P_LAMBDA = "lambda";
+
+    public int[] mu;
+    public int[] lambda;
+    
+    public Population parentPopulation;
+
+    public byte[] comparison; 
+    public static final byte C_OVER_ONE_FIFTH_BETTER = 1;
+    public static final byte C_UNDER_ONE_FIFTH_BETTER = -1;
+    public static final byte C_EXACTLY_ONE_FIFTH_BETTER = 0;
+   
+    /** Modified by multiple threads, don't fool with this */
+    public int[] count;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // we're not using the base
+        Parameter p = new Parameter(Initializer.P_POP).push(Population.P_SIZE);
+        int size = state.parameters.getInt(p,null,1);  // if size is wrong, we'll let Population complain about it -- for us, we'll just make 0-sized arrays and drop out.
+        
+        mu = new int[size];
+        lambda = new int[size];
+        comparison = new byte[size];
+        
+        // load mu and lambda data
+        for(int x=0;x<size;x++)
+            {
+            lambda[x] = state.parameters.getInt(ESDefaults.base().push(P_LAMBDA).push(""+x),null,1);            
+            if (lambda[x]==0) state.output.error("lambda must be an integer >= 1",ESDefaults.base().push(P_LAMBDA).push(""+x));
+            mu[x] = state.parameters.getInt(ESDefaults.base().push(P_MU).push(""+x),null,1);            
+            if (mu[x]==0) state.output.error("mu must be an integer >= 1",ESDefaults.base().push(P_MU).push(""+x));
+            else if ((lambda[x] / mu[x]) * mu[x] != lambda[x]) // note integer division
+                state.output.error("mu must be a multiple of lambda", ESDefaults.base().push(P_MU).push(""+x));
+            }
+        state.output.exitIfErrors();
+        }
+
+
+
+    /** Sets all subpopulations in pop to the expected lambda size.  Does not fill new slots with individuals. */
+    public Population setToLambda(Population pop, EvolutionState state)
+        {
+        for(int x=0;x<pop.subpops.length;x++)
+            {
+            int s = lambda[x];
+            
+            // check to see if the array's not the right size
+            if (pop.subpops[x].individuals.length != s)
+                // need to increase
+                {
+                Individual[] newinds = new Individual[s];
+                System.arraycopy(pop.subpops[x].individuals,0,newinds,0,
+                    s < pop.subpops[x].individuals.length ? 
+                    s : pop.subpops[x].individuals.length);
+                pop.subpops[x].individuals = newinds;
+                }
+            }
+        return pop;
+        }
+                
+
+    public Population breedPopulation(EvolutionState state) 
+        {
+        // Complete 1/5 statistics for last population
+        
+        if (parentPopulation != null)
+            {
+            // Only go from 0 to lambda-1, as the remaining individuals may be parents.
+            // A child C's parent's index I is equal to C / mu[subpopulation].
+            for (int x=0;x<state.population.subpops.length;x++)
+                {
+                int numChildrenBetter = 0;
+                for (int i = 0; i < lambda[x]; i++)
+                    {
+                    int parent = i / (lambda[x] / mu[x]);  // note integer division
+                    if (state.population.subpops[x].individuals[i].fitness.betterThan(
+                            parentPopulation.subpops[x].individuals[parent].fitness))
+                        numChildrenBetter++;
+                    }
+                if (numChildrenBetter > lambda[x] / 5.0)  // note float division
+                    comparison[x] = C_OVER_ONE_FIFTH_BETTER;
+                else if (numChildrenBetter < lambda[x] / 5.0)  // note float division
+                    comparison[x] = C_UNDER_ONE_FIFTH_BETTER;
+                else comparison[x] = C_EXACTLY_ONE_FIFTH_BETTER;
+                }
+            }
+                        
+        // load the parent population
+        parentPopulation = state.population;
+        
+        // MU COMPUTATION
+        
+        // At this point we need to do load our population info
+        // and make sure it jibes with our mu info
+
+        // the first issue is: is the number of subpopulations
+        // equal to the number of mu's?
+
+        if (mu.length!=state.population.subpops.length) // uh oh
+            state.output.fatal("For some reason the number of subpops is different than was specified in the file (conflicting with Mu and Lambda storage).",null);
+
+        // next, load our population, make sure there are no subpopulations smaller than the mu's
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            if (state.population.subpops[0].individuals.length < mu[x])
+                state.output.error("Subpopulation " + x + " must be a multiple of the equivalent mu (that is, "+ mu[x]+").");
+            }
+        state.output.exitIfErrors();
+        
+        
+
+
+        int numinds[][] = 
+            new int[state.breedthreads][state.population.subpops.length];
+        int from[][] = 
+            new int[state.breedthreads][state.population.subpops.length];
+            
+        // sort evaluation to get the Mu best of each subpopulation
+        
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            final Individual[] i = state.population.subpops[x].individuals;
+
+            java.util.Arrays.sort(i,
+                new java.util.Comparator()
+                    {
+                    public int compare(Object o1, Object o2)
+                        {
+                        Individual a = (Individual) o1;
+                        Individual b = (Individual) o2;
+                        // return 1 if should appear after object b in the array.
+                        // This is the case if a has WORSE fitness.
+                        if (b.fitness.betterThan(a.fitness)) return 1;
+                        // return -1 if a should appear before object b in the array.
+                        // This is the case if b has WORSE fitness.
+                        if (a.fitness.betterThan(b.fitness)) return -1;
+                        // else return 0
+                        return 0;
+                        }
+                    });
+            }
+
+        // now the subpops are sorted so that the best individuals
+        // appear in the lowest indexes.
+
+        Population newpop = setToLambda((Population) state.population.emptyClone(),state);
+
+        // create the count array
+        count = new int[state.breedthreads];
+
+        // divvy up the lambda individuals to create
+
+        for(int y=0;y<state.breedthreads;y++)
+            for(int x=0;x<state.population.subpops.length;x++)
+                {
+                // figure numinds
+                if (y<state.breedthreads-1) // not last one
+                    numinds[y][x]=
+                        lambda[x]/state.breedthreads;
+                else // in case we're slightly off in division
+                    numinds[y][x]=
+                        lambda[x]/state.breedthreads +
+                        (lambda[x] - (lambda[x] / state.breedthreads)  // note integer division
+                        *state.breedthreads);                   
+                
+                // figure from
+                from[y][x]=
+                    (lambda[x]/
+                    state.breedthreads) * y;
+                }
+            
+        if (state.breedthreads==1)
+            {
+            breedPopChunk(newpop,state,numinds[0],from[0],0);
+            }
+        else
+            {
+            Thread[] t = new Thread[state.breedthreads];
+                
+            // start up the threads
+            for(int y=0;y<state.breedthreads;y++)
+                {
+                MuLambdaBreederThread r = new MuLambdaBreederThread();
+                r.threadnum = y;
+                r.newpop = newpop;
+                r.numinds = numinds[y];
+                r.from = from[y];
+                r.me = this;
+                r.state = state;
+                t[y] = new Thread(r);
+                t[y].start();
+                }
+                
+            // gather the threads
+            for(int y=0;y<state.breedthreads;y++) try
+                                                      {
+                                                      t[y].join();
+                                                      }
+                catch(InterruptedException e)
+                    {
+                    state.output.fatal("Whoa! The main breeding thread got interrupted!  Dying...");
+                    }
+            }
+
+        return postProcess(newpop,state.population,state);
+        }
+
+    /** A hook for Mu+Lambda, not used in Mu,Lambda */
+
+    public Population postProcess(Population newpop, Population oldpop, EvolutionState state)
+        {
+        return newpop;
+        }
+    
+    
+    int[] children;
+    int[] parents;
+    
+    
+    /** A private helper function for breedPopulation which breeds a chunk
+        of individuals in a subpopulation for a given thread.
+        Although this method is declared
+        public (for the benefit of a private helper class in this file),
+        you should not call it. */
+    
+    public void breedPopChunk(Population newpop, EvolutionState state, 
+        int[] numinds, int[] from, int threadnum) 
+        {
+        for(int subpop=0;subpop<newpop.subpops.length;subpop++)
+            {
+            // reset the appropriate count slot  -- this used to be outside the for-loop, a bug
+            // I believe
+            count[threadnum]=0;
+        
+            BreedingPipeline bp = (BreedingPipeline) newpop.subpops[subpop].
+                species.pipe_prototype.clone();
+            
+            // check to make sure that the breeding pipeline produces
+            // the right kind of individuals.  Don't want a mistake there! :-)
+            if (!bp.produces(state,newpop,subpop,threadnum))
+                state.output.fatal("The Breeding Pipeline of subpopulation " + subpop + " does not produce individuals of the expected species " + newpop.subpops[subpop].species.getClass().getName() + " or fitness " + newpop.subpops[subpop].species.f_prototype );
+            bp.prepareToProduce(state,subpop,threadnum);
+            if (count[threadnum] == 0)  // the ESSelection didn't set it to nonzero to inform us of his existence
+                state.output.warning("Whoa!  Breeding Pipeline for subpop " + subpop + " doesn't have an ESSelection, but is being used by MuCommaLambdaBreeder or MuPlusLambdaBreeder.  That's probably not right.");
+            // reset again
+            count[threadnum] = 0;
+        
+            // start breedin'!
+            
+            int upperbound = from[subpop]+numinds[subpop];
+            for(int x=from[subpop];x<upperbound;x++)
+                {
+                if (bp.produce(1,1,x,subpop, newpop.subpops[subpop].individuals,
+                        state,threadnum) != 1)
+                    state.output.fatal("Whoa! Breeding Pipeline for subpop " + subpop + " is not producing one individual at a time, as is required by the MuLambda strategies.");
+
+                // increment the count
+                count[threadnum]++;
+                }
+            bp.finishProducing(state,subpop,threadnum);
+            }
+        }
+    }
+
+
+/** A private helper class for implementing multithreaded breeding */
+class MuLambdaBreederThread implements Runnable
+    {
+    Population newpop;
+    public int[] numinds;
+    public int[] from;
+    public MuCommaLambdaBreeder me;
+    public EvolutionState state;
+    public int threadnum;
+    public void run()
+        {
+        me.breedPopChunk(newpop,state,numinds,from,threadnum);
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/es/MuPlusLambdaBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/es/MuPlusLambdaBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/es/MuPlusLambdaBreeder.java	(revision 6152)
@@ -0,0 +1,70 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.es;
+import ec.*;
+
+/* 
+ * MuPlusLambdaBreeder.java
+ * 
+ * Created: Thu Sep  7 18:49:42 2000
+ * By: Sean Luke
+ */
+
+/**
+ * MuPlusLambdaBreeder is a subclass of MuCommaLambdaBreeder which, together with
+ * ESSelection, implements the (mu + lambda) breeding strategy and gathers
+ * the comparison data you can use to implement a 1/5-rule mutation mechanism.
+ * Note that MuPlusLambdaBreeder increases subpopulation sizes by their mu
+ * values in the second generation and keep them at that size thereafter.
+ * See MuCommaLambdaBreeder for information about how to set mu and lambda.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MuPlusLambdaBreeder extends MuCommaLambdaBreeder
+    {
+    /** Sets all subpopulations in pop to the expected mu+lambda size.  Does not fill new slots with individuals. */
+    public Population setToMuPlusLambda(Population pop, EvolutionState state)
+        {
+        for(int x=0;x<pop.subpops.length;x++)
+            {
+            int s = mu[x]+lambda[x];
+            
+            // check to see if the array's big enough
+            if (pop.subpops[x].individuals.length != s)
+                // need to increase
+                {
+                Individual[] newinds = new Individual[s];
+                System.arraycopy(pop.subpops[x].individuals,0,newinds,0,
+                    s < pop.subpops[x].individuals.length ? 
+                    s : pop.subpops[x].individuals.length);
+                pop.subpops[x].individuals = newinds;
+                }
+            }
+        return pop;
+        }
+
+    public Population postProcess(Population newpop, Population oldpop, EvolutionState state)
+        {
+        // first we need to expand newpop to mu+lambda in size
+        newpop = setToMuPlusLambda(newpop,state);
+        
+        // now we need to dump the old population into the high end of the new population
+         
+        for(int x=0;x<newpop.subpops.length;x++)
+            {
+            for(int y=0;y<mu[x];y++)
+                {
+                newpop.subpops[x].individuals[y+lambda[x]] =
+                    (Individual)(oldpop.subpops[x].individuals[y].clone());
+                }
+            }
+        return newpop;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/es/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/es/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/es/README	(revision 6152)
@@ -0,0 +1,30 @@
+This package implements the (mu+lambda) and (mu,lambda) evolution strategies.
+Use this package in conjunction with the 'simple' package (that is,
+generational evolution).  The provided es.params file shows some more
+information on how to do this.
+
+These techniques are implemented with custom Breeders in combination with a
+special SelectionMethod which handles the dirty work of truncation selection.
+The SelectionMethod is:
+
+	ec.es.ESSelection
+
+This method should only be used with the Breeders in this package.  You can
+place ESSelection anywhere in your pipeline, including multiple times if you
+like.  It will return the mu best individuals in the population, one at a time,
+each time it's pulsed.  Individual ESSelection methods in various parts of
+your pipeline will return the same individual.
+
+The (mu,lambda) evolution strategy is implemented with the Breeder
+
+	ec.es.MuCommaLambdaBreeder
+
+This breeder requires you to specify a 'mu' value and a 'lambda' value for
+each subpopulation.  You need to provide a 'lambda' value instead of just
+the subpopulation size because the subpopulation size is used solely to set the
+INITIAL size of the subpopulation.  
+
+The (mu+lambda) evolution strategy has exactly the same options, and is
+implemented in a subclass:
+
+	ec.es.MuPlusLambdaBreeder
Index: branches/OKBJavaConnector/ECJClient/src/ec/es/es.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/es/es.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/es/es.params	(revision 6152)
@@ -0,0 +1,51 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../simple/simple.params
+
+# 
+# The following parameter file will set up (mu,lambda) evolution,
+# single-threaded, no coevolution, no exchanging,
+# no cross-population breeding, using generational evolution,
+# simple fitness, popsize=1024, etc. 
+# You'll need to fill in some of the gaps.
+#
+# This file tweaks some features in simple.params.  Perhaps you might
+# change parent.0 to ../gp/koza/koza.params if you're doing GP (see below)
+#
+# Some notes: 
+# 1. To perform truncation selection, include the ec.es.ESSelection
+#    selection method in your breeding pipeline.  You can mix in other
+#    selection methods along with it.
+#
+# 2. You need to specify the mu and lambda values for each of your
+#    subpopulations.  This is different than past versions of ECJ where
+#    you didn't specify the lambda -- it was inferred from the subpopulation
+#    size.  However, now, you are permitted to have whatever initial
+#    subpopulation size you like.
+#
+# 3. If you want to do EP-style 50/50 truncation selection, I believe the
+#    way to do it is to set your mu value to the same as the lambda,
+#    and use ec.es.MuPlusLambdaBreeder.
+#
+
+# We begin by specifying the mu value for the first subpopulation,
+# You need to change this and/or specify mu values for additional
+# subpopulations as needed.  We'll default the mu to 1.
+# We'll default the lambda to 10.  What the heck.
+# ================================================================
+
+es.mu.0 =				1
+es.lambda.0 =				10
+breed =					ec.es.MuCommaLambdaBreeder
+
+# you'll need to remember to set up the system so that one, and exactly
+# one, selection method called each time is an ESSelectionMethod.  Here's
+# how you could do it if you were doing Koza-style GP stuff:
+
+# gp.koza.reproduce.source.0 = ec.es.ESSelection
+# gp.koza.xover.source.0 = ec.es.ESSelection
+# gp.koza.xover.source.1 = ec.select.TournamentSelection
+# gp.koza.mutate.source.0 = ec.es.ESSelection
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/Job.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/Job.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/Job.java	(revision 6152)
@@ -0,0 +1,81 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.eval;
+
+import ec.*;
+import java.io.*;
+import ec.util.*;
+
+/**
+ * Job.java
+ *
+
+ This class stores information regarding a job submitted to a Slave: the individuals,
+ the subpopulations in which they are stored, a scratch array for the individuals used
+ internally, and various coevolutionary information (whether we should only count victories
+ single-elimination-tournament style; which individuals should have their fitnesses updated).
+ 
+ <p>Jobs are of two types: traditional evaluations (Slave.V_EVALUATESIMPLE), and coevolutionary
+ evaluations (Slave.V_EVALUATEGROUPED).  <i>type</i> indicates the type of job.
+ For traditional evaluations, we may submit a group of individuals all at one time.  
+ Only the individuals and their subpopulation numbers are needed. 
+ Coevolutionary evaluations require the number of individuals, the subpopulations they come from, the
+ pointers to the individuals, boolean flags indicating whether their fitness is to be updated or
+ not, and another boolean flag indicating whether to count only victories in competitive tournament.
+
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public class Job
+    {
+    // either Slave.V_EVALUATESIMPLE or Slave.V_EVALUATEGROUPED
+    int type;
+
+    boolean sent = false;
+    Individual[] inds;   // original individuals
+    Individual[] newinds;  // individuals that were returned -- may be different individuals!
+    int[] subPops; 
+    boolean countVictoriesOnly;
+    boolean[] updateFitness;
+    
+    void copyIndividualsForward()
+        {
+        if (newinds == null || newinds.length != inds.length)
+            newinds = new Individual[inds.length];
+        for(int i=0; i < inds.length; i++)
+            {
+            newinds[i] = (Individual)(inds[i].clone());
+            }
+        }
+        
+    // a ridiculous hack
+    void copyIndividualsBack(EvolutionState state)
+        {
+        try
+            {
+            DataPipe p = new DataPipe();
+            DataInputStream in = p.input;
+            DataOutputStream out = p.output;
+            
+            for(int i = 0; i < inds.length; i++)
+                {
+                p.reset();
+                newinds[i].writeIndividual(state, out);
+                inds[i].readIndividual(state, in);
+                }
+                
+            newinds = null;
+            }
+        catch (IOException e) 
+            { 
+            e.printStackTrace();
+            state.output.fatal("Caught impossible IOException in Job.copyIndividualsBack()");
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/MasterProblem.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/MasterProblem.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/MasterProblem.java	(revision 6152)
@@ -0,0 +1,325 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.eval;
+
+import ec.*;
+import ec.util.*;
+import ec.coevolve.GroupedProblemForm;
+import ec.simple.SimpleProblemForm;
+import ec.steadystate.QueueIndividual;
+import java.util.ArrayList;
+
+import java.io.*;
+
+/**
+ * MasterProblem.java
+ *
+
+ <p>The MasterProblem is a special ECJ problem that performs evaluations by sending them to
+ a remote Slave process to be evaluated.  As it implements both the
+ <i>SimpleProblemForm</i> and the <i>GroupedProblemForm</i> interfaces, the MasterProblem
+ can perform both traditional EC evaluations as well as coevolutionary evaluations.
+ 
+ <p>When a MasterProblem is specified by the Evaluator, the Problem is set up as usual, but then
+ the MasterProblem replaces it.  The Problem is not garbage collected -- instead, it's hung off the
+ MasterProblem's <tt>problem</tt> variable.  In some sense the Problem is "pushed aside".
+ 
+ <p>If the Evaluator begins by calling prepareToEvaluate(), and we're not doing coevolution, then
+ the MasterProblem does not evaluate individuals immediately.  Instead, it waits for at most 
+ <i>jobSize</i> individuals be submitted via evaluate(), and then sends them all off in a group,
+ called a <i>job</i>, to the remote slave.  In other situations (coevolution, or no prepareToEvaluate())
+ the MasterProblem sends off individuals immediately.
+ 
+ <p>It may be the case that no Slave has space in its queue to accept a new job containing, among others,
+ your new individual.  In this case, calling evaluate() will block until one comes available.  You can avoid
+ this by testing for availability first by calling canEvaluate().  Note that canEvaluate() and evaluate()
+ together are not atomic and so you should not rely on this facility if your system uses multiple threads.
+ 
+ <P>When the individuals or their fitnesses return, they are immediately updated in place.  You have three
+ options to wait for them:
+ 
+ <ul>
+ <li><p>You can wait for all the individuals to finish evaluation by calling finishEvaluating().
+ If you call this method before a job is entirely filled, it will be sent in truncated format (which
+ generally is perfectly fine).  You then block until all the jobs have been completed and the individuals
+ updated.
+    
+ <li><p>You can block until at least one individual is available, by calling getNextEvaluatedIndividual(),
+ which blocks and then returns the individual that was just completed.
+    
+ <li><p>You can test in non-blocking fashion to see if an individual is available, by calling 
+ evaluatedIndividualAvailable().  If this returns true, you may then call getNextEvaluatedIndividual()
+ to get the individual.  Note that this isn't atomic, so don't use it if you have multiple threads.
+ </ul>
+  
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>debug-info</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether the system should display information useful for debugging purposes)<br>
+
+ <tr><td valign=top><i>base.</i><tt>job-size</tt><br>
+ <font size=-1>integer &gt; 0 </font></td>
+ <td valign=top>(how large should a job be at most?)<br>
+ </td></tr>
+
+
+ <!-- technically these are handled by the SlaveMonitor -->
+
+ <tr><td valign=top><tt>eval.master.port</tt><br>
+ <font size=-1>int</font></td>
+ <td valign=top>(the port where the slaves will connect)<br>
+ </td></tr>
+ <tr><td valign=top><tt>eval.compression</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether the communication with the slaves should be compressed or not)<br>
+ </td></tr>
+ <tr><td valign=top><tt>eval.masterproblem.max-jobs-per-slave</tt><br>
+ <font size=-1>int</font></td>
+ <td valign=top>(the maximum load (number of jobs) per slave at any point in time)<br>
+ </td></tr>
+
+ </table>
+
+ * @author Liviu Panait, Keith Sullivan, and Sean Luke
+ * @version 1.0 
+ */
+
+public class MasterProblem extends Problem implements SimpleProblemForm, GroupedProblemForm 
+    {
+    public static final String P_DEBUG_INFO = "debug-info";
+    public static final String P_JOB_SIZE = "job-size";
+        
+    int jobSize;
+    boolean showDebugInfo;
+    public Problem problem;
+    public boolean batchMode;
+    public SlaveMonitor monitor;
+
+    // except for the problem, everything else is shallow-cloned
+    public Object clone()
+        {
+        MasterProblem c = (MasterProblem)(super.clone());
+
+        // shallow-cloned stuff
+        c.monitor = monitor;
+        c.batchMode = batchMode;
+        c.jobSize = jobSize; 
+        c.showDebugInfo = showDebugInfo;
+
+        // deep-cloned stuff
+        c.problem = (Problem)(problem.clone());
+
+        return c;
+        }
+
+    // setup
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        Thread.currentThread().setName("MainThread: ");
+        super.setup(state, base);
+        showDebugInfo = state.parameters.getBoolean(base.push(P_DEBUG_INFO),null,false);
+                
+        jobSize = state.parameters.getIntWithDefault(base.push(P_JOB_SIZE),null,1);
+        if (jobSize<=0)
+            state.output.fatal("The job size must be an integer > 0.", base.push(P_JOB_SIZE));
+
+        batchMode = false;
+        }
+
+    // prepare for a batch of evaluations
+    public void prepareToEvaluate(final EvolutionState state, final int threadnum)
+        {
+        if (jobSize > 1) queue = new ArrayList();
+        batchMode = true;
+        }
+
+    // wait until a batch of evaluations is finished
+    public void finishEvaluating(final EvolutionState state, final int threadnum)
+        {
+        if(showDebugInfo)
+            state.output.message(Thread.currentThread().getName() + "Waiting for all slaves to finish.");
+        flush(state, threadnum);
+        queue = null;  // get rid of it just in case
+                
+        monitor.waitForAllSlavesToFinishEvaluating( state );
+        batchMode = false;
+        if(showDebugInfo)
+            state.output.message(Thread.currentThread().getName() + "All slaves have finished their jobs.");
+        }
+
+    // evaluate a regular individual
+    public void evaluate(EvolutionState state, Individual ind, int subpopulation, int threadnum)
+        {
+        if (jobSize > 1 && batchMode == true)    // chunked evaluation mechanism
+            {
+            queue.add(new QueueIndividual(ind, subpopulation));
+            if (queue.size() >= jobSize)
+                flush(state, threadnum);
+            }
+        else    /// ordinary evaluation mechanism  
+            evaluate(state, new Individual[] { ind }, new int[] { subpopulation }, threadnum);           
+        }
+        
+        
+    ArrayList queue;
+    void flush(EvolutionState state, int threadnum)
+        {
+        int subpopulation;
+        if (queue!=null && queue.size() > 0 )
+            {
+            Individual[] inds = new Individual[queue.size()];
+            int[] subpopulations = new int[queue.size()];
+            for(int i = 0; i < queue.size(); i++)
+                {
+                QueueIndividual qind = (QueueIndividual)(queue.get(i));
+                inds[i] = qind.ind;
+                subpopulations[i] = qind.subpop; 
+                }
+            evaluate(state, inds, subpopulations, threadnum);
+            }
+        queue = new ArrayList();
+        }
+
+
+    // send a group of individuals to one slave for evaluation 
+    void evaluate(EvolutionState state, Individual inds[], int[] subpopulations, int threadnum)
+        {
+        if(showDebugInfo)
+            state.output.message(Thread.currentThread().getName() + "Starting a " + (batchMode ? "batched " : "") + "SimpleProblemForm evaluation.");
+
+        // Acquire a slave socket
+        Job job = new Job();
+        job.type = Slave.V_EVALUATESIMPLE;
+        job.inds = inds;
+        job.subPops = subpopulations ;
+        job.updateFitness = new boolean[inds.length]; 
+        for (int i=0 ; i < inds.length; i++) 
+            job.updateFitness[i]=true; 
+        monitor.scheduleJobForEvaluation(state,job);
+        if( !batchMode )
+            monitor.waitForAllSlavesToFinishEvaluating( state );
+        if(showDebugInfo) state.output.message(Thread.currentThread().getName() + "Finished a " + (batchMode ? "batched " : "") + "SimpleProblemForm evaluation.");
+        }
+        
+        
+        
+
+    /* (non-Javadoc)
+     * @see ec.simple.SimpleProblemForm#describe(ec.EvolutionState, ec.Individual, int, int)
+     */
+    public void describe(EvolutionState state, Individual ind, int subpopulation, int threadnum, int log) 
+        {
+        if ((problem instanceof SimpleProblemForm)) 
+            {
+            ((SimpleProblemForm)problem).describe(state, ind, subpopulation, threadnum, log);
+            }
+        }
+
+    /* (non-Javadoc)
+     * @see ec.coevolve.GroupedProblemForm#preprocessPopulation(ec.EvolutionState, ec.Population)
+     */
+    public void preprocessPopulation(EvolutionState state, Population pop, boolean countVictoriesOnly) 
+        {
+        if (!(problem instanceof GroupedProblemForm)) 
+            {
+            state.output.fatal("MasterProblem.preprocessPopulation(...) invoked, but the underlying Problem is not of GroupedProblemForm");
+            }
+                
+        ((GroupedProblemForm) problem).preprocessPopulation(state, pop, countVictoriesOnly);
+        }
+
+    /* (non-Javadoc)
+     * @see ec.coevolve.GroupedProblemForm#postprocessPopulation(ec.EvolutionState, ec.Population)
+     */
+    public void postprocessPopulation(EvolutionState state, Population pop, boolean countVictoriesOnly) 
+        {
+        if (!(problem instanceof GroupedProblemForm)) 
+            {
+            state.output.fatal("MasterProblem.postprocessPopulation(...) invoked, but the underlying Problem is not of GroupedProblemForm");
+            }
+                
+        ((GroupedProblemForm) problem).postprocessPopulation(state, pop, countVictoriesOnly);
+        }
+
+    // regular coevolutionary evaluation
+    public void evaluate(EvolutionState state, Individual[] inds,
+        boolean[] updateFitness, boolean countVictoriesOnly, int[] subpops, int threadnum)
+        {
+        if(showDebugInfo)
+            state.output.message("Starting a GroupedProblemForm evaluation.");
+
+        // Acquire a slave socket
+        Job job = new Job();
+        job.type = Slave.V_EVALUATEGROUPED;
+        job.subPops = subpops;
+        job.countVictoriesOnly = countVictoriesOnly;
+        job.inds = inds;
+        job.updateFitness = updateFitness;
+        monitor.scheduleJobForEvaluation(state,job);
+                
+        if( !batchMode )
+            monitor.waitForAllSlavesToFinishEvaluating( state );
+
+        if(showDebugInfo)
+            state.output.message("Finished the GroupedProblemForm evaluation.");
+        }
+
+    /** Custom serialization */
+    private void writeObject(ObjectOutputStream out) throws IOException
+        {
+        out.writeObject(problem);
+        }
+
+    /** Custom serialization */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+        {
+        problem = (Problem) in.readObject();
+        }
+
+    /** Initialize contacts with the slaves */
+    public void initializeContacts( final EvolutionState state )
+        {
+        if(showDebugInfo)
+            state.output.message(Thread.currentThread().getName() + "Spawning the server thread.");
+        monitor = new SlaveMonitor(state, showDebugInfo);
+        }
+
+    /** Reinitialize contacts with the slaves */
+    public void reinitializeContacts( final EvolutionState state )
+        {
+        initializeContacts(state);
+        }
+
+    /** Gracefully close contacts with the slaves */
+    public void closeContacts(EvolutionState state, int result)
+        {
+        monitor.shutdown();
+        }
+        
+    public boolean canEvaluate() 
+        {
+        return (monitor.numAvailableSlaves() != 0); 
+        }
+        
+    /** This will only return true if (1) the EvolutionState is a SteadyStateEvolutionState and
+        (2) an individual has returned from the system.  If you're not doing steady state evolution,
+        you should not call this method.  */
+    public boolean evaluatedIndividualAvailable()
+        {
+        return monitor.evaluatedIndividualAvailable();
+        }
+    
+    /** This method blocks until an individual is available from the slaves (which will cause evaluatedIndividualAvailable()
+        to return true), at which time it returns the individual.  You should only call this method
+        if you're doing steady state evolution -- otherwise, the method will block forever. */
+    public QueueIndividual getNextEvaluatedIndividual()
+        {
+        return monitor.waitForIndividual();
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/README	(revision 6152)
@@ -0,0 +1,410 @@
+This directory contains the code for running the ECJ master/slave
+evaluator.  The master/slave evaluator allows you to connect one ECJ
+evolution process with some N remote slave processes.  These processes
+can come on-line at any time, and you can add new processes at any time,
+perhaps if new machines come available, or to replace slaves which have
+died for some reason.  If a remote slave dies, ECJ gracefully handles
+it, rescheduling its jobs to the next available slave.
+
+Slaves run in single-threaded mode, and so have a single random number
+generator each.  A slave receives a 32-bit random number seed from the
+master.  Initially the master selects a random number seed based on
+current wall clock time.  Each time a slave goes on-line, the master
+increments this current seed and gives the slave the revised seed.
+Slaves use this seed regardless of their seeds in their parameter files.
+
+You can use the master/slave evaluator freely in conjunction with island
+models to connect each island to its own private group of N slaves,
+though we have no examples for that in the distribution.
+
+Typical params files for the master and for the slaves are illustrated
+in the ec/app/star directory.
+
+You fire up the master something like this:
+
+java ec.Evolve -file foo.master.params
+
+	(where foo.master.params might have parent.0 be normal ec
+         parameters, and have parent.1 = master.params)
+
+You fire up each of the N slaves something like this:
+
+java ec.eval.Slave -file foo.slave.params
+
+	(where foo.slave.params might have parent.0 be normal ec
+         parameters, and have parent.1 = slave.params)
+
+...and it should all nicely work!  The system works fine under
+checkpointing as far as we know.
+
+
+
+
+
+MASTERS AND SLAVES
+
+The master and slave processes can (and generally ought to) share
+parameter files.  The way a slave knows it's a slave is through the
+addition of the following *slave-only* parameter:
+
+eval.i-am-slave = true
+
+The master sets up distributed evaluation by loading special class,
+called a MasterProblem, which replaces the Problem during evaluation. 
+The MasterProblem is defined by the following *master* parameter:
+
+eval.masterproblem = ec.eval.MasterProblem
+
+When the Evaluator is started up, it normally sets up the Problem class. 
+If eval.masterproblem is set, the Evaluator also loads the master
+problem and then *replaces* the Problem class prototype with a prototype
+of the MasterProblem class.  The Problem prototype is then set to be the
+'problem' instance variable in the MasterProblem prototype.  This
+essentially allows the Problem to stick around even though it's never
+called by the Evaluator any more -- instead, the MasterProblem is
+called.
+
+The MasterProblem's job is to send stuff to remote slaves.  Thus a slave
+should not load it, but instead should load the regular Problem
+instance.  The slave does this by checking the eval.i-am-slave
+parameter.  If it's true, it simply ignores the eval.masterproblem
+parameter entirely.
+
+More information about the architecture may be found near the end of
+this file.
+
+The master listens on socket for new slaves to arrive and register
+themselves. When slaves are fired up, they attempt to attach to this
+socket and negotiate connection.  This means that both the master and
+the slave needs to know the master's port number, and furthermore the
+slave needs to know the master's IP address.  The socket port number is
+specified in the *master and slave* parameter (here set to 15000):
+
+eval.master.port = 15000
+
+The slave is told where the master is with the following *slave*
+parameter:
+
+eval.master.host = put.the.master.ip.address.here
+
+The master and slave can communicate over a compressed stream.  
+Communication is by default compressed.  Note that Java's
+compression routines are broken (they don't support PARTIAL_FLUSH), so we
+have to rely on a third-party library called JZLIB.  You can get the jar
+file for this library on the ECJ main web page or at
+http://www.jcraft.com/jzlib/
+This is specified in the *master and slave* parameter:
+
+eval.compression = true 
+
+Last, the slave can be given a name.  This is solely for debugging
+purposes.  If you don't provide this parameter, the slave will give
+itself an arbitrary name, and that's fine.  The *slave* parameter is:
+
+eval.slave-name = put-my-name-here
+
+The master can print out various debug information if you turn on the
+following parameter:
+
+eval.masterproblem.debug-info = false
+
+
+
+
+JOBS
+
+A slave receives chunks of individuals to evaluate and return as a
+group. This chunk is called a "job".  If you're doing non-coevolutionary
+evolution, you can specify how many individuals the slave should receive
+at one time with the *master* parameter (here set to 100):
+
+eval.master-problem.job-size = 100
+
+If you have very small individuals, or fast evaluation, this makes
+better use of network bandwidth as it sends them as a group, evaluates 
+them all, and then returns them all.  This is because more individuals 
+can get packed into a TCP/IP packet before it's sent out, minimizing
+overhead.  However, the primary effect of changing the job-size is
+to modify the "slave evolution" population size (see the next section).
+
+Another way to improve network efficiency, particularly with very fast
+jobs, is to fill the network buffer with as many jobs as you can fit.
+Each slave mantains a queue of jobs that it's working on.  When the
+master needs to hand a job to a slave, it looks for one whose queue is
+not filled, and then puts the job in the queue.  Each of the slave
+connections keep their TCP/IP buffers stuffed with as many of these
+queued jobs as they can, so jobs are available at the Slaves before
+they even realize it.  To set the queue size, you use the *master* 
+parameter (here it's being set to 100):
+
+eval.masterproblem.max-jobs-per-slave = 100
+
+If you only have 100 individuals in your population (say), this 
+won't fill all the jobs on one slave connection.  The system goes
+round-robin through all the slaves and distributes jobs appropriately.
+Even so, if you have new slaves coming online all the time, they'll
+have to wait if jobs have already been measured out to the other
+slaves, so in that case it might be wise to keep the max-jobs-per-slave
+a bit low.
+
+If you are doing coevolutionary evolution, a job will consist of the
+individuals necessary to perform one joint coevolutionary evaluation.
+
+
+
+SLAVE EVOLUTION
+
+Slaves can operate in one of two modes: "regular" and "evolve".  In
+regular mode, when a slave receives a job, it evaluates them and returns
+them or their resulting fitnesses (see 'FITNESS VERSUS INDIVIDUAL'
+below).  In 'evolve' mode, the slave evaluates its individuals; but if
+it has some extra time on its hands, it then treats the individuals as a
+little population and does some evolution on it.  When time is up, it
+returns the most recent individuals in its little individuals in lieu of
+the original individuals.  This is particularly useful when your
+evaluation procedure is very fast compared to the amount of time spent
+reading and writing individuals over the network.  Note that this only
+works in NON-coevolutionary evolution.
+
+To turn on this feature in a slave, you set the following parameter in
+the *slave*:
+
+eval.run-evolve = true
+
+You will also need to specify how long the slave should do its
+evolution.  This is specified in wall clock time (in milliseconds) with
+the following *slave* parameter, here specifying 6 seconds:
+
+eval.runtime = 6000
+
+Last, you'll need to turn this *slave* parameter on to get
+"evolve" mode working right (see 'FITNESS VERSUS INDIVIDUAL' below for
+more information):
+
+eval.return-inds = true
+
+The size of this mini-"population" the slave is evolving is determined
+by the job-size parameter discussed earlier, so you'll want to set it to
+something appropriate.  Here again it's being set to 100:
+
+eval.master-problem.job-size = 100
+
+
+
+
+
+
+
+FITNESS VERSUS INDIVIDUAL
+
+By default the master/slave system sends individuals from master to
+slave, but only returns FITNESS values from slave to master, in order to
+save on network bandwidth.  However it is possible that some evaluations
+of individuals literally change them during evaluation.  If you have
+done such an evil thing, you'll need to have the modified individual
+shipped back to the master for reinsertion.  Be sure to change the
+appropriate *slave* parameter:
+
+eval.return-inds = true
+
+If you're running in "evolve" mode, you will *always* need to set this
+parameter to true.
+
+
+
+SLAVE CONFIGURATION
+
+Because individuals don't know that they're being evaluated remotely,
+it's best to make your Slave's EvolutionState structure, and particularly
+its Population structure, look and feel as much like the Master as
+possible.  Notably, Subpopulation classes, Species, Individual 
+representations, and Fitnesses should be the same.  This is particularly
+important if when you want to do evolution on the Slave.  The easiest way 
+to do this is simply to derive the Slave's parameter file from the Master's
+paramter file.  
+
+However, if you're doing evolution on the Slave, this doesn't mean you have
+to have the Slave set up the same way as the Master: just the Population 
+and objects hanging off of it.  It might be preferable to do (for example) 
+generational evolution on the Slave while asynchronous steady state 
+evolution is happening on the Master.  You're free to change the high-level
+evolution procedures; but you should maintain the same representations and
+breeding mechanisms so that Individuals on the Slave are valid on the Master
+when they come back.
+
+If the Master and Slave share parameters, what prevents the Slave from
+trying to set up its own MasterProblem as well?  The answer: the i-am-slave
+parameter.  The Evaluator class will not set up a MasterProblem, even if one
+is specified, if i-am-slave is true.
+
+
+
+
+ARCHITECTURE
+
+The system's classes naturally break into two groups: the Slave class
+and the various master-side classes (all others).  The Slave class is
+essentially a replacement for Evolve.java which sets up a dummy ECJ
+process in which to evaluate individuals.  This means, of course, that
+the Slave must have the same basic evolutionary parameters --
+particularly representation parameters -- as the master evolutionary
+process.
+
+The master system is set up by MasterProblem, a special version of the
+Problem class which, instead of evaluating individuals, sends them to
+remote Slaves to be evaluated.  As mentioned before, MasterProblem is
+loaded in the master process and then replaces the original Problem
+instance, in essence "pretending" to be a Problem instance. 
+
+Like any Problem, multiple MasterProblems are created during the course
+of evaluation, one per thread and per generation.  During setup, the
+MasterProblem prototype constructs one shared class which acts as the
+clearing house for remotely evaluating individuals handed it by the
+various MasterProblems.  This class is called the SlaveMonitor.
+
+The SlaveMonitor is responsible for keeping track of the remote
+slave connections.  For each Slave which has connected, the SlaveMonitor
+manages reading and writing to that slave via a SlaveConnection.  The
+SlaveConnection holds the job queue for that remote Slave, holds the
+socket connection and streams to the remote Slave, and runs, in its own
+thread, a worker thread which reads and writes jobs to/from the Slave. 
+MasterProblems submit jobs to the SlaveMonitor, which in turn 
+distributes them to an available slave.
+
+Most evaluation procedures can take advantage of this to provide a
+degree of semi-asynchrony.  For example, SimpleEvaluator performs
+per-thread evaluation in the following way:
+
+	problem.prepareToEvaluate(...)
+	for each individual
+		problem.evaluate(individual,...)
+	problem.finishEvaluating(...)
+
+This protocol informs the underlying Problem that it is free to delay
+actual evaluation of the requested individuals until
+finishEvaluating(...) time.  This in turn allows a MasterProblem to bulk
+up all the individuals as it likes.  The MasterProblem will then read in
+a full job's worth of individuals, then send them out to a slave, then
+read another job's worth of individuals, then send THEM out to another
+slave, and so on.  When SimpleEvaluator calls finishEvaluating, the
+remaining individuals are sent out as a (possibly short) job, and then
+the MasterProblem blocks waiting until all the individuals have come
+back.
+
+The SteadyStateEvaluator performs evaluation in a different way:
+
+	problem.prepareToEvaluate(...) // at the very beginning of evolution!
+	loop forever
+		if problem.canEvaluate(),
+			create/breed individual
+			problem.evaluate(individual, ...)
+		individual = problem.getNextEvaluatedIndividual()
+		if individual != null
+			introduce individual to population
+		sleep a tiny bit to avoid spin-waiting
+
+Note that problem.finishEvaluating(...) is NEVER CALLED.  Here, if a
+Slave's queue can accept another job, the MasterProblem returns true
+from canEvaluate().  Each time problem.evaluate() is called, the
+MasterProblem adds the individual to the job until the job is filled, at
+which time it sends the job off to the Slave.  Likewise, if
+problem.evaluatedIndividualAvailable() returns true from the Master
+Problem -- indicating that a job has come back with individuals for the
+SteadyStateEvaluator, then getNextEvaluatedIndividual() returns the next
+individual in that job.  This is sort of like the SteadyStateEvaluator
+loading individuals onto a bus, and sending it out, and then when busses
+come back to the station, the SteadyStateEvaluator gets the individuals
+one by one as they disembark from the bus. 
+
+A note on how individuals come back from the slaves.  You'd think that
+the indivdiuals are sent out, and either revised fitnesses are read back
+and replace their old fitnesses; or new individuals replace the old
+individuals.  But that's not the case.  This is because the
+MasterProblem actually has no idea where the individuals are stored that
+it's receiving.  Instead we have a bit of an odd way of doing it.
+
+When a job is submitted to a Slave, we send the individuals off to the
+Slave, and then clone all the individuals to 'scratch individuals' a
+second array.  If fitnesses come back, for each individual i in the
+scratch array, we call
+scratchindividual[i].fitness.readFitness(inputStream).  If whole
+individuals come back, for each individual i in the scratch array, we
+call scratchindividual[i].readIndividual(inputStream).  We don't want to
+call these functions on the original individuals because if the Slave
+dies in the middle of transmission, the population's individuals are
+corrupted and our whole evolutionary process is messed up.  That's why
+we read into scratch individuals.
+
+So how do we then get the scratch individuals copied into the originals,
+if we don't know where the originals are stored?  ECJ does not have an
+Individual.copyIndividualIntoMe(individual) function -- it'd be nice if
+it did! Instead, we create a special buffered pipe, stored in
+ec/util/DataPipe.java, and write a scratch individual into it, using
+Individual.writeIndividual(pipeOutputStream). We then read from that
+same pipe into the original individual, using
+Individual.readIndividual(pipeInputStream). It's a hack but a pretty
+one.
+
+
+
+MASTER/SLAVE NETWORK PROTOCOL
+
+The master maintains a thread which continually waits for new slaves
+to come in.  When a slave does in, the master creates a SlaveConnection
+to handle the slave communication.  The SlaveConnection creates a read
+thread and a write thread to keep the pipeline to the slave filled with
+Individuals.
+
+You have the option of using compressed streams.  Unfortunately,
+Java has broken compression -- it doesn't support "partial flush", which
+is critical for doing compressed network streams.  To do compression you
+will need to download the JZLIB library from the ECJ website or from
+http://www.jcraft.com/jzlib/  and ECJ will detect and use it automatically.
+
+
+<On Connection>
+<- slave name							readUTF
+-> random number generator seed					writeInt
+	(note: the seed then increments by SEED_INCREMENT (7919)
+	 and the Slave is free to use any integer values between
+	 the seed and seed + SEED_INCREMENT - 1 to seed its
+	 random number generators.  We hopve 7919 is enough :-)
+-> FLUSH
+
+
+<SlaveConnection's writer protocol loops the following:>
+-> job type							writeByte
+	(Slave.V_EVALUATESIMPLE or Slave.V_EVALUATEGROUPED or
+	 Slave.V_SHUTDOWN)
+If Slave.V_SHUTDOWN,
+	break connection
+If Slave.V_EVALUATEGROUPED,
+	-> countVictoriesOnly					writeBoolean
+-> number of individuals in job					writeInt
+Loop for number of individuals in job,
+	-> individual						writeIndividual
+	-> update ind's fitness					writeBoolean
+-> FLUSH
+
+
+<SlaveConnection's reader protocol loops the following:>
+<- arbitrary byte (to block on)					readByte
+Loop for number of individuals in job,
+	<- returning individual type                            readByte
+        	(Slave.V_INDIVIDUAL or Slave.V_FITNESS)
+	If Slave.V_INDIVIDUAL,
+		<- individual					readIndividual
+	Else if Slave.V_FITNESS,
+		<- evaluated?					readBoolean
+		<- fitness					readFitness
+	Else if Slave.V_NOTHING,
+		(nothing is sent)
+<- FLUSH
+
+Note that the reader protocol does not tell the SlaveConnection how many
+individuals there are in the job.  This is because the SlaveConnection
+already knows: jobs are received in the order they were sent.
+
+The slaves and slave connections shut down when the socket breaks
+or when the Slave.V_SHUTDOWN signal was received.
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/Slave.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/Slave.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/Slave.java	(revision 6152)
@@ -0,0 +1,671 @@
+/*
+  Copyright 2006 by Sean Paus, Sean Luke, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Oct 8, 2004
+ */
+package ec.eval;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import ec.*;
+import ec.coevolve.GroupedProblemForm;
+import ec.simple.SimpleProblemForm;
+import ec.simple.SimpleEvolutionState;
+import ec.util.*;
+
+/**
+ * Slave.java
+ *
+ 
+ <p>Slave is the main entry point for a slave evaluation process.  The slave works with a master process,
+ receiving individuals from the master, evaluating them, and reporting the results back to the master, thus
+ enabling distributed evolution.  
+ 
+ <p>Slave replicates most of the functionality of
+ the ec.Evolve class, for example in terms of parameters and checkpointing.  This is mostly because it needs
+ to bootstrap and set up the EvolutionState in much the same way that ec.Evolve does.  Additionally, depending
+ on settings below, the Slave may act like a mini-evolver on the individuals it receives from the master.
+ 
+ <p>Like ec.Evolve, Slave is run with like this:
+ 
+ <p><tt>java ec.eval.Slave -file </tt><i>parameter_file [</i><tt>-p </tt><i>parameter=value]*</i>
+ 
+ <p>This starts a new slave, using the parameter file <i>parameter_file</i>.
+ The user can provide optional overriding parameters on the command-line with the <tt>-p</tt> option.
+ 
+ <p>Slaves need to know some things in order to run: the master's IP address and socket port number,
+ whether to do compression, and whether or not to return individuals or just fitnesses.  Unfortunately, 
+ Sun's CompressedInputStream/CompressedOutputStream is broken (it doesn't allow partial flushes, which
+ is critical for doing compressed network streams).  In order to do compression, you need to download the
+ JZLIB library from the ECJ website or from http://www.jcraft.com/jzlib/  .  ECJ will detect and use it
+ automatically.
+ 
+ <p>Slaves presently always run in single-threaded mode and receive their random number generator seed
+ from the master.  Thus they ignore any seed parameters given to them.
+ 
+ <p>Slaves run in one of three modes:
+ 
+ <ul>
+ <p><li>"Regular" mode, which does a loop where it receives N individuals, evaluates them, and
+ returns either the individuals or their new fitnesses.
+ <p><li>"Regular Coevolutionary" mode, which does a loop where it receives N individuals to assess together in
+ a single coevolutionary evaluation, evaluates them, and returns either the individuals or their new fitnesses
+ (or only some fitnesses if only some are requested).
+ <p><li>"Evolve" mode, which does a loop where it receives
+ N individuals, evaluates them, and if there's some more time left, does a little evolution on those individuals as
+ if they were a population, then when the time is up, the current individuals in the population are returned in lieu
+ of the original individuals.  In this second form, individuals MUST be returned, not fitnesses.  This mode is not
+ available if you're doing coevolution.
+ </ul>
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ 
+ <tr><td valign=top><tt>eval.slave-name</tt><br>
+ <font size=-1> String </font></td>
+ <td valign=top>(the slave's name, only for debugging purposes.  If not specified, the slave makes one up.)</td></tr>
+
+ <tr><td valign=top><tt>eval.master.host</tt><br>
+ <font size=-1> String </font></td>
+ <td valign=top>(the IP Address of the master.)</td></tr>
+
+ <tr><td valign=top><tt>eval.master.port</tt><br>
+ <font size=-1> integer &gt;= 1024 </font></td>
+ <td valign=top>(the socket port number of the master.)</td></tr>
+
+ <tr><td valign=top><tt>eval.compression</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default) </font></td>
+ <td valign=top>(should we use compressed streams in communicating with the master?)</td></tr>
+
+ <tr><td valign=top><tt>eval.run-evolve</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default) </font></td>
+ <td valign=top>(should we immediately evaluate the individuals and return them (or their fitnesses), or if we have extra time (defined by eval.runtime),
+ should we do a little evolution on our individuals first?)</td></tr>
+
+ <tr><td valign=top><tt>eval.runtime</tt><br>
+ <font size=-1> integer &gt; 0 </font></td>
+ <td valign=top>(if eval.run-evolve is true, how long (in milliseconds wall-clock time) should we allow the individuals to evolve?)</td></tr>
+
+ <tr><td valign=top><tt>eval.return-inds</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default) </font></td>
+ <td valign=top>(should we return whole individuals or (if false) just the fitnesses of the individuals?  This must be TRUE if eval.run-evolve is true.)</td></tr>
+
+ <!-- 
+ <tr><td valign=top><tt>nostore</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should the ec.util.Output facility <i>not</i> store announcements in memory?)</td></tr>
+
+ <tr><td valign=top><tt>flush</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should I flush all output as soon as it's printed (useful for debugging when an exception occurs))</td></tr>
+ -->
+
+ <tr><td valign=top><tt>state</tt><br>
+ <font size=-1>classname, inherits and != ec.EvolutionState</font></td>
+ <td valign=top>(the EvolutionState object class)</td></tr>
+
+ <tr><td valign=top><tt>print-accessed-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters requested during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-used-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters actually <i>used</i> during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-unaccessed-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters NOT requested during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-unused-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters NOT actually used during the run?)</td></tr>
+
+ <tr><td valign=top><tt>print-all-params</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(at the end of a run, do we print out a list of all the parameters stored in the parameter database?)</td></tr>
+
+ </table>
+ 
+ * 
+ * @author Liviu Panait, Sean Paus, Keith Sullivan, and Sean Luke
+ */
+ 
+ 
+ 
+public class Slave 
+    {
+    public final static String P_PRINTACCESSEDPARAMETERS = "print-accessed-params";
+        
+    public final static String P_PRINTUSEDPARAMETERS = "print-used-params";
+        
+    public final static String P_PRINTALLPARAMETERS = "print-all-params";
+        
+    public final static String P_PRINTUNUSEDPARAMETERS = "print-unused-params";
+        
+    public final static String P_PRINTUNACCESSEDPARAMETERS = "print-unaccessed-params";
+        
+    public final static String P_EVALSLAVENAME = "eval.slave-name";
+        
+    public final static String P_EVALMASTERHOST = "eval.master.host";
+        
+    public final static String P_EVALMASTERPORT = "eval.master.port";
+        
+    public final static String P_EVALCOMPRESSION = "eval.compression";
+    
+    public final static String P_RETURNINDIVIDUALS = "eval.return-inds";
+        
+    public static final String P_SUBPOP = "pop.subpop";
+    
+    public static final byte V_NOTHING = 0;
+    public static final byte V_INDIVIDUAL = 1;
+    public static final byte V_FITNESS = 2;
+        
+    public static final byte V_SHUTDOWN = 0;
+    public static final byte V_EVALUATESIMPLE = 1;
+    public static final byte V_EVALUATEGROUPED = 2;
+//    public static final byte V_CHECKPOINT = 3;
+        
+    /* The argument indicating that we're starting up from a checkpoint file. */
+//    public static final String A_CHECKPOINT = "-checkpoint";
+        
+    /** The argument indicating that we're starting fresh from a new parameter file. */
+    public static final String A_FILE = "-file";
+        
+    /* flush announcements parameter */
+    // public static final String P_FLUSH = "flush";
+        
+    /* nostore parameter */
+    // public static final String P_STORE = "store";
+        
+    /** state parameter */
+    public static final String P_STATE = "state";
+        
+    /** Time to run evolution on the slaves in seconds */ 
+    public static final String P_RUNTIME = "eval.runtime"; 
+    public static int runTime=0; 
+        
+    /** Should slave run its own evolutionary process? */ 
+    public static final String P_RUNEVOLVE = "eval.run-evolve"; 
+    public static boolean runEvolve=false; 
+        
+    /** How long we sleep in between attempts to connect to the master (in milliseconds). */
+    public static final int SLEEP_TIME = 100;
+        
+    public static void main(String[] args)
+        {
+        EvolutionState state = null;
+        ParameterDatabase parameters = null;
+        Output output = null;
+
+        boolean store;
+        int x;
+                
+        // 0. find the parameter database
+        for (x = 0; x < args.length - 1; x++)
+            if (args[x].equals(A_FILE))
+                {
+                try
+                    {
+                    parameters = new ParameterDatabase(
+                        // not available in jdk1.1: new File(args[x+1]).getAbsoluteFile(),
+                        new File(new File(args[x + 1]).getAbsolutePath()),
+                        args);
+                                                
+                    // add the fact that I am a slave:      eval.i-am-slave = true
+                    // this is used only by the Evaluator to determine whether to use the MasterProblem
+                    parameters.set(new Parameter(ec.EvolutionState.P_EVALUATOR).push(ec.Evaluator.P_IAMSLAVE), "true");
+                    break;
+                    }
+                catch(FileNotFoundException e)
+                    { 
+                    Output.initialError(
+                        "A File Not Found Exception was generated upon" +
+                        "reading the parameter file \"" + args[x+1] + 
+                        "\".\nHere it is:\n" + e); }
+                catch(IOException e)
+                    { 
+                    Output.initialError(
+                        "An IO Exception was generated upon reading the" +
+                        "parameter file \"" + args[x+1] +
+                        "\".\nHere it is:\n" + e); } 
+                }
+        if (parameters == null)
+            Output.initialError("No parameter file was specified." ); 
+                
+        // 5. Determine whether or not to return entire Individuals or just Fitnesses
+        //    (plus whether or not the Individual has been evaluated).
+        
+        boolean returnIndividuals = parameters.getBoolean(new Parameter(P_RETURNINDIVIDUALS),null,false);
+                
+                
+        // 6. Open a server socket and listen for requests
+        String slaveName = parameters.getString(
+            new Parameter(P_EVALSLAVENAME),null);
+                
+        String masterHost = parameters.getString(
+            new Parameter(P_EVALMASTERHOST),null );
+        int masterPort = parameters.getInt(
+            new Parameter(P_EVALMASTERPORT),null);
+        boolean useCompression = parameters.getBoolean(new Parameter(P_EVALCOMPRESSION),null,false);
+                
+        runTime = parameters.getInt(new Parameter(P_RUNTIME), null, 0); 
+                
+        runEvolve = parameters.getBoolean(new Parameter(P_RUNEVOLVE),null,false); 
+        
+        if (runEvolve && !returnIndividuals)
+            {
+            Output.initialError("You have the slave running in 'evolve' mode, but it's only returning fitnesses to the master, not whole individuals.  This is almost certainly wrong.",
+                new Parameter(P_RUNEVOLVE), new Parameter(P_RETURNINDIVIDUALS));
+            }
+        
+        Output.initialMessage("ECJ Slave");
+        if (runEvolve) Output.initialMessage("Running in Evolve mode, evolve time is " + runTime + " milliseconds");
+        if (returnIndividuals) Output.initialMessage("Whole individuals will be returned");
+        else Output.initialMessage("Only fitnesses will be returned");
+        
+        
+        // Continue to serve new masters until killed.
+        while (true)
+            {
+            try
+                {
+                Socket socket;
+                long connectAttemptCount = 0;
+                Output.initialMessage("Connecting to master at "+masterHost+":"+masterPort);
+                while (true)
+                    {
+                    try
+                        {
+                        socket = new Socket(masterHost, masterPort);
+                        break;
+                        }
+                    catch (ConnectException e)   // it's not up yet...
+                        {
+                        connectAttemptCount++;
+                        try
+                            {
+                            Thread.sleep(SLEEP_TIME);
+                            }
+                        catch( InterruptedException f )
+                            {
+                            }
+                        }
+                    }
+                Output.initialMessage("Connected to master after " + (connectAttemptCount * SLEEP_TIME) + " ms");
+                                
+                DataInputStream dataIn = null;
+                DataOutputStream dataOut = null;
+
+                try
+                    {
+                    InputStream tmpIn = socket.getInputStream();
+                    OutputStream tmpOut = socket.getOutputStream();
+                    if (useCompression)
+                        {
+                        //Output.initialError("JDK 1.5 has broken compression.  For now, you must set eval.compression=false");
+                        /*
+                          tmpIn = new CompressingInputStream(tmpIn);
+                          tmpOut = new CompressingOutputStream(tmpOut);
+                        */
+                        tmpIn = Output.makeCompressingInputStream(tmpIn);
+                        tmpOut = Output.makeCompressingOutputStream(tmpOut);
+                        if (tmpIn == null || tmpOut == null)
+                            Output.initialError("You do not appear to have JZLib installed on your system, and so must set eval.compression=false.  " +
+                                "To get JZLib, download from the ECJ website or from http://www.jcraft.com/jzlib/");
+                        }
+                                                
+                    dataIn = new DataInputStream(tmpIn);
+                    dataOut = new DataOutputStream(tmpOut);
+                    }
+                catch (IOException e)
+                    {
+                    Output.initialError("Unable to open input stream from socket:\n"+e);
+                    }
+                                
+                // specify the slaveName
+                if (slaveName==null)
+                    {
+                    slaveName = socket.getLocalAddress().toString() + "/" + System.currentTimeMillis();
+                    Output.initialMessage("No slave name specified.  Using: " + slaveName);
+                    }
+                                
+                dataOut.writeUTF(slaveName);
+                dataOut.flush();
+
+                // 1. create the output
+                // store = parameters.getBoolean(new Parameter(P_STORE), null, false);
+                
+                if (output != null) output.close();
+                output = new Output(true);
+                //output.setFlush(
+                //    parameters.getBoolean(new Parameter(P_FLUSH),null,false));
+                
+                // stdout is always log #0. stderr is always log #1.
+                // stderr accepts announcements, and both are fully verbose
+                // by default.
+                output.addLog(ec.util.Log.D_STDOUT, false);
+                output.addLog(ec.util.Log.D_STDERR, true);
+
+                output.systemMessage(Version.message());
+
+
+                // 2. set up thread values
+
+/*
+  int breedthreads = parameters.getInt(
+  new Parameter(Evolve.P_BREEDTHREADS),null,1);
+
+  if (breedthreads < 1)
+  output.fatal("Number of breeding threads should be an integer >0.",
+  new Parameter(Evolve.P_BREEDTHREADS),null);
+
+
+  int evalthreads = parameters.getInt(
+  new Parameter(Evolve.P_EVALTHREADS),null,1);
+
+  if (evalthreads < 1)
+  output.fatal("Number of eval threads should be an integer >0.",
+  new Parameter(Evolve.P_EVALTHREADS),null);
+*/
+
+                int breedthreads = Evolve.determineThreads(output, parameters, new Parameter(Evolve.P_BREEDTHREADS));
+                int evalthreads = Evolve.determineThreads(output, parameters, new Parameter(Evolve.P_EVALTHREADS));
+
+                // Note that either breedthreads or evalthreads (or both) may be 'auto'.  We don't warn about this because
+                // the user isn't providing the thread seeds.
+                
+
+                // 3. create the Mersenne Twister random number generators,
+                // one per thread
+
+                MersenneTwisterFast[] random = new MersenneTwisterFast[breedthreads > evalthreads ? 
+                    breedthreads : evalthreads];
+        
+                int seed = dataIn.readInt();
+                for(int i = 0; i < random.length; i++)
+                    random[i] = Evolve.primeGenerator(new MersenneTwisterFast(seed++));  // we prime the generator to be more sure of randomness.
+
+                // 4. Set up the evolution state
+                
+                // what evolution state to use?
+                state = (EvolutionState)
+                    parameters.getInstanceForParameter(new Parameter(P_STATE),null,
+                        EvolutionState.class);
+                state.parameters = new ParameterDatabase();
+                state.parameters.addParent(parameters);
+                state.random = random;
+                state.output = output;
+                state.evalthreads = evalthreads;
+                state.breedthreads = breedthreads;
+        
+                state.setup(state, null);
+                state.population = state.initializer.setupPopulation(state, 0);
+                
+
+                // Is this a Simple or Grouped ProblemForm?
+                int problemType;
+                try
+                    {
+                    while (true)
+                        {
+                        EvolutionState newState = state;
+                        
+                        if (runEvolve) 
+                            {
+                            // Construct and use a new EvolutionState.  This will be inefficient the first time around
+                            // as we've set up TWO EvolutionStates in a row with no good reason.
+                            ParameterDatabase coverDatabase = new ParameterDatabase();  // protect the underlying one
+                            coverDatabase.addParent(state.parameters);
+                            newState = (EvolutionState) Evolve.initialize(coverDatabase, 0);
+                            newState.startFresh();
+                            newState.output.message("Replacing random number generators, ignore above seed message");
+                            newState.random = state.random;  // continue with RNG
+                            }
+                        
+                        // 0 means to shut down
+                        System.err.println("reading next problem");
+                        problemType = dataIn.readByte();
+                        System.err.println("Read problem: " + (int)problemType);
+                        switch (problemType)
+                            {
+                            case V_SHUTDOWN:
+                                socket.close();
+                                return;  // we're outa here
+                            case V_EVALUATESIMPLE:
+                                evaluateSimpleProblemForm(newState, returnIndividuals, dataIn, dataOut, args);
+                                break;
+                            case V_EVALUATEGROUPED:
+                                evaluateGroupedProblemForm(newState, returnIndividuals, dataIn, dataOut);
+                                break;
+                            default:
+                                state.output.fatal("Unknown problem form specified: "+problemType);
+                            }
+                        //System.err.println("Done Evaluating Individual");
+                        }
+
+                    } catch (IOException e)    
+                    {
+                    // Since an IOException can happen here if the peer closes the socket
+                    // on it's end, we don't necessarily have to exit.  Maybe we don't
+                    // even need to print a warning, but we'll do so just to indicate
+                    // something happened.
+                    state.output.warning("Unable to read type of evaluation from master.  Maybe the master closed its socket and exited?:\n"+e);
+                    }
+                } 
+            catch (UnknownHostException e)
+                {
+                state.output.fatal(e.getMessage());
+                }
+            catch (IOException e)
+                {
+                state.output.fatal("Unable to connect to master:\n" + e);
+                }
+            }
+        }
+            
+    public static void evaluateSimpleProblemForm( EvolutionState state, boolean returnIndividuals,
+        DataInputStream dataIn, DataOutputStream dataOut, String[] args )
+        {
+        ParameterDatabase params=null; 
+        
+        // first load the individuals
+        int numInds=1; 
+        try
+            {
+            numInds = dataIn.readInt();
+            }
+        catch (IOException e)
+            {
+            state.output.fatal("Unable to read the number of individuals from the master:\n"+e);
+            }
+        
+        // load the subpops 
+        int[] subpops = new int[numInds];  // subpops desired by each ind
+        int[] indsPerSubpop = new int[state.population.subpops.length];  // num inds for each subpop
+        for(int i = 0; i < numInds; i++)
+            {
+            try
+                {
+                subpops[i] = dataIn.readInt();
+                if (subpops[i] < 0 || subpops[i] >= state.population.subpops.length)
+                    state.output.fatal("Bad subpop number for individual #" + i + ": " + subpops[i]);
+                indsPerSubpop[subpops[i]]++;
+                }
+            catch (IOException e)
+                {
+                state.output.fatal("Unable to read the subpop number from the master:\n"+e);
+                }
+            }
+        
+                
+        // Read the individual(s) from the stream  and evaluate 
+        
+        boolean[] updateFitness = new boolean[numInds];
+        Individual[] inds = new Individual[numInds];
+        try
+            {
+            for (int i=0; i < numInds; i++) 
+                { 
+                inds[i] = state.population.subpops[subpops[i]].species.newIndividual(state, dataIn);
+                if (!runEvolve) 
+                    ((SimpleProblemForm)(state.evaluator.p_problem)).evaluate( state, inds[i], subpops[i], 0 );
+                updateFitness[i] = dataIn.readBoolean(); 
+                }
+            }
+        catch (IOException e)
+            {
+            state.output.fatal("Unable to read individual from master." + e);
+            }
+        
+        
+        if (runEvolve) 
+            {
+            long startTime = System.currentTimeMillis(); 
+            long endTime=0; 
+
+            // Now we need to reset the subpopulations.  They were already set up with the right
+            // classes, Species, etc. in state.setup(), so all we need to do is modify the number
+            // of individuals in each subpopulation.
+        
+            for(int subpop = 0; subpop < state.population.subpops.length; subpop++)
+                {
+                if (state.population.subpops[subpop].individuals.length != indsPerSubpop[subpop])
+                    state.population.subpops[subpop].individuals = new Individual[indsPerSubpop[subpop]];
+                }
+            
+            // Disperse into the population
+            int[] counts = new int[state.population.subpops.length];
+            for(int i =0; i < numInds; i++)
+                state.population.subpops[subpops[i]].individuals[counts[subpops[i]]++] = inds[i];
+            
+            // Evaluate the population until time is up, or the evolution stops
+            int result = state.R_NOTDONE; 
+            while (result == state.R_NOTDONE) 
+                { 
+                result = state.evolve(); 
+                endTime = System.currentTimeMillis(); 
+                if ((endTime - startTime) > runTime) 
+                    break;
+                }
+                
+            // re-gather from population in the same order
+            counts = new int[state.population.subpops.length];
+            for(int i =0; i < numInds; i++)
+                inds[i] = state.population.subpops[subpops[i]].individuals[counts[subpops[i]]++];
+            state.finish(result);
+            Evolve.cleanup(state);
+            }
+
+
+        //System.err.println("Returning Individuals ");
+        // Return the evaluated individual to the master
+        try 
+            { 
+            returnIndividualsToMaster(state, inds, updateFitness, dataOut, returnIndividuals); 
+            } 
+        catch( IOException e ) { state.output.fatal("Caught fatal IOException\n"+e ); }
+        }
+    
+    public static void evaluateGroupedProblemForm( EvolutionState state, boolean returnIndividuals,
+        DataInputStream dataIn, DataOutputStream dataOut )
+        {
+        boolean countVictoriesOnly = false;
+
+        // first load the individuals
+        int numInds = 1;
+        try
+            {
+            countVictoriesOnly = dataIn.readBoolean();
+            numInds = dataIn.readInt();
+            }
+        catch (IOException e)
+            {
+            state.output.fatal("Unable to read the number of individuals from the master:\n"+e);
+            }
+
+        // load the subpops 
+        int[] subpops = new int[numInds];  // subpops desired by each ind
+        int[] indsPerSubpop = new int[state.population.subpops.length];  // num inds for each subpop
+        for(int i = 0; i < numInds; i++)
+            {
+            try
+                {
+                subpops[i] = dataIn.readInt();
+                if (subpops[i] < 0 || subpops[i] >= state.population.subpops.length)
+                    state.output.fatal("Bad subpop number for individual #" + i + ": " + subpops[i]);
+                indsPerSubpop[subpops[i]]++;
+                }
+            catch (IOException e)
+                {
+                state.output.fatal("Unable to read the subpop number from the master:\n"+e);
+                }
+            }
+
+        // Read the individuals from the stream
+        Individual inds[] = new Individual[numInds];
+        boolean updateFitness[] = new boolean[numInds];
+        try
+            {
+            for(int i=0;i<inds.length;++i)
+                {
+                inds[i] = state.population.subpops[subpops[i]].species.newIndividual( state, dataIn );
+                updateFitness[i] = dataIn.readBoolean();
+                }
+            }
+        catch (IOException e)
+            {
+            state.output.fatal("Unable to read individual from master.");
+            }
+                
+        // Evaluate the individuals together
+        ((GroupedProblemForm)(state.evaluator.p_problem)).evaluate( state, inds, updateFitness, countVictoriesOnly, subpops, 0 );
+                                
+        try 
+            {
+            returnIndividualsToMaster(state, inds, updateFitness, dataOut, returnIndividuals); 
+            } 
+        catch( IOException e ) { state.output.fatal("Caught fatal IOException\n"+e ); }
+        }
+        
+    private static void returnIndividualsToMaster(EvolutionState state, Individual []inds, boolean[] updateFitness,
+        DataOutputStream dataOut, boolean returnIndividuals) throws IOException 
+        {
+        // Return the evaluated individual to the master
+        // just write evaluated and fitness
+        for(int i=0;i<inds.length;i++)
+            {
+            //System.err.println("Returning Individual " + i);
+            //System.err.println("writing byte: " + ( returnIndividuals ? V_INDIVIDUAL : (updateFitness[i] ? V_FITNESS : V_NOTHING)));
+            dataOut.writeByte(returnIndividuals ? V_INDIVIDUAL : (updateFitness[i] ? V_FITNESS : V_NOTHING));
+            //System.err.println("wrote byte");
+            if (returnIndividuals)
+                {
+//              System.err.println("Writing Individual");
+                inds[i].writeIndividual(state, dataOut);
+//              System.err.println("Wrote Individual");
+                }
+            else if (updateFitness[i])
+                {
+                dataOut.writeBoolean(inds[i].evaluated);
+                inds[i].fitness.writeFitness(state,dataOut);
+                }
+            }
+//      System.err.println("flushing");
+        dataOut.flush();
+//      System.err.println("flushed");
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/SlaveConnection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/SlaveConnection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/SlaveConnection.java	(revision 6152)
@@ -0,0 +1,356 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.eval;
+
+import java.io.*;
+import java.net.*;
+import java.util.LinkedList;
+import ec.*;
+import java.util.*;
+
+/**
+ * SlaveConnection.java
+ *
+
+ This class contains certain information associated with a slave: its name, connection socket,
+ input and output streams, and the job queue.  Additionally, the class sets up an auxillary thread
+ which reads and writes to the streams to talk to the slave in the background.  This thread uses
+ the SlaveMonitor as its synchronization point (it sleeps with wait() and wakes up when notified()
+ to do some work).
+ 
+ <P>Generally SlaveConnection is only seen by communicates only with SlaveMonitor.
+
+ * @author Liviu Panait, Keith Sullivan, and Sean Luke
+ * @version 2.0 
+ */
+
+class SlaveConnection 
+    {
+    /** Name of the slave process */
+    String slaveName;
+        
+    /**  Socket for communication with the slave process */
+    Socket evalSocket;
+        
+    /**  Used to transmit data to the slave. */
+    DataOutputStream dataOut;
+        
+    /**  Used to read results and randoms state from slave. */
+    public DataInputStream dataIn;
+        
+    // a pointer to the evolution state
+    EvolutionState state;
+
+    // a pointer to the monitor
+    SlaveMonitor slaveMonitor;
+
+    // a pointer to the worker thread that is working for this slave
+    Thread reader;
+    Thread writer;
+
+    // given that we expect the slave to return the evaluated individuals in the exact same order,
+    // the jobs need to be represented as a queue.
+    private LinkedList jobs = new LinkedList();
+
+    /**
+       The constructor also creates the queue storing the jobs that the slave
+       has been asked to evaluate.  It also creates and launches the worker
+       thread that is communicating with the remote slave to read back the results
+       of the evaluations.
+    */
+    public SlaveConnection( EvolutionState state,
+        String slaveName,
+        Socket evalSocket,
+        DataOutputStream dataOut,
+        DataInputStream dataIn,
+        SlaveMonitor slaveMonitor )
+        {
+        this.slaveName = slaveName;
+        this.evalSocket = evalSocket;
+        this.dataOut = dataOut;
+        this.dataIn = dataIn;
+        this.state = state;
+        this.slaveMonitor = slaveMonitor;
+        buildThreads();
+        showDebugInfo = slaveMonitor.showDebugInfo;
+        }
+        
+    /**
+       This method is called whenever there are any communication problems with the slave
+       (indicating possibly that the slave might have crashed).  In this case, the jobs will
+       be rescheduled for evaluation on other slaves.
+    */
+    boolean shuttingDown;
+    Object shutDownLock = new int[0];  // serializable and lockable
+    protected void shutdown( final EvolutionState state )
+        {
+        // prevent me from hitting this multiple times
+        synchronized(shutDownLock) { if (shuttingDown) return; else shuttingDown = true; }
+        
+        // don't want to miss any of these so we'll wrap them individually
+        try { dataOut.writeByte(Slave.V_SHUTDOWN); } catch (Exception e) { }  // exception, not IOException, because JZLib throws some array exceptions
+        try { dataOut.flush(); } catch (Exception e) { }
+        try { dataOut.close(); } catch (Exception e) { }
+        try { dataIn.close(); } catch (Exception e) { }
+        try { evalSocket.close(); } catch (IOException e) { }
+
+        state.output.systemMessage( SlaveConnection.this.toString() + " Slave is shutting down...." );
+        slaveMonitor.unregisterSlave(this);  // unregister me BEFORE I reschedule my jobs
+        rescheduleJobs(state);
+        synchronized(jobs) 
+            {
+            // notify my threads now that I've closed stuff in case they're still waiting
+            slaveMonitor.notifyMonitor(jobs);
+            reader.interrupt();  // not important right now but...
+            writer.interrupt();  // very important that we be INSIDE the jobs synchronization here so the writer doesn't try to wait on the monitor again.
+            }
+        state.output.systemMessage( SlaveConnection.this.toString() + " Slave exits...." );
+        }
+
+    public String toString() { return "Slave(" + slaveName + ")"; }
+
+    boolean showDebugInfo;
+        
+    final void debug(String s)
+        {
+        if (showDebugInfo) { System.err.println(Thread.currentThread().getName() + "->" + s); }
+        }
+    
+    /**
+       Returns the number of jobs that a slave is in charge of.
+    */
+    public int numJobs()
+        {
+        synchronized(jobs) { return jobs.size(); }
+        }
+    
+    // constructs the worker thread for the slave and starts it
+    void buildThreads()
+        {
+        reader = new Thread()
+            {
+            public void run()
+                {
+                while( readLoop()); 
+                }
+            };
+        writer = new Thread()
+            {
+            public void run()
+                {
+                while( writeLoop()); 
+                }
+            };
+        writer.start();
+        reader.start();
+        }
+    
+    
+    // returns the oldest unsent job, or null if there is no unsent job.
+    // marks the job as sent so we don't try to grab it next time
+    // NOT SYNCHRONIZED -- YOU MUST SYNCHRONIZE ON jobs!
+    Job oldestUnsentJob()
+        {
+        // jobs are loaded into the queue from the back and go to the front.
+        // so the oldest jobs are in the front and we should search starting
+        // at the front.  List iterators go from front to back, so we can iterate
+        // starting with the oldest.
+        
+        // This all could have been O(1) if we had used two queues, but we're being
+        // intentionally lazy to keep this from getting to complex.
+        Iterator i = jobs.iterator();
+        while(i.hasNext())
+            {
+            Job job = (Job)(i.next());
+            if (!job.sent) { job.sent = true; return job; }
+            }
+        return null;
+        }
+        
+    
+    boolean writeLoop()
+        {
+        Job job = null;
+        
+        try
+            {
+            synchronized(jobs)
+                {
+                // check for an unsent job
+                if ((job = oldestUnsentJob()) == null)  // automatically marks as sent
+                    {
+                    // failed -- wait and drop out of the loop and come in again
+                    debug("" + Thread.currentThread().getName() + "Waiting for a job to send" );
+                    slaveMonitor.waitOnMonitor(jobs); 
+                    }
+                }
+            if (job != null)  // we got a job inside our synchronized wait
+                {
+                // send the job
+                debug("" + Thread.currentThread().getName() + "Sending Job");
+                if( job.type == Slave.V_EVALUATESIMPLE )
+                    {
+                    // Tell the server we're evaluating a SimpleProblemForm
+                    dataOut.writeByte(Slave.V_EVALUATESIMPLE);
+                    }
+                else
+                    {
+                    // Tell the server we're evaluating a GroupedProblemForm
+                    dataOut.writeByte(Slave.V_EVALUATEGROUPED);
+                                        
+                    // Tell the server whether to count victories only or not.
+                    dataOut.writeBoolean(job.countVictoriesOnly);
+                    }
+                                
+                // transmit number of individuals 
+                dataOut.writeInt(job.inds.length); 
+                            
+                // Transmit the subpopulations to the slave 
+                for(int x=0;x<job.subPops.length;x++)
+                    dataOut.writeInt(job.subPops[x]);
+                            
+                debug("Starting to transmit individuals"); 
+                            
+                // Transmit the individuals to the server for evaluation...
+                for(int i=0;i<job.inds.length;i++)
+                    {
+                    job.inds[i].writeIndividual(state, dataOut);
+                    dataOut.writeBoolean(job.updateFitness[i]);
+                    }
+                dataOut.flush();
+                }
+            }
+        catch (Exception e)  { shutdown(state); return false; }
+        return true;
+        }
+        
+        
+        
+        
+        
+    boolean readLoop()
+        {
+        Job job = null;
+        
+        try
+            {
+            // block on an incoming job
+            byte val = dataIn.readByte();
+            debug(SlaveConnection.this.toString() + " Incoming Job");
+            
+            // okay, we've got a job.  Grab the earliest job, that's what's coming in
+            
+            synchronized(jobs) 
+                {
+                job = (Job)(jobs.getFirst());
+                }
+            debug("Got job: " + job);
+            
+            
+            ///// NEXT STEP: COPY THE INDIVIDUALS FORWARD INTO NEWINDS.
+            ///// WE DO THIS SO WE CAN LOAD THE INDIVIDUALS BACK INTO NEWINDS
+            ///// AND THEN COPY THEM BACK INTO THE ORIGINAL INDS, BECAUSE ECJ
+            ///// DOESN'T HAVE A COPY(INDIVIDUAL,INTO_INDIVIDUAL) FUNCTION
+            
+            job.copyIndividualsForward();
+
+            // now start reading.  Remember that we've already got a byte.
+            
+            for(int i = 0; i < job.newinds.length; i++)
+                {
+                debug(SlaveConnection.this.toString() + " Individual# " + i);
+                debug(SlaveConnection.this.toString() + " Reading Byte" );
+                if (i > 0) val = dataIn.readByte();  // otherwise we've got it already
+                debug(SlaveConnection.this.toString() + " Reading Individual" );
+                if (val == Slave.V_INDIVIDUAL)
+                    {
+                    job.newinds[i].readIndividual(state, dataIn);
+                    }
+                else if (val == Slave.V_FITNESS)
+                    {
+                    job.newinds[i].evaluated = dataIn.readBoolean();
+                    job.newinds[i].fitness.readFitness(state,dataIn);
+                    }
+                else if (val == Slave.V_NOTHING)
+                    {
+                    // do nothing
+                    }
+                debug( SlaveConnection.this.toString() + " Read Individual" );
+                }
+
+
+            ///// NEXT STEP: COPY THE NEWLY-READ INDIVIDUALS BACK INTO THE ORIGINAL
+            ///// INDIVIDUALS.  THIS IS QUITE A HACK, IF YOU READ JOB.JAVA
+
+            // Now we have all the individuals in so we're good.  Copy them back into the original individuals
+            job.copyIndividualsBack(state);
+
+
+            ///// LAST STEP: LET OTHERS KNOW WE'RE DONE AND AVAILABLE FOR ANOTHER JOB
+
+            // we're all done!  Yank the job from the queue so others think we're available
+            synchronized(jobs)
+                {
+                jobs.removeFirst();
+                }
+        
+            // And let the slave monitor we just finished a job
+            slaveMonitor.notifySlaveAvailability( SlaveConnection.this, job, state );
+
+            }
+        catch (IOException e)
+            {
+            shutdown(state);  // will redistribute jobs
+            return false;
+            }
+
+        return true;
+        }
+
+    
+
+
+    /**
+       Adds a new jobs to the queue.  This implies that the slave will be in charge of executing
+       this particular job.
+    */
+    public void scheduleJob( final Job job )
+        {
+        synchronized(jobs)
+            {
+            if (job.sent) // just in case
+                state.output.fatal("Tried to reschedule an existing job");
+            jobs.addLast(job);
+            slaveMonitor.notifyMonitor(jobs);
+            }
+        }
+
+    /**
+       Reschedules the jobs in this job queue to other slaves in the system.  It assumes that the slave associated
+       with this queue has already been removed from the available slaves, such that it is not assigned its own jobs.
+    */
+    // only called when we're shutting down, so we're not waiting for any notification.
+    void rescheduleJobs( final EvolutionState state )
+        {
+        while( true )
+            {
+            Job job = null;
+            synchronized(jobs)
+                {
+                if( jobs.isEmpty() ) { return; }
+                job = (Job)(jobs.removeFirst());
+                }
+            debug(Thread.currentThread().getName() + " Waiting for a slave to reschedule the evaluation.");
+            job.sent = false;  // reuse
+            slaveMonitor.scheduleJobForEvaluation(state,job);
+            debug(Thread.currentThread().getName() + " Got a slave to reschedule the evaluation.");
+            }
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/SlaveMonitor.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/SlaveMonitor.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/SlaveMonitor.java	(revision 6152)
@@ -0,0 +1,448 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.eval;
+
+import ec.*;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import ec.util.*;
+import ec.steadystate.SteadyStateEvolutionState;
+import ec.steadystate.QueueIndividual;
+
+/**
+ * SlaveMonitor.java
+ *
+
+ <P>The SlaveMonitor manages slave connections to each remote slave, and provides synchronization facilities
+ for the slave connections and for various other objects waiting to be notified when new slaves are
+ available, space is available in a slave's job queue, an individual has been completed, etc.
+
+ <p>The monitor provides functions to create and delete slaves (registerSlave(), unregisterSlave()), 
+ schedule a job for evaluation (scheduleJobForEvaluation(...)), block until all jobs have completed
+ (waitForAllSlavesToFinishEvaluating(...)), test if any individual in a job has been finished
+ (evaluatedIndividualAvailable()),  and block until an individual in a job is available and returned
+ (waitForindividual()).
+ 
+ <p>Generally speaking, the SlaveMonitor owns the SlaveConnections -- no one else
+ should speak to them.  Also generally speaking, only MasterProblems create and speak to the SlaveMonitor.
+  
+ * @author Sean Luke, Liviu Panait, and Keith Sullivan
+ * @version 1.0 
+ */
+
+public class SlaveMonitor
+    {
+    public static final String P_EVALMASTERPORT = "eval.master.port";
+    public static final String P_EVALCOMPRESSION = "eval.compression";
+    public static final String P_MAXIMUMNUMBEROFCONCURRENTJOBSPERSLAVE = "eval.masterproblem.max-jobs-per-slave";
+    public static final int SEED_INCREMENT = 7919; // a large value (prime for fun) bigger than expected number of threads per slave
+
+    public EvolutionState state;
+    
+    /**
+     *  The socket where slaves connect.
+     */
+    public ServerSocket servSock;
+        
+    /**
+     * Indicates whether compression is used over the socket IO streams.
+     */
+    public boolean useCompression;
+
+    boolean shutdownInProgress = false;
+    Object[] shutdownInProgressLock = new Object[0];  // arrays are serializable
+    final boolean isShutdownInProgress() { synchronized (shutdownInProgressLock) { return shutdownInProgress; } }
+    final void setShutdownInProgress(boolean val) { synchronized (shutdownInProgressLock) { shutdownInProgress = val; } }
+    
+    int randomSeed;
+    Thread thread;
+
+    public boolean waitOnMonitor(Object monitor)
+        {
+        try
+            {
+            monitor.wait();
+            }
+        catch (InterruptedException e) { return false; }
+        return true;
+        }
+
+    public void notifyMonitor(Object monitor)
+        {
+        monitor.notifyAll();
+        }
+
+    // the slaves (not really a queue)
+    private LinkedList allSlaves = new LinkedList();
+
+    // the available slaves
+    private LinkedList availableSlaves = new LinkedList();
+
+    // the maximum number of jobs per slave
+    int maxJobsPerSlave;
+
+    // whether the system should display information that is useful for debugging 
+    boolean showDebugInfo;
+    
+    final void debug(String s)
+        {
+        if (showDebugInfo) { System.err.println(Thread.currentThread().getName() + "->" + s); }
+        }
+    
+    /**
+       Simple constructor that initializes the data structures for keeping track of the state of each slave.
+       The constructor receives two parameters: a boolean flag indicating whether the system should display
+       information that is useful for debugging, and the maximum load per slave (the maximum number of jobs
+       that a slave can be entrusted with at each time).
+    */
+    public SlaveMonitor( final EvolutionState state, boolean showDebugInfo )
+        {
+        this.showDebugInfo = showDebugInfo;
+        this.state = state;
+                
+        int port = state.parameters.getInt(
+            new Parameter( P_EVALMASTERPORT ),null);
+                
+        maxJobsPerSlave = state.parameters.getInt(
+            new Parameter( P_MAXIMUMNUMBEROFCONCURRENTJOBSPERSLAVE ),null);
+
+        useCompression = state.parameters.getBoolean(new Parameter(P_EVALCOMPRESSION),null,false);
+                
+        try
+            {
+            servSock = new ServerSocket(port);
+            }
+        catch( IOException e )
+            {
+            state.output.fatal("Unable to bind to port " + port + ": " + e);
+            }
+                
+        randomSeed = (int)(System.currentTimeMillis());
+
+        // spawn the thread
+        thread = new Thread(new Runnable()
+            {
+            public void run()
+                {
+                Thread.currentThread().setName("SlaveMonitor::    ");
+                Socket slaveSock;
+                        
+                while (!isShutdownInProgress())
+                    {
+                    slaveSock = null;
+                    while( slaveSock==null && !isShutdownInProgress() )
+                        {
+                        try
+                            {
+                            slaveSock = servSock.accept();
+                            }
+                        catch( IOException e ) { slaveSock = null; }
+                        }
+
+                    debug(Thread.currentThread().getName() + " Slave attempts to connect." );
+
+                    if( isShutdownInProgress() ) break;
+
+                    try
+                        {
+                        DataInputStream dataIn = null;
+                        DataOutputStream dataOut = null;
+                        InputStream tmpIn = slaveSock.getInputStream();
+                        OutputStream tmpOut = slaveSock.getOutputStream();
+                        if (useCompression)
+                            {
+                            /*
+                              state.output.fatal("JDK 1.5 has broken compression.  For now, you must set eval.compression=false");
+                              tmpIn = new CompressingInputStream(tmpIn);
+                              tmpOut = new CompressingOutputStream(tmpOut);
+                            */
+                            tmpIn = Output.makeCompressingInputStream(tmpIn);
+                            tmpOut = Output.makeCompressingOutputStream(tmpOut);
+                            if (tmpIn == null || tmpOut == null)
+                                Output.initialError("You do not appear to have JZLib installed on your system, and so must set eval.compression=false. " +
+                                    "To get JZLib, download from the ECJ website or from http://www.jcraft.com/jzlib/");
+                            }
+                                                                                                        
+                        dataIn = new DataInputStream(tmpIn);
+                        dataOut = new DataOutputStream(tmpOut);
+                        String slaveName = dataIn.readUTF();
+
+                        dataOut.writeInt(randomSeed);
+                        randomSeed+=SEED_INCREMENT;
+                        
+                        // Write random state for eval thread to slave
+                        dataOut.flush();
+
+                        registerSlave(state, slaveName, slaveSock, dataOut, dataIn);
+                        state.output.systemMessage( "Slave " + slaveName + " connected successfully." );
+                        }
+                    catch (IOException e) {  }
+                    }
+
+                debug( Thread.currentThread().getName() + " The monitor is shutting down." );
+                }
+            });
+        thread.start();
+        }
+
+    /**
+       Registers a new slave with the monitor.  Upon registration, a slave is marked as available for jobs.
+    */
+    public void registerSlave( EvolutionState state, String name, Socket socket, DataOutputStream out, DataInputStream in)
+        {
+        SlaveConnection newSlave = new SlaveConnection( state, name, socket, out, in, this );
+        
+        synchronized(availableSlaves)
+            {
+            availableSlaves.addLast(newSlave);
+            notifyMonitor(availableSlaves);
+            }
+        synchronized(allSlaves)
+            {
+            allSlaves.addLast(newSlave);
+            notifyMonitor(allSlaves);
+            }
+        }
+
+    /**
+       Unregisters a dead slave from the monitor.
+    */
+    public void unregisterSlave( SlaveConnection slave )
+        {
+        synchronized(allSlaves)
+            {
+            allSlaves.remove(slave);
+            notifyMonitor(allSlaves);
+            }
+        synchronized(availableSlaves)
+            {
+            availableSlaves.remove(slave);
+            notifyMonitor(availableSlaves);
+            }
+        }
+
+    /**
+       Shuts down the slave monitor (also shuts down all slaves).
+    */
+    public void shutdown()
+        {
+        // kill the socket socket and bring down the thread
+        setShutdownInProgress(true);
+        try
+            {
+            servSock.close();
+            }
+        catch (IOException e)
+            {
+            }
+        thread.interrupt();
+        try { thread.join(); }
+        catch (InterruptedException e) { }
+        
+        // gather all the slaves
+        
+        synchronized(allSlaves)
+            {
+            while( !allSlaves.isEmpty() )
+                {
+                ((SlaveConnection)(allSlaves.removeFirst())).shutdown(state);
+                }
+            notifyMonitor(allSlaves);
+            }
+        }
+
+    /**
+       Schedules a job for execution on one of the available slaves.  The monitor waits until at least one
+       slave is available to perform the job.
+    */
+    public void scheduleJobForEvaluation( final EvolutionState state, Job job )
+        {
+        if (isShutdownInProgress()) return;  // no more jobs allowed.  This line rejects requests from slaveConnections when THEY'RE shutting down.
+        
+        SlaveConnection result = null;
+        synchronized(availableSlaves)
+            {
+            while( true)
+                {
+                if (!availableSlaves.isEmpty()) 
+                    {
+                    result = (SlaveConnection)(availableSlaves.removeFirst());
+                    break;
+                    }
+                debug("Waiting for an available slave." );
+                waitOnMonitor(availableSlaves);
+                }
+            notifyMonitor(availableSlaves);
+            }       
+        debug( "Got a slave available for work." );
+
+        result.scheduleJob(job);
+
+        if( result.numJobs() < maxJobsPerSlave )
+            {
+            synchronized(availableSlaves) 
+                {
+                if( !availableSlaves.contains(result)) availableSlaves.addLast(result);  // so we're round-robin
+                notifyMonitor(availableSlaves);
+                }
+            }
+        }
+
+    /**
+       This method returns only when all slaves have finished the jobs that they were assigned.  While this method waits,
+       new jobs can be assigned to the slaves.  This method is usually invoked from MasterProblem.finishEvaluating.  You
+       should not abuse using this method: if there are two evaluation threads, where one of them waits until all jobs are
+       finished, while the second evaluation thread keeps posting jobs to the slaves, the first thread might have to wait
+       until the second thread has had all its jobs finished.
+    */
+    public void waitForAllSlavesToFinishEvaluating( final EvolutionState state )
+        {
+        synchronized(allSlaves)
+            {
+            Iterator iter = allSlaves.iterator();
+            while( iter.hasNext() )
+                {
+                SlaveConnection slaveConnection = (SlaveConnection)(iter.next());
+                try { slaveConnection.dataOut.flush(); } catch (java.io.IOException e) {} // we'll catch this error later....
+                }
+            notifyMonitor(allSlaves);
+            }
+            
+        boolean shouldCycle = true;
+        synchronized(allSlaves)
+            {
+            while( shouldCycle )
+                {
+                shouldCycle = false;
+                Iterator iter = allSlaves.iterator();
+                while( iter.hasNext() )
+                    {
+                    SlaveConnection slaveConnection = (SlaveConnection)(iter.next());
+                    int jobs = slaveConnection.numJobs();
+                    if( jobs != 0 )
+                        {
+                        debug("Slave " + slaveConnection + " has " + jobs + " more jobs to finish." );
+                        shouldCycle = true;
+                        break;
+                        }                               
+                    }
+                if( shouldCycle )
+                    {
+                    debug("Waiting for slaves to finish their jobs." );
+                    waitOnMonitor(allSlaves);
+                    debug("At least one job has been finished." );
+                    }
+                }
+            notifyMonitor(allSlaves);
+            }
+        debug("All slaves have finished their jobs." );
+        }
+
+    /**
+       Notifies the monitor that the particular slave has finished performing a job, and it (probably) is
+       available for other jobs.
+    */
+    void notifySlaveAvailability( SlaveConnection slave, final Job job, EvolutionState state )
+        {
+        // first announce that a slave in allSlaves has finished, so people blocked on waitForAllSlavesToFinishEvaluating
+        // can wake up and realize it.
+        
+        synchronized(allSlaves)
+            {
+            notifyMonitor(allSlaves);
+            }
+
+        // now announce that we've got a new available slave if someone wants it
+        
+        if( slave.numJobs() < maxJobsPerSlave )
+            {
+            synchronized(availableSlaves)
+                { 
+                if( !availableSlaves.contains(slave)) availableSlaves.addLast(slave);
+                notifyMonitor(availableSlaves);
+                }
+            }
+
+        debug("Notify the monitor that the slave is available." );
+
+        // now announce that we've got a new completed individual if someone is waiting for it
+
+        if( state instanceof ec.steadystate.SteadyStateEvolutionState )
+            {
+            // Perhaps we should the individuals by fitness first, so the fitter ones show up later
+            // and don't get immediately wiped out by less fit ones.  Or should it be the other way
+            // around?  We might revisit that in the future.
+            
+            // At any rate, add ALL the individuals that came back to the evaluatedIndividuals LinkedList
+            synchronized(evaluatedIndividuals)
+                {
+                for(int x=0; x<job.inds.length;x++)
+                    evaluatedIndividuals.addLast( new QueueIndividual(job.inds[x], job.subPops[x]) );
+                notifyMonitor(evaluatedIndividuals);
+                }
+            }
+        }
+
+    LinkedList evaluatedIndividuals =  new LinkedList();
+
+    public boolean evaluatedIndividualAvailable()
+        {
+        synchronized(evaluatedIndividuals)
+            {
+            try { evaluatedIndividuals.getFirst(); return true; }
+            catch (NoSuchElementException e) { return false; }
+            }
+        }
+
+
+    /** Blocks until an individual comes available */
+    public QueueIndividual waitForIndividual()
+        {
+        while(true)
+            {
+            synchronized(evaluatedIndividuals)
+                {
+                if (evaluatedIndividualAvailable())
+                    return (QueueIndividual)(evaluatedIndividuals.removeFirst());
+
+                debug("Waiting for individual to be evaluated." );
+                waitOnMonitor(evaluatedIndividuals);  // lets go of evaluatedIndividuals loc
+                debug("At least one individual has been finished." );
+                }
+            }
+        }
+
+    /** Returns the number of available slave (not busy) */ 
+    int numAvailableSlaves()
+        {
+        int i = 0;
+        synchronized(availableSlaves) { i = availableSlaves.size(); }
+        return i;
+        }
+
+    /**
+     * @param s checkpoint file output stream
+     * @throws IOException
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException
+        {
+        state.output.fatal("Not implemented yet: SlaveMonitor.writeObject");
+        }
+        
+    /**
+     * @param s checkpoint file input stream.
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+        {
+        state.output.fatal("Not implemented yet: SlaveMonitor.readObject");
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/master.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/master.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/master.params	(revision 6152)
@@ -0,0 +1,65 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# Note that the slave shares this file with the master, because they
+# have a number of parameters held in common.  See slave.params.  
+# You don't have to do this, but it's a convenient way to keep the
+# master and slave consistent with one another.
+
+
+
+
+# When eval.masterproblem is turned on, the system assumes
+# use of the master/slave evaluator.
+eval.masterproblem = ec.eval.MasterProblem
+
+
+# Turning this on will provide synchronization
+# information for debugging the master/slave evaluator
+eval.masterproblem.debug-info = false
+
+
+# How large should each slave's job queue be?  ECJ will
+# keep slaves' TCP/IP streams filled with jobs even if the
+# slaves haven't processed them yet, which has a significant
+# effect on network performance.  Increasing this number is
+# likely to be more efficient.  Note that once a job is
+# committed to a slave, a brand new slave coming on-line cannot
+# take it -- it'll have to sit and wait, which isn't particularly
+# efficient.  At the very least, it's probably helpful to have 2
+# or 3 jobs in the queue.
+eval.masterproblem.max-jobs-per-slave = 3
+
+
+# How large should our job be?  If you're doing ordinary
+# non-coevolutionary evolution, you can specify how many individuals
+# should be placed into a job (maximum) and sent to the slave
+# to be evaluated at one time, using the below parameter.
+# If your individuals are small in size, this can significantly
+# improve the network bandwidth.  If the individuals are large
+# in size, it'll have no real effect.  Furthermore, if your
+# slave is running in 'evolve' mode, this parameter will determine
+# the maximum (and typical) size of the "population" the slave is
+# evolving.  This works for both steady-state and generational evolution,
+# but if you're doing coevolution, the job size is ignored -- instead
+# the job will consist of the individuals to be coevolved together.
+eval.masterproblem.job-size = 100
+
+
+# This compresses the streams between the master and slaves.
+# Compression requires the zlib library.
+# See the ECJ main webpage or http://www.jcraft.com/jzlib/
+
+eval.compression=true
+
+
+# This defines the socket port that the master listens in
+# for incomoing Slaves to connect.
+eval.master.port = 15000
+
+
+# You do NOT want to set   eval.i-am-slave=true   in this file,
+# because then the master will think it's a slave.  Instead, set
+# that parameter in the slave.params file.
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/eval/slave.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/eval/slave.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/eval/slave.params	(revision 6152)
@@ -0,0 +1,60 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# This file is used only by the slaves, not the master.  The shared
+# parameters between the master and slaves should instead be defined
+# in the master.params file.
+
+parent.0 = master.params
+
+
+#### This should no longer be set -- it's set automatically by Slave.java
+#### When you run as a slave
+# Lets the slaves know that they're slaves.
+#eval.i-am-slave = true
+#### End deprecation
+
+
+# Specifies the IP address of the master, for the Slaves
+# to connect.  Slaves need to be told this in their
+# parameter files.  The example below sets it to localhost,
+# which is probably not what you want.
+eval.master.host = 127.0.0.1
+
+
+# Specifies a slave's name for debugging purposes.  If this is not
+# set (the default), then the system will use an approximately unique
+# name constructed from the IP address and startup time of the
+# slave.  Names don't have to be unique -- it's only for debugging.
+eval.slave-name = my-slave-name
+
+
+# Specifies the mode the slave runs in.  If false, the slave runs in
+# 'regular' mode where it just evaluates the individuals and returns
+# either the fitnesses or the whole individuals.  If true, the slave
+# runs in 'evolve' mode, where it evaluates the individuals, but then
+# if there's extra time (see next parameter), it will treat the individuals
+# as its own mini-population and do some evolution on that population
+# according to the evolution parameters you provided the slave.  When
+# the time is up, it then returns the entire individuals.
+#
+# You want to make sure that if you set this to true, then the mini-population
+# on the slave is sufficiently large to support its own evolution.
+# The population size is specified by eval.master-problem.job-size
+# on the Master.
+eval.run-evolve = true
+
+
+# Specifies the length of (wall clock) time, in milliseconds, that the
+# slave should do "evolution" on its individuals if eval.run-evolve = true
+eval.runtime = 6000
+
+
+# Change this to force whole Individuals to be returned by the
+# Slave rather than just returning Fitnesses, plus whether or not the
+# Individual was evaluated.  Returning a whole Individual is expensive
+# over the network and should only be done if, for some reason, your
+# Problem class modified the Individuals as it evaluates them.
+eval.return-inds = false
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/evolve/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/evolve/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/evolve/README	(revision 6152)
@@ -0,0 +1,13 @@
+This package contains utility operations which can be plugged into most
+evolutionary loops, but are neither evaluation, breeding, nor exchange
+procedures.
+
+At present there is exactly one class here:
+
+
+ec.evolve.RandomRestarts	[UNTESTED]
+
+This class is a Statistics subclass and is attached into the Statistics chain.
+The class resets the evolutionary procedure every once in a while, by
+calling Population.populate(...) (with an empty loadInds file), which causes
+the Population to create all new indivdiuals.
Index: branches/OKBJavaConnector/ECJClient/src/ec/evolve/RandomRestarts.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/evolve/RandomRestarts.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/evolve/RandomRestarts.java	(revision 6152)
@@ -0,0 +1,124 @@
+package ec.evolve;
+
+import ec.*;
+import ec.steadystate.*;
+import ec.util.*;
+import java.io.*;
+
+/**
+ * A special Statistics class which performs random restarts on the population,
+ * effectively reininitializing the population and starting over again.
+ * RandomRestarts has two ways of determining when to perform a restart.  If
+ * the restart type is "fixed", then the restart will occur precisely when
+ * the generation is a multiple of restart-upper-bound, minus one.  (That's
+ * hardly random, of course).  If the restart type is "random", then at the
+ * beginning of the run, and after every restart, a new restart is chosen 
+ * randomly from one to restart-upper-bound.
+ *
+ * <p>This class is compatible with populations which load from files -- it
+ * temporarily disables the load-from-file feature when telling the population
+ * to populate itself again, forcing the population to do so by creating random
+ * individuals.
+ *
+ * @author James O'Beirne
+  
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>restart-type</tt><br>
+ <font size=-1>random or fixed</font></td>
+ <td valign=top>Either initiates clock at a random value or a fixed one.</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>restart-upper-bound</tt><br>
+ <font size=-1>1 &lt; int &lt; \inf</font></td>
+ <td valign=top>Maximum time clock can initiate with.</td></tr>
+ </table>
+*/
+ 
+public class RandomRestarts extends Statistics implements SteadyStateStatisticsForm
+    {
+    /** Two options available here: "fixed" and "random"; "fixed"
+     *  will initate the restart timer at the value specified for
+     *  <i>restart-upper-bound</i>, "random" will initiate the restart
+     *  timer somewhere below the value specified for 
+     *  <i>restart-upper-bound</i> */
+    public static final String P_RESTART_TYPE = "restart-type";
+
+    /** This is the highest value at which the "ticking" 
+     *  restart clock can initiate at.  */
+    public static final String P_RESTART_UPPERBOUND = "restart-upper-bound";
+
+    public int countdown;              // what we'll use for the "ticking" clock
+    public int upperbound;             // highest possible value on the clock
+   
+    String restartType;    // are we doing random or fixed?
+
+    /** Gets the clock ticking. */
+    public void setup( final EvolutionState state, final Parameter base )
+        {
+        super.setup( state, base );
+
+        restartType = state.parameters.getString(base.push(P_RESTART_TYPE),  null);
+        upperbound = state.parameters.getInt( base.push(P_RESTART_UPPERBOUND), null, 1);
+
+        if( upperbound < 1 )
+            state.output.fatal("Parameter either not found or invalid (<1).", base.push(P_RESTART_UPPERBOUND));
+                        
+        if( !restartType.equals( "random" ) && !restartType.equals( "fixed" ) )
+            state.output.fatal("Parameter must be either 'fixed' or 'random'.", base.push(P_RESTART_TYPE));
+
+        // start counting down
+        this.resetClock( state );
+        }
+
+    /**
+     * Checks the clock; if it's time to restart, we repopulate the population. 
+     * Afterwards, we reset the clock.
+     *
+     * If it's not time yet, the clock goes tick.
+     */
+    public void preEvaluationStatistics( final EvolutionState state )
+        {
+        super.preEvaluationStatistics(state);
+        possiblyRestart(state);
+        }
+
+    public void generationBoundaryStatistics(final EvolutionState state)
+        {
+        super.generationBoundaryStatistics(state);
+        possiblyRestart(state);
+        }
+                
+    void possiblyRestart(EvolutionState state)
+        {
+                
+        Subpopulation currentSubp;
+        File tempFile;
+        // time to restart!
+        if( countdown == 0 )
+            {
+            System.out.println( "Restarting the population!" );
+            // for each subpopulation
+            for( int subp = 0; subp < state.population.subpops.length; subp++ )
+                {
+                currentSubp = state.population.subpops[subp];
+                tempFile = currentSubp.loadInds;
+                // disable loadInds so we generate candidates randomly
+                currentSubp.loadInds = null;
+                currentSubp.populate( state, 0 );
+                currentSubp.loadInds = tempFile;
+                }
+            this.resetClock( state );
+            }
+        else
+            countdown--;
+        }
+
+    void resetClock( final EvolutionState state )
+        {
+        if(restartType.equals( "fixed" ))
+            countdown = upperbound;
+        else
+            // might need to fix random index to support multithreading
+            countdown = state.random[0].nextInt( upperbound + 1 );
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/README	(revision 6152)
@@ -0,0 +1,41 @@
+[If you're looking for a simple example of doing an island
+model, don't look here -- look instead in 3-Island.]
+
+This model is a special example of how to create a server
+that's not actually a client program -- the process
+SOLELY exists to be a server.  Why would you want to do this?
+Well, we were running on a beowulf cluster maintained by a 
+company that wouldn't allow us to know beforehand exactly
+what the IP address was of *any* node.  (They were using a
+queueing system, argh).  We got around this by putting our
+clients out on the cluster, but having a dedicated machine
+with a known IP address as the server.  The company permitted
+this because the server doesn't have almost any network traffic
+going to it -- it's just for synchronization.
+
+So in this example we'll have two islands, Minoa and Crete,
+using minoa.params and crete.params, plus a separate server 
+(in server.params).  You need to launch the server differently
+than you'd normally launch an ECJ process.  What you do here
+is launch the server as:
+
+java ec.exchange.IslandExchange -file server.params
+
+
+Then you launch your islands:
+
+java ec.Evolve -file crete.params
+
+java ec.Evolve -file minoa.params
+
+
+If you're running crete and minoa on separate machines from
+the server, you'll need to modify the parameter to tell them
+where the server is:
+
+java ec.Evolve -file crete.params \
+    -p exch.server-addr=address.of.server.com
+
+java ec.Evolve -file minoa.params \
+    -p exch.server-addr=address.of.server.com
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/client.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/client.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/client.params	(revision 6152)
@@ -0,0 +1,13 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../..//app/ant/ant.params
+
+exch = ec.exchange.IslandExchange
+exch.select = ec.select.TournamentSelection
+exch.compressed = true
+# This assumes all the islands are on the same machine.
+# You probably want to change this.
+exch.server-addr = localhost
+exch.server-port = 8999
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/crete.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/crete.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/crete.params	(revision 6152)
@@ -0,0 +1,16 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = Crete
+stat.file = $crete.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1001
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9001
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/minoa.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/minoa.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/minoa.params	(revision 6152)
@@ -0,0 +1,16 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = Minoa
+stat.file = $minoa.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1000
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9000
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/server.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/server.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/2-Island-Server/server.params	(revision 6152)
@@ -0,0 +1,34 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.i-am-server = true
+
+#exch.sync = true
+
+### These parameters are only used if the per-island
+### versions aren't specified.
+#exch.mod = 4
+#exch.start = 1
+#exch.size = 4
+#exch.mailbox-capacity = 20
+
+exch.num-islands = 2
+
+exch.island.0.id = Minoa
+exch.island.0.num-mig = 1
+exch.island.0.mig.0 = Crete
+exch.island.0.size = 4
+exch.island.0.mod = 6
+exch.island.0.start = 3
+exch.island.0.mailbox-capacity = 20
+
+exch.island.1.id = Crete
+exch.island.1.num-mig = 1
+exch.island.1.mig.0 = Minoa
+exch.island.1.size = 4
+exch.island.1.mod = 6
+exch.island.1.start = 5
+exch.island.1.mailbox-capacity = 20
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/README	(revision 6152)
@@ -0,0 +1,31 @@
+In this model, three islands are created:
+Wallops, Assateague, and Chincoteague.
+Wallops will be the server.
+
+To run this example, launch three processes
+using the wallops.params, assateague.params, or 
+chincoteague.params parameter files respectively.
+If you're running them on the same machines, you can
+simply do:
+
+java ec.Evolve -file wallops.params
+
+java ec.Evolve -file assateague.params
+
+java ec.Evolve -file chincoteague.params
+
+If you're running the processes on different machines,  
+you'll need to modify the server address
+so the machines know where wallops (the server) is located:
+
+java ec.Evolve -file wallops.params 
+
+java ec.Evolve -file assateague.params \
+    -p exch.server-addr=address.of.wallops.com
+
+java ec.Evolve -file chincoteague.params \
+    -p exch.server-addr=address.of.wallops.com
+
+The parameter files have been set up to define different
+socket ports for each client; though this is only necessary
+if they're running on the same computer.
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/assateague.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/assateague.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/assateague.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = AssateagueIsland
+stat.file = $assateague.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1000
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9000
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/chincoteague.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/chincoteague.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/chincoteague.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = ChincoteagueIsland
+stat.file = $chincoteague.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1001
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9001
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/client.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/client.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/client.params	(revision 6152)
@@ -0,0 +1,13 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../app/ant/ant.params
+
+exch = ec.exchange.IslandExchange
+exch.select = ec.select.TournamentSelection
+exch.compressed = true
+# This assumes all the islands are on the same machine.
+# You probably want to change this.
+exch.server-addr = localhost
+exch.server-port = 8999
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/server.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/server.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/server.params	(revision 6152)
@@ -0,0 +1,45 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.i-am-server = true
+
+#exch.sync = true
+
+### These parameters are only used if the per-island
+### versions aren't specified.
+#exch.mod = 4
+#exch.start = 1
+#exch.size = 4
+#exch.mailbox-capacity = 20
+
+exch.num-islands = 3
+
+exch.island.0.id = WallopsIsland
+exch.island.0.num-mig = 2
+exch.island.0.mig.0 = AssateagueIsland
+exch.island.0.mig.1 = ChincoteagueIsland
+exch.island.0.size = 40
+exch.island.0.mod = 6
+exch.island.0.start = 1
+exch.island.0.mailbox-capacity = 200
+
+exch.island.1.id = AssateagueIsland
+exch.island.1.num-mig = 2
+exch.island.1.mig.0 = ChincoteagueIsland
+exch.island.1.mig.1 = WallopsIsland
+exch.island.1.size = 40
+exch.island.1.mod = 6
+exch.island.1.start = 3
+exch.island.1.mailbox-capacity = 200
+
+exch.island.2.id = ChincoteagueIsland
+exch.island.2.num-mig = 2
+exch.island.2.mig.0 = WallopsIsland
+exch.island.2.mig.1 = AssateagueIsland
+exch.island.2.size = 40
+exch.island.2.mod = 6
+exch.island.2.start = 5
+exch.island.2.mailbox-capacity = 200
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/wallops.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/wallops.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/3-Island/wallops.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = server.params
+exch.id = WallopsIsland
+stat.file = $wallops.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1002
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9002
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/README	(revision 6152)
@@ -0,0 +1,57 @@
+Ellis, Gilligans, Coney, Fantasy, Rhode, Survivor, Temptation,
+and Treasure Island.  Survivor Island will be the server.
+
+To run this example, launch eight processes, each with
+the appropriate .params file for that island.  
+
+If you're running them on the same machines, you can
+simply do:
+
+java ec.Evolve -file survivor.params
+
+java ec.Evolve -file ellis.params
+
+java ec.Evolve -file gilligans.params
+
+java ec.Evolve -file coney.params
+
+java ec.Evolve -file fantasy.params
+
+java ec.Evolve -file rhode.params
+
+java ec.Evolve -file temptation.params
+
+java ec.Evolve -file treasure.params
+
+
+If you're running the processes on different machines,  
+you'll need to modify the server address
+so the machines know where Survivor Island (the server) is located:
+
+java ec.Evolve -file survivor.params 
+
+java ec.Evolve -file ellis.params \
+    -p exch.server-addr=address.of.survivor.com
+
+java ec.Evolve -file gilligans.params \
+    -p exch.server-addr=address.of.survivor.com
+
+java ec.Evolve -file coney.params \
+    -p exch.server-addr=address.of.survivor.com
+
+java ec.Evolve -file fantasy.params \
+    -p exch.server-addr=address.of.survivor.com
+
+java ec.Evolve -file rhode.params \
+    -p exch.server-addr=address.of.survivor.com
+
+java ec.Evolve -file temptation.params \
+    -p exch.server-addr=address.of.survivor.com
+
+java ec.Evolve -file treasure.params \
+    -p exch.server-addr=address.of.survivor.com
+
+
+The parameter files have been set up to define different
+socket ports for each client; though this is only necessary
+if they're running on the same computer.
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/client.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/client.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/client.params	(revision 6152)
@@ -0,0 +1,13 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../../app/ant/ant.params
+
+exch = ec.exchange.IslandExchange
+exch.select = ec.select.TournamentSelection
+exch.compressed = true
+# This assumes all the islands are on the same machine.
+# You probably want to change this.
+exch.server-addr = localhost
+exch.server-port = 8999
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/coney.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/coney.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/coney.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = ConeyIsland
+stat.file = $coney.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1000
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9000
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/ellis.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/ellis.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/ellis.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = EllisIsland
+stat.file = $ellis.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1001
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9001
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/fantasy.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/fantasy.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/fantasy.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = FantasyIsland
+stat.file = $fantasy.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1002
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9002
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/gilligans.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/gilligans.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/gilligans.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = GilligansIsland
+stat.file = $gilligans.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1003
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9003
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/rhode.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/rhode.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/rhode.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = RhodeIsland
+stat.file = $rhode.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1004
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9004
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/server.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/server.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/server.params	(revision 6152)
@@ -0,0 +1,99 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.i-am-server = true
+
+#exch.sync = true
+
+### These parameters are only used if the per-island
+### versions aren't specified.
+#exch.mod = 4
+#exch.start = 1
+#exch.size = 4
+#exch.mailbox-capacity = 20
+
+exch.num-islands = 8
+
+exch.island.0.id = SurvivorIsland
+exch.island.0.num-mig = 3
+exch.island.0.mig.0 = GilligansIsland
+exch.island.0.mig.1 = TemptationIsland
+exch.island.0.mig.2 = RhodeIsland
+exch.island.0.size = 4
+exch.island.0.mod = 4
+exch.island.0.start = 1
+exch.island.0.mailbox-capacity = 20
+
+exch.island.1.id = GilligansIsland
+exch.island.1.num-mig = 3
+exch.island.1.mig.0 = SurvivorIsland
+exch.island.1.mig.1 = EllisIsland
+exch.island.1.mig.2 = FantasyIsland
+exch.island.1.size = 4
+exch.island.1.mod = 4
+exch.island.1.start = 2
+exch.island.1.mailbox-capacity = 20
+
+exch.island.2.id = FantasyIsland
+exch.island.2.num-mig = 3
+exch.island.2.mig.0 = GilligansIsland
+exch.island.2.mig.1 = ConeyIsland
+exch.island.2.mig.2 = TemptationIsland
+exch.island.2.size = 4
+exch.island.2.mod = 4
+exch.island.2.start = 3
+exch.island.2.mailbox-capacity = 20
+
+exch.island.3.id = TemptationIsland
+exch.island.3.num-mig = 3
+exch.island.3.mig.0 = TreasureIsland
+exch.island.3.mig.1 = SurvivorIsland
+exch.island.3.mig.2 = FantasyIsland
+exch.island.3.size = 4
+exch.island.3.mod = 4
+exch.island.3.start = 2
+exch.island.3.mailbox-capacity = 20
+
+exch.island.4.id = RhodeIsland
+exch.island.4.num-mig = 3
+exch.island.4.mig.0 = TreasureIsland
+exch.island.4.mig.1 = SurvivorIsland
+exch.island.4.mig.2 = EllisIsland
+exch.island.4.size = 4
+exch.island.4.mod = 4
+exch.island.4.start = 2
+exch.island.4.mailbox-capacity = 20
+
+exch.island.5.id = EllisIsland
+exch.island.5.num-mig = 3
+exch.island.5.mig.0 = GilligansIsland
+exch.island.5.mig.1 = ConeyIsland
+exch.island.5.mig.2 = RhodeIsland
+exch.island.5.size = 4
+exch.island.5.mod = 4
+exch.island.5.start = 3
+exch.island.5.mailbox-capacity = 20
+
+exch.island.6.id = ConeyIsland
+exch.island.6.num-mig = 3
+exch.island.6.mig.0 = EllisIsland
+exch.island.6.mig.1 = TreasureIsland
+exch.island.6.mig.2 = FantasyIsland
+exch.island.6.size = 4
+exch.island.6.mod = 4
+exch.island.6.start = 1
+exch.island.6.mailbox-capacity = 20
+
+exch.island.7.id = TreasureIsland
+exch.island.7.num-mig = 3
+exch.island.7.mig.0 = ConeyIsland
+exch.island.7.mig.1 = TemptationIsland
+exch.island.7.mig.2 = RhodeIsland
+exch.island.7.size = 4
+exch.island.7.mod = 4
+exch.island.7.start = 3
+exch.island.7.mailbox-capacity = 20
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/survivor.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/survivor.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/survivor.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = server.params
+exch.id = SurvivorIsland
+stat.file = $survivor.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1005
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9005
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/temptation.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/temptation.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/temptation.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = TemptationIsland
+stat.file = $temptation.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1006
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9006
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/treasure.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/treasure.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/8-Island/treasure.params	(revision 6152)
@@ -0,0 +1,17 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = client.params
+exch.id = TreasureIsland
+stat.file = $treasure.stat
+
+# We need to give this island its own unique random number seed
+seed.0 = 1007
+
+# We also need to give this island its own unique client port.  Actually
+# if you're running on different machines, then each island can use the 
+# same port.  But since we don't know this ahead of time, it's safer to
+# give 'em different ports
+exch.client-port = 9007
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/InterPopulationExchange.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/InterPopulationExchange.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/InterPopulationExchange.java	(revision 6152)
@@ -0,0 +1,437 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.exchange;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * InterPopulationExchange.java
+ * 
+ * Created Sat Feb 10 13:44:11 EST 2001
+ * By: Liviu Panait
+ */
+
+/**
+ * InterPopulationExchange is an Exchanger which implements a simple exchanger
+ * between subpopulations. IterPopulationExchange uses an arbitrary graph topology
+ * for migrating individuals from subpopulations. The assumption is that all
+ * subpopulations have the same representation and same task to solve, otherwise
+ * the exchange between subpopulations does not make much sense.
+
+ * <p>InterPopulationExchange has a topology which is similar to the one used by
+ * IslandExchange.  Every few generations, a subpopulation will send some number
+ * of individuals to other subpopulations.  Since all subpopulations evolve at
+ * the same generational speed, this is a synchronous procedure (IslandExchange
+ * instead is asynchronous by default, though you can change it to synchronous).
+ 
+ * <p>Individuals are sent from a subpopulation prior to breeding.  They are stored
+ * in a waiting area until after all subpopulations have bred; thereafter they are
+ * added into the new subpopulation.  This means that the subpopulation order doesn't
+ * matter.  Also note that it means that some individuals will be created during breeding,
+ * and immediately killed to make way for the migrants.  A little wasteful, we know,
+ * but it's simpler that way.
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt><i>base</i>.chatty</tt><br>
+ <font size=-1>boolean, default = true</font></td>
+ <td valign=top> Should we be verbose or silent about our exchanges?
+ </td></tr>
+ </table>
+ <p><i>Note:</i> For each subpopulation in your population, there <b>must</b> be 
+ one exch.subpop... declaration set.
+ <table>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.select</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod</font></td>
+ <td valign=top> The selection method used by subpopulation #n for picking 
+ migrants to emigrate to other subpopulations.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.select</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: the selection method used by a given subpopulation for picking 
+ migrants to emigrate to other subpopulations.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.select-to-die</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod (Default is random selection)</font></td>
+ <td valign=top> The selection method used by subpopulation #n for picking 
+ individuals to be replaced by migrants.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.select-to-die</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod (Default is random selection)</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: the selection method used by a given subpopulation for picking 
+ individuals to be replaced by migrants.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.mod</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top> The number of generations that subpopulation #n waits between 
+ sending emigrants.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.mod</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: the number of generations that a given subpopulation waits between 
+ sending emigrants.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.start</tt><br>
+ <font size=-1>int >= 0</font></td>
+ <td valign=top> The generation when subpopulation #n begins sending emigrants.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.start</tt><br>
+ <font size=-1>int >= 0</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: the generation when a given subpopulation begins sending emigrants.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.size</tt><br>
+ <font size=-1>int >= 0</font></td>
+ <td valign=top> The number of emigrants sent at one time by generation #n.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.num-dest</tt><br>
+ <font size=-1>int >= 0</font></td>
+ <td valign=top> The number of destination subpopulations for this subpopulation.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.dest.<i>m</i></tt><br>
+ <font size=-1>int >= 0</font></td>
+ <td valign=top> Subpopulation #n's destination #m is this subpopulation.
+ </td></tr>
+ </table>
+ 
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><tt><i>base</i>.subpop.<i>n</i>.select</tt><br>
+ <td>selection method for subpopulation #n's migrants</td></tr>
+ </table>
+
+ *  
+ * @author Liviu Panait & Sean Luke
+ * @version 2.0 
+ */
+
+
+public class InterPopulationExchange extends Exchanger
+    {
+    // static inner classes don't need SerialVersionUIDs
+    static class IPEInformation implements Serializable
+        {
+        // the selection method
+        SelectionMethod immigrantsSelectionMethod;
+
+        // the selection method
+        SelectionMethod indsToDieSelectionMethod;
+
+        // the number of destination subpopulations
+        int numDest;
+
+        // the subpopulations where individuals need to be sent
+        int[] destinations;
+
+        // the modulo
+        int modulo;
+
+        // the start (offset)
+        int offset;
+
+        // the size
+        int size;
+        }
+
+
+    /** The subpopulation delimiter */
+    public static final String P_SUBPOP = "subpop";
+
+    /** The parameter for the modulo (how many generations should pass between consecutive sendings of individuals */
+    public static final String P_MODULO = "mod";
+
+    /** The number of emigrants to be sent */
+    public static final String P_SIZE = "size";
+
+    /** How many generations to pass at the beginning of the evolution before the first
+        emigration from the current subpopulation */
+    public static final String P_OFFSET = "start";
+
+    /** The number of destinations from current island */
+    public static final String P_DEST_FOR_SUBPOP = "num-dest";
+
+    /** The prefix for destinations */
+    public static final String P_DEST = "dest";
+
+    /** The selection method for sending individuals to other islands */
+    public static final String P_SELECT_METHOD = "select";
+
+    /** The selection method for deciding individuals to be replaced by immigrants */
+    public static final String P_SELECT_TO_DIE_METHOD = "select-to-die";
+    
+    /** Whether or not we're chatty */
+    public static final String P_CHATTY = "chatty";
+
+    /** My parameter base -- I need to keep this in order to help the server
+        reinitialize contacts */
+    // SERIALIZE
+    public Parameter base;
+    
+    IPEInformation[] exchangeInformation;
+
+    //  storage for the incoming immigrants: 2 sizes:
+    //    the subpopulation and the index of the emigrant
+    // this is virtually the array of mailboxes
+    Individual[][] immigrants;
+
+    // the number of immigrants in the storage for each of the subpopulations
+    int[] nImmigrants;
+
+    int nrSources;
+    
+    public boolean chatty;
+
+    // sets up the Island Exchanger
+    public void setup( final EvolutionState state, final Parameter _base )
+        {
+        base = _base;
+
+        Parameter p_numsubpops = new Parameter( ec.Initializer.P_POP ).push( ec.Population.P_SIZE );
+        int numsubpops = state.parameters.getInt(p_numsubpops,null,1);
+        if ( numsubpops == 0 )
+            {
+            // later on, Population will complain with this fatally, so don't
+            // exit here, just deal with it and assume that you'll soon be shut
+            // down
+            }
+
+        // how many individuals (maximally) would each of the mailboxes have to hold
+        int[] incoming = new int[ numsubpops ];
+
+        // allocate some of the arrays
+        exchangeInformation = new IPEInformation[ numsubpops ];
+        for( int i = 0 ; i < numsubpops ; i++ )
+            exchangeInformation[i] = new IPEInformation();
+        nImmigrants = new int[ numsubpops ];
+
+        Parameter p;
+
+        Parameter localBase = base.push( P_SUBPOP );
+
+        chatty = state.parameters.getBoolean(base.push(P_CHATTY), null, true);
+
+        for( int i = 0 ; i < numsubpops ; i++ )
+            {
+
+            // update the parameter for the new context
+            p = localBase.push( "" + i );
+
+            // read the selection method
+            exchangeInformation[i].immigrantsSelectionMethod = (SelectionMethod)
+                state.parameters.getInstanceForParameter( p.push( P_SELECT_METHOD ), base.push(P_SELECT_METHOD), ec.SelectionMethod.class );
+            if( exchangeInformation[i].immigrantsSelectionMethod == null )
+                state.output.fatal( "Invalid parameter.",  p.push( P_SELECT_METHOD ), base.push(P_SELECT_METHOD) );
+            exchangeInformation[i].immigrantsSelectionMethod.setup( state, p.push(P_SELECT_METHOD) );
+
+            // read the selection method
+            if( state.parameters.exists( p.push( P_SELECT_TO_DIE_METHOD ), base.push(P_SELECT_TO_DIE_METHOD ) ) )
+                exchangeInformation[i].indsToDieSelectionMethod = (SelectionMethod)
+                    state.parameters.getInstanceForParameter( p.push( P_SELECT_TO_DIE_METHOD ), base.push( P_SELECT_TO_DIE_METHOD ), ec.SelectionMethod.class );
+            else // use RandomSelection
+                exchangeInformation[i].indsToDieSelectionMethod = new ec.select.RandomSelection();
+            exchangeInformation[i].indsToDieSelectionMethod.setup( state, p.push(P_SELECT_TO_DIE_METHOD));
+
+            // get the modulo
+            exchangeInformation[i].modulo = state.parameters.getInt( p.push( P_MODULO ), base.push(P_MODULO ), 1 );
+            if( exchangeInformation[i].modulo == 0 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p.push( P_MODULO ), base.push( P_MODULO ) );
+            
+            // get the offset
+            exchangeInformation[i].offset = state.parameters.getInt( p.push( P_OFFSET ), base.push( P_OFFSET ), 0 );
+            if( exchangeInformation[i].offset == -1 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p.push( P_OFFSET ), base.push( P_OFFSET ) );
+            
+            // get the size
+            exchangeInformation[i].size = state.parameters.getInt( p.push( P_SIZE ), base.push( P_SIZE ), 1 );
+            if( exchangeInformation[i].size == 0 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p.push( P_SIZE ), base.push( P_SIZE ) );
+
+            // get the number of destinations
+            exchangeInformation[i].numDest = state.parameters.getInt( p.push( P_DEST_FOR_SUBPOP ), null, 0 );
+            if( exchangeInformation[i].numDest == -1 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p.push( P_DEST_FOR_SUBPOP ) );
+
+            exchangeInformation[i].destinations = new int[ exchangeInformation[i].numDest ];
+            // read the destinations
+            for( int j = 0 ; j < exchangeInformation[i].numDest ; j++ )
+                {
+                exchangeInformation[i].destinations[j] =
+                    state.parameters.getInt( p.push( P_DEST ).push( "" + j ), null, 0 );
+                if( exchangeInformation[i].destinations[j] == -1 ||
+                    exchangeInformation[i].destinations[j] >= numsubpops )
+                    state.output.fatal( "Parameter not found, or it has an incorrect value.", p.push( P_DEST ).push( "" + j ) );
+                // update the maximum number of incoming individuals for the destination island
+                incoming[ exchangeInformation[i].destinations[j] ] += exchangeInformation[i].size;
+                }
+
+            }
+            
+        // calculate the maximum number of incoming individuals to be stored in the mailbox
+        int max = -1;
+
+        for( int i = 0 ; i < incoming.length ; i++ )
+            if( max == - 1 || max < incoming[i] )
+                max = incoming[i];
+
+        // set up the mailboxes
+        immigrants = new Individual[ numsubpops ][ max ];
+
+        }    
+
+
+    /**
+       Initializes contacts with other processes, if that's what you're doing.
+       Called at the beginning of an evolutionary run, before a population is set up.
+       It doesn't do anything, as this exchanger works on only 1 computer.
+    */
+    public void initializeContacts(EvolutionState state)
+        {
+        }
+
+    /**
+       Initializes contacts with other processes, if that's what you're doing.  Called after restarting from a checkpoint.
+       It doesn't do anything, as this exchanger works on only 1 computer.
+    */
+    public void reinitializeContacts(EvolutionState state)
+        {
+        }
+
+
+
+    public Population preBreedingExchangePopulation(EvolutionState state)
+        {
+        // exchange individuals between subpopulations
+        // BUT ONLY if the modulo and offset are appropriate for this
+        // generation (state.generation)
+        // I am responsible for returning a population.  This could
+        // be a new population that I created fresh, or I could modify
+        // the existing population and return that.
+
+        // for each of the islands that sends individuals
+        for( int i = 0 ; i < exchangeInformation.length ; i++ )
+            {
+
+            // else, check whether the emigrants need to be sent
+            if( ( state.generation >= exchangeInformation[i].offset ) &&
+                    ( ( exchangeInformation[i].modulo == 0 ) ||
+                    ( ( ( state.generation - exchangeInformation[i].offset ) % exchangeInformation[i].modulo ) == 0 ) ) )
+                {
+
+                // send the individuals!!!!
+
+                // for each of the islands where we have to send individuals
+                for( int x = 0 ; x < exchangeInformation[i].numDest ; x++ )
+                    {
+
+                    if (chatty) state.output.message( "Sending the emigrants from subpopulation " +
+                        i + " to subpopulation " +
+                        exchangeInformation[i].destinations[x] );
+
+                    // select "size" individuals and send then to the destination as emigrants
+                    exchangeInformation[i].immigrantsSelectionMethod.prepareToProduce( state, i, 0 );
+                    for( int y = 0 ; y < exchangeInformation[i].size ; y++ ) // send all necesary individuals
+                        {
+                        // get the index of the immigrant
+                        int index = exchangeInformation[i].immigrantsSelectionMethod.produce( i, state, 0 );
+                        // copy the individual to the mailbox of the destination subpopulation
+                        immigrants[ exchangeInformation[i].destinations[x] ]
+                            [ nImmigrants[ exchangeInformation[i].destinations[x] ] ] =
+                            state.population.subpops[ i ].individuals[ index ];
+                        // increment the counter with the number of individuals in the mailbox
+                        nImmigrants[ exchangeInformation[i].destinations[x] ]++;
+                        }
+                    exchangeInformation[i].immigrantsSelectionMethod.finishProducing( state, i, 0 ); // end the selection step
+                    }
+                }
+            }
+
+        return state.population;
+
+        }
+
+
+    public Population postBreedingExchangePopulation(EvolutionState state)
+        {
+        // receiving individuals from other islands
+        // same situation here of course.
+
+        for( int x = 0 ; x < nImmigrants.length ; x++ )
+            {
+
+            if( nImmigrants[x] > 0 && chatty )
+                {
+                state.output.message( "Immigrating " +  nImmigrants[x] +
+                    " individuals from mailbox for subpopulation " + x );
+                }
+                
+            int len = state.population.subpops[x].individuals.length;
+            // double check that we won't go into an infinite loop!
+            if ( nImmigrants[x] >= state.population.subpops[x].individuals.length )
+                state.output.fatal("Number of immigrants ("+nImmigrants[x] +
+                    ") is larger than subpopulation #" + x + "'s size (" +
+                    len +").  This would cause an infinite loop in the selection-to-die procedure.");
+
+            boolean[] selected = new boolean[ len ];
+            int[] indeces = new int[ nImmigrants[x] ];
+            for( int i = 0 ; i < selected.length ; i++ )
+                selected[i] = false;
+            exchangeInformation[x].indsToDieSelectionMethod.prepareToProduce( state, x, 0 );
+            for( int i = 0 ; i < nImmigrants[x] ; i++ )
+                {
+                do {
+                    indeces[i] = exchangeInformation[x].indsToDieSelectionMethod.produce( x, state, 0 );
+                    } while( selected[indeces[i]] );
+                selected[indeces[i]] = true;
+                }
+            exchangeInformation[x].indsToDieSelectionMethod.finishProducing( state, x, 0 );
+
+            for( int y = 0 ; y < nImmigrants[x] ; y++ )
+                {
+
+                // read the individual
+                state.population.subpops[x].individuals[ indeces[y] ] = immigrants[x][y];
+
+                // reset the evaluated flag (the individuals are not evaluated in the current island */
+                state.population.subpops[x].individuals[ indeces[y] ].evaluated = false;
+
+                }
+
+            // reset the number of immigrants in the mailbox for the current subpopulation
+            // this doesn't need another synchronization, because the thread is already synchronized
+            nImmigrants[x] = 0;
+            }
+
+        return state.population;
+
+        }
+
+    /** Called after preBreedingExchangePopulation(...) to evaluate whether or not
+        the exchanger wishes the run to shut down (with ec.EvolutionState.R_FAILURE).
+        This would happen for two reasons.  First, another process might have found
+        an ideal individual and the global run is now over.  Second, some network
+        or operating system error may have occurred and the system needs to be shut
+        down gracefully.
+        This function does not return a String as soon as it wants to exit (another island found
+        the perfect individual, or couldn't connect to the server). Instead, it sets a flag, called
+        message, to remember next time to exit. This is due to a need for a graceful
+        shutdown, where checkpoints are working properly and save all needed information. */
+    public String runComplete(EvolutionState state)
+        {
+        return null;
+        }
+
+    /** Closes contacts with other processes, if that's what you're doing.  Called at the end of an evolutionary run. result is either ec.EvolutionState.R_SUCCESS or ec.EvolutionState.R_FAILURE, indicating whether or not an ideal individual was found. */
+    public void closeContacts(EvolutionState state, int result)
+        {
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/IslandExchange.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/IslandExchange.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/IslandExchange.java	(revision 6152)
@@ -0,0 +1,2274 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.exchange;
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * IslandExchange.java
+ * 
+ * Created Sat Feb 10 13:44:11 EST 2001
+ * By: Liviu Panait and Sean Luke
+ */
+
+/**
+ * IslandExchange is an Exchanger which 
+ * implements a simple but quite functional asynchronous
+ * island model for doing massive parallel distribution of evolution across
+ * beowulf clusters.  One of its really nice features is that because everything
+ * is in Java, your cluster can have mixed platforms in it (MacOS, Unix, 
+ * Windoze, whatever you like).  You can also have multiple processes running
+ * on the same machine, as long as they're given different client ports.
+ * IslandExchange operates over TCP/IP with Java sockets, and is compatible 
+ * with checkpointing.
+ *
+ * <p>IslandExchange uses an arbitrary graph topology for migrating individuals
+ * from island (EC process) to island over the network.  There are a few
+ * restrictions for simplicity, however:
+
+ <ul>
+ <li> Every island must have the same kind of subpopulations and species.
+ <li> Every subpopulation will send the same number of migrants as any 
+ other subpopulation.
+ <li> Migrants from a subpopulation will go to the same subpopulation.
+ </ul>
+
+ * <p>Every island is a <i>client</i>.  Additionally one island is designated
+ * a <i>server</i>.  Note that, just like in the Hair Club for Men, the server
+ * is also a client.  The purpose of the server is to synchronize the clients
+ * so that they all get set up properly and hook up to each other, then to
+ * send them small signal messages (like informing them that another client has
+ * discovered the ideal individual), and help them gracefully shut down.  Other
+ * than these few signals which are routed through the server to the clients,
+ * all other information -- namely the migrants themselves -- are sent directly
+ * from client to client in a peer-to-peer fashion.
+ *
+ * <p>The topology of the network is stored solely in the server's parameter
+ * database.  When the clients fire up, they first set up "Mailboxes" (where
+ * immigrants from other clients will appear), then they go to the server 
+ * and ask it who they should connect to to send migrants.  The server tells
+ * them, and then they then hook up.  When a client has finished hooking up, it
+ * reports this to the server.  After everyone has hooked up, the server tells
+ * the clients to begin evolution, and they're off and running.
+ *
+ * <p>Islands send emigrants to other islands by copying good individuals
+ * (selected with a SelectionMethod) and sending the good individuals to
+ * the mailboxes of receiving clients.  Once an individual has been received,
+ * it is considered to be unevaluated by the receiving island, even though 
+ * it had been previously evaluated by the sending island.
+ *
+ * <p>The IslandExchange model is typically <i>asynchronous</i> because migrants may
+ * appear in your mailbox at any time; islands do not wait for each other
+ * to complete the next generation.  This is a more efficient usage of network
+ * bandwidth.  When an island completes its breeding, it looks inside its
+ * mailbox for new migrants.  It then replaces some of its newly-bred
+ * individuals (chosen entirely at random)
+ * with the migrants (we could have increased the population size so we didn't
+ * waste that breeding time, but we were lazy).  It then flushes the mailbox,
+ * which patiently sits waiting for more individuals.
+ *
+ * <p>Clients may also be given different start times and modulos for 
+ * migrating.  For example, client A might be told that he begins sending emigrants
+ * only after generation 6, and then sends emigrants on every 4 generations beyond
+ * that.  The purpose for the start times and modulos is so that not every client
+ * sends emigrants at the same time; this also makes better use of network bandwidth.
+ *
+ * <p>When a client goes down, the other clients deal with it gracefully; they
+ * simply stop trying to send to it.  But if the server goes down, the clients
+ * do not continue operation; they will shut themselves down.  This means that in
+ * general you can shut down an entire island model network just by killing the
+ * server process.  However, if the server quits because it runs out of generations,
+ * it will wait for the clients to all quit before it finally stops.
+ *
+ * <p>IslandExchange works correctly with checkpointing.  If you restart from
+ * a checkpoint, the IslandExchange will start up the clients and servers again
+ * and reconnect.  Processes can start from different checkpoints, of course.
+ * However, realize that if you restart from a checkpoint, some migrants
+ * may have been lost in transit from island to island.  That's the nature of
+ * networking without heavy-duty transaction management! This means that we
+ * cannot guarantee that restarting from checkpoint will yield the same results
+ * as the first run yielded.
+ *
+ * <p>Islands are not described in the topology parameters by their
+ * IP addresses; instead, they are described by "ids", strings which uniquely 
+ * identify each island.  For example, "gilligans-island" might be an id.  :-)
+ * This allows you to move your topology to different IP addresses without having
+ * to change all your parameter files!  You can even move your topology to totally
+ * different machines, and restart from previous checkpoints, and everything
+ * should still work correctly.
+ *
+ * <p>There are times, especially to experiment with dynamics, that you need
+ * a <i>synchronous</i> island model.  If you specify synchronicity, the server's
+ * stated modulo and offset override any modulii or offsets specified by clients.
+ * Everyone will use the server's modulo and offset.  This means that everyone
+ * will trade individuals on the same generation.  Additionally, clients will wait
+ * until everyone else has traded, before they are permitted to continue evolving.
+ * This has the effect of locking all the clients together generation-wise; no
+ * clients can run faster than any other clients.
+ * 
+ * <p>One last item: normally in this model, the server is also a client.  But 
+ * if for some reason you need the server to be a process all by itself, without
+ * creating a client as well, you can do that.  You spawn such a server differently
+ * than the main execution of ECJ.  To spawn a server on a given server params file
+ * (let's say it's server.params) but NOT spawn a client, you do:
+ <p><pre>
+ java ec.exchange.IslandExchange -file server.params
+ </pre>
+ * <p> ...this sets up a special process which just spawns a server, and doesn't do
+ * all the setup of an evolutionary run.  Of course as usual, for each of the 
+ * clients, you'll run <tt>java ec.Evolve ...</tt> instead.
+
+ <p><b>Parameters</b><br>
+ <p><i>Note:</i> some of these parameters are only necessary for creating
+ <b>clients</b>.  Others are necessary for creating the <b>server</b>.
+ <table>
+ <tr><td valign=top><tt><i>base</i>.chatty</tt><br>
+ <font size=-1>boolean, default = true</font></td>
+ <td valign=top> Should we be verbose or silent about our exchanges?
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.select</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod</font></td>
+ <td valign=top>
+ <i>client</i>: The selection method used for picking migrants to emigrate to other islands
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.select-to-die</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod, default is ec.select.RandomSelection</font></td>
+ <td valign=top>
+ <i>client</i>: The selection method used for picking individuals to be replaced by incoming migrants.
+ <b>IMPORTANT Note</b>.  This selection method must <i>not</i> pick an individual based on fitness.
+ The selection method will be called just after breeding but <i>before</i> evaluation; many individuals
+ will not have had a fitness assigned at that point.  You might want to design a SelectionMethod
+ other than RandomSelection, however, to do things like not picking elites to die.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.server-addr</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>
+ <i>client</i>: The IP address of the server
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.server-port</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>client</i>: The port number of the server
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.client-port</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>client</i>: The port number of the client (where it will receive migrants) -- this should be different from the server port.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.id</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>
+ <i>client</i>: The "name" the client is giving itself.  Each client should have a unique name.  For example, "gilligans-island".
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.compressed</tt><br>
+ <font size=-1>bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ <td valign=top>
+ <i>client</i>: Whether the communication with other islands should be compressed or not.  Compressing uses more CPU, but it may also significantly reduce communication.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.i-am-server</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>
+ <i>client</i>: Is this client also the server?  If so, it'll read the server parameters and set up a server as well.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.sync</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>
+ <i>server</i>: Are we doing a synchronous island model?  If so, the server's modulo and offset override any client's stated modulo and offset.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.num-islands</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: The number of islands in the topology.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.id</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>
+ <i>server</i>: The ID of island #n in the topology.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.num-mig</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: The number of islands that island #n sends emigrants to.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.mig.</tt><i>m</i><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: The ID of island #m that island #n sends emigrants to.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.size</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: The number of emigrants (per subpopulation) that island #n sends to other islands.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.size</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: number of emigrants (per subpopulation) that a given island sends to other islands.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.start</tt><br>
+ <font size=-1>int >= 0</font></td>
+ <td valign=top>
+ <i>server</i>: The generation when island #n begins sending emigrants. If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.start</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: the generation when an island begins sending emigrants.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.mod</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: The number of generations that island #n waits between sending emigrants.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.mod</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: The number of generations an island waits between sending emigrants.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.island.<i>n</i>.mailbox-capacity</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: The maximum size (per subpopulation) of the mailbox for island #n.  If not set, uses the default parameter below.
+ </td></tr>
+ <tr><td valign=top><tt><i>base</i>.mailbox-capacity</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>
+ <i>server</i>: Default parameter: the maximum size (per subpopulation) of the mailbox for a given island.
+ </td></tr>
+ </table>
+ 
+ <p><b>Parameter bases</b><br>
+ <table>
+
+ <tr><td valign=top><tt><i>base</i>.select</tt></td>
+ <td>selection method for the client's migrants</td></tr>
+ </table>
+  
+ * @author Liviu Panait and Sean Luke
+ * @version 2.0
+ */
+
+public class IslandExchange extends Exchanger
+    {
+
+    //// Client information
+
+    /** The server address */
+    public static final String P_SERVER_ADDRESS = "server-addr";
+
+    /** The server port */
+    public static final String P_SERVER_PORT = IslandExchangeServer.P_SERVER_PORT;
+
+    /** The client port */
+    public static final String P_CLIENT_PORT = "client-port";
+
+    /** Whether the server is also on this island */
+    public static final String P_IS_SERVER = "i-am-server";
+    
+    /** The id of the island */
+    public static final String P_OWN_ID = "id";
+        
+    /** Whether the communication is compressed or not */
+    public static final String P_COMPRESSED_COMMUNICATION = "compressed";
+
+    /** The selection method for sending individuals to other islands */
+    public static final String P_SELECT_METHOD = "select";
+
+    /** The selection method for deciding individuals to be replaced by immigrants */
+    public static final String P_SELECT_TO_DIE_METHOD = "select-to-die";
+
+    /** How long we sleep in between attempts to connect or look for signals */
+    public static final int SLEEP_TIME = 100;
+
+    /** How long we sleep between checking for FOUND messages */
+    public static final int FOUND_TIMEOUT = 100;
+
+    /** Whether or not we're chatty */
+    public static final String P_CHATTY = "chatty";
+
+    /** Okay signal */
+    public static final String OKAY = "okay";
+
+    /** Synchronize signal */
+    public static final String SYNC = "sync";
+
+    /** Found signal */
+    public static final String FOUND = "found";
+
+    /** Our chattiness */
+    boolean chatty;
+
+    /** The thread of the server (is different than null only for the island with the server) */
+    public Thread serverThread;
+
+    /** My parameter base -- I need to keep this in order to help the server
+        reinitialize contacts */
+    // SERIALIZE
+    public Parameter base;
+    
+    /** The address of the server */
+    // SERIALIZE
+    public String serverAddress;
+
+    /** The port of the server */
+    // SERIALIZE
+    public int serverPort;
+
+    /** The port of the client mailbox */
+    // SERIALIZE
+    public int clientPort;
+
+    /** whether the server should be running on the current island or not */
+    // SERIALIZE
+    public boolean iAmServer;
+
+    /** the id of the current island */
+    // SERIALIZE
+    public String ownId;
+
+    /** whether the communication is compressed or not */
+    // SERIALIZE
+    public boolean compressedCommunication;
+
+    /** the selection method for emigrants */
+    // SERIALIZE
+    public SelectionMethod immigrantsSelectionMethod;
+
+    /** the selection method for individuals to be replaced by immigrants */
+    // SERIALIZE
+    public SelectionMethod indsToDieSelectionMethod;
+
+    // the mailbox of the current client (exchanger)
+    IslandExchangeMailbox mailbox;
+
+    // the thread of the mailbox
+    Thread mailboxThread;
+
+    /// Communication with the islands where individuals have to be sent
+    // Number of islands to send individuals to
+    int number_of_destination_islands;
+
+    /** synchronous or asynchronous communication */
+    public boolean synchronous;
+
+    /** how often to send individuals */
+    public int modulo;
+
+    /** after how many generations to start sending individuals */
+    public int offset;
+
+    /** how many individuals to send each time */
+    public int size;
+
+    // Sockets to the destination islands
+    Socket[] outSockets;
+
+    // DataOutputStream to the destination islands
+    DataOutputStream[] outWriters;
+
+    // so we can print out nice names for our outgoing connections
+    String[] outgoingIds;
+
+    // information on the availability of the different islands
+    boolean[] running;
+
+    // the capacity of the mailboxes
+//    int mailboxCapacity;
+
+    // the socket to the server
+    Socket serverSocket;
+
+    // reader and writer to the serverSocket
+    DataOutputStream toServer;
+    DataInputStream fromServer;
+
+    // am I ONLY a server?
+    static boolean just_server;
+
+    public static void main(String[] args) throws InterruptedException
+        {
+        just_server = true;
+        int x;
+        ParameterDatabase parameters=null;
+        Output output;
+        boolean store;
+        
+        // The following is a little chunk of the ec.Evolve code sufficient
+        // to get IslandExchange up and running all by itself.
+        
+        System.err.println("Island Exchange Server\n" +
+            "Used in ECJ by Sean Luke\n");
+        
+        
+        // 0. find the parameter database
+        for(x=0;x<args.length-1;x++)
+            if (args[x].equals(Evolve.A_FILE))
+                {
+                try
+                    {
+                    parameters=new ParameterDatabase(
+                        // not available in jdk1.1: new File(args[x+1]).getAbsoluteFile(),
+                        new File(new File(args[x+1]).getAbsolutePath()),
+                        args);
+                    break;
+                    }
+                catch(FileNotFoundException e)
+                    { Output.initialError(
+                            "A File Not Found Exception was generated upon" +
+                            "reading the parameter file \"" + args[x+1] + 
+                            "\".\nHere it is:\n" + e); }
+                catch(IOException e)
+                    { Output.initialError(
+                            "An IO Exception was generated upon reading the" +
+                            "parameter file \"" + args[x+1] +
+                            "\".\nHere it is:\n" + e); } 
+                }
+        if (parameters==null)
+            Output.initialError(
+                "No parameter file was specified." ); 
+
+        // 1. create the output
+        //store = (parameters.getBoolean(new Parameter(Evolve.P_STORE),null,false));
+
+        output = new Output(true);
+        // output.setFlush(
+        //    parameters.getBoolean(new Parameter(Evolve.P_FLUSH),null,false));
+
+
+        // stdout is always log #0.  stderr is always log #1.
+        // stderr accepts announcements, and both are fully verbose 
+        // by default.
+        output.addLog(ec.util.Log.D_STDOUT,false);
+        output.addLog(ec.util.Log.D_STDERR,true); 
+        
+        
+        // this is an ugly, ugly, ugly, UGLY HACK
+        // it will only work if we don't ask interesting things
+        // of our "EvolutionState"  :-)  you know, things like
+        // random number generators or generation numbers!
+        
+        EvolutionState myEvolutionState = new
+            EvolutionState();
+        
+        myEvolutionState.parameters = parameters;
+        myEvolutionState.output = output;
+        
+        // set me up
+        Parameter myBase = new Parameter(EvolutionState.P_EXCHANGER);
+
+        IslandExchange ie = (IslandExchange)parameters.getInstanceForParameterEq(
+            myBase, null, IslandExchange.class);
+        
+        ie.setup(myEvolutionState,myBase);
+        ie.fireUpServer(myEvolutionState,myBase);
+        ie.serverThread.join();
+        
+        // flush the output
+        output.flush();
+        System.err.flush();
+        System.out.flush();
+        System.exit(0);
+        }
+
+    // sets up the Island Exchanger
+    public void setup( final EvolutionState state, final Parameter _base )
+        {
+        base = _base;
+
+        Parameter p;
+        
+        // get the port of the server
+        p = base.push( P_SERVER_PORT );
+        serverPort = state.parameters.getInt( p, null, 1 );
+        if( serverPort == 0 )
+            state.output.fatal( "Could not get the port of the server, or it is invalid.", p );
+
+        chatty = state.parameters.getBoolean(base.push(P_CHATTY), null, true);
+
+        // by default, communication is not compressed
+        compressedCommunication = state.parameters.getBoolean(base.push(P_COMPRESSED_COMMUNICATION),null,false);
+        if( compressedCommunication )
+            {
+//            state.output.fatal("JDK 1.5 has broken compression.  For now, you must set " + base.push(P_COMPRESSED_COMMUNICATION) + "=false");
+            state.output.message( "Communication will be compressed" ); 
+            }
+            
+        // check whether it has to launch the main server for coordination
+        p = base.push( P_IS_SERVER );
+        iAmServer = state.parameters.getBoolean( p, null, false );
+
+        // Am I ONLY the server or not?
+        if (just_server)
+            {
+            // print out my IP address
+            try
+                {
+                state.output.message("IP ADDRESS: " + LocalHost.getLocalHost().getHostAddress());
+                }
+            catch (java.net.UnknownHostException e) { }
+            }
+        else
+            {
+            // setup the selection method
+            p = base.push( P_SELECT_METHOD );
+            immigrantsSelectionMethod = (SelectionMethod)
+                state.parameters.getInstanceForParameter( p, null, ec.SelectionMethod.class );
+            immigrantsSelectionMethod.setup( state, base );
+
+            // setup the selection method
+            p = base.push( P_SELECT_TO_DIE_METHOD );
+            if( state.parameters.exists( p, null) )
+                indsToDieSelectionMethod = (SelectionMethod)
+                    state.parameters.getInstanceForParameter( p, null, ec.SelectionMethod.class );
+            else // use RandomSelection
+                indsToDieSelectionMethod = new ec.select.RandomSelection();
+            indsToDieSelectionMethod.setup( state, base );
+
+            // get the address of the server
+            p = base.push( P_SERVER_ADDRESS );
+            serverAddress = state.parameters.getStringWithDefault( p, null, "" );
+            if( serverAddress.equalsIgnoreCase("") )
+                state.output.fatal( "Could not get the address of the server.", p );
+
+            // get the port of the client mailbox
+            p = base.push( P_CLIENT_PORT );
+            clientPort = state.parameters.getInt( p, null, 1 );
+            if( clientPort == 0 )
+                state.output.fatal( "Could not get the port of the client, or it is invalid.", p );
+
+            // get the id of the island
+            p = base.push( P_OWN_ID );
+            ownId = state.parameters.getStringWithDefault( p, null, "" );
+            if( ownId.equals("") )
+                state.output.fatal( "Could not get the Id of the island.", p );
+            }
+        }
+
+    /** Custom serialization */
+    private void writeObject(ObjectOutputStream out) throws IOException
+        {
+        // this is all we need to write out -- everything else
+        // gets recreated when we call reinitializeContacts(...) again...
+    
+        out.writeObject(base);
+        out.writeObject(serverAddress);
+        out.writeObject(ownId);
+        out.writeBoolean(compressedCommunication);
+        out.writeObject(immigrantsSelectionMethod);
+        out.writeObject(indsToDieSelectionMethod);
+        out.writeInt(serverPort);
+        out.writeInt(clientPort);
+        out.writeBoolean(iAmServer);
+        }
+
+    /** Custom serialization */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+        {
+        // this is all we need to read in -- everything else
+        // gets recreated when we call reinitializeContacts(...) again...
+    
+        base = (Parameter)(in.readObject());
+        serverAddress=(String)(in.readObject());
+        ownId=(String)(in.readObject());
+        compressedCommunication = in.readBoolean();
+        immigrantsSelectionMethod=(SelectionMethod)(in.readObject());
+        indsToDieSelectionMethod=(SelectionMethod)(in.readObject());
+        serverPort = in.readInt();
+        clientPort = in.readInt();
+        iAmServer = in.readBoolean();
+        }
+    
+    
+    /** Fires up the server. */
+
+    public void fireUpServer(EvolutionState state, Parameter serverBase)
+        {
+        IslandExchangeServer serv = new IslandExchangeServer();
+        serv.setupServerFromDatabase(state,serverBase);
+        serverThread = serv.spawnThread();
+        }
+        
+
+    /** Initializes contacts with other processes, if that's what you're doing. Called at the beginning of an evolutionary run, before a population is set up. */
+    public void initializeContacts(EvolutionState state)
+        {
+
+        // launch the server
+        if( iAmServer )
+            {
+            fireUpServer(state,base);
+            state.output.message( "Server Launched." );
+            }
+        else
+            {
+            state.output.message( "I'm just a client." );
+            }
+
+
+
+        // In this thread, *I* am the client.  I connect to the server
+        // and get the information from the server, then I connect
+        // to the clients and go through the synchronization process
+        // with the server.  Spawn the mailbox. When the server says "go", I'm done with
+        // this function.
+
+
+        /** Make our connections and hook up */
+        long l = 0;
+        try
+            { 
+            // spin until we get a connection
+            state.output.message("Connecting to Server " + serverAddress + ", port " + serverPort);
+            while(true)
+                {
+                try
+                    {
+                    serverSocket = new Socket(serverAddress,serverPort);
+                    break;
+                    }
+                catch (IOException e)   // it's not up yet...
+                    {
+                    l++;
+                    try
+                        {
+                        Thread.sleep( 5000 );
+                        }
+                    catch( InterruptedException f )
+                        {
+                        state.output.message(""+f);
+                        }
+                    state.output.message("Retrying");
+                    }
+                }
+            
+            // okay, we're connected.  Send our info.
+            state.output.message("Connected to Server after " + (l * SLEEP_TIME) + " ms");
+            fromServer = new DataInputStream(serverSocket.getInputStream());
+            toServer = new DataOutputStream(serverSocket.getOutputStream());
+
+            // sending the server own contact information
+            toServer.writeUTF( ownId );
+            toServer.flush();
+
+            // Launch the mailbox thread (read from the server how many sockets to allocate
+            // on the mailbox. Obtain the port and address of the mailbox.
+            mailbox = new IslandExchangeMailbox( state, clientPort, fromServer.readInt(),
+                fromServer.readInt(), ownId, chatty, compressedCommunication );
+            mailboxThread = new Thread( mailbox );
+            mailboxThread.start();
+
+            // record that the mailbox has been created
+            state.output.message( "IslandExchangeMailbox created." );
+
+            // tell the server the address and port of the mailbox
+            try
+                {
+                toServer.writeUTF( LocalHost.getLocalHost().getHostAddress() );
+                toServer.flush();
+                state.output.message("My address is: " + LocalHost.getLocalHost().getHostAddress() );
+                }
+            catch( UnknownHostException e )
+                {
+                state.output.fatal( "Could not get the address of the local computer." );
+                }
+            toServer.writeInt( mailbox.getPort() );
+            toServer.flush();
+
+            // read from the server the modulo, offset and size it has to use.
+            // this parameters allow an extendable/modifiable version where different
+            // islands send different number of individuals (based on the size of their populations)
+            synchronous = ( fromServer.readInt() == 1 );
+            if( synchronous )
+                {
+                state.output.message( "The communication will be synchronous." );
+                }
+            else
+                {
+                state.output.message( "The communication will be asynchronous." );
+                }
+            modulo = fromServer.readInt();
+            offset = fromServer.readInt();
+            size = fromServer.readInt();
+
+            // read the number of islands it has to send messages to
+            number_of_destination_islands = fromServer.readInt();
+
+            // allocate the arrays
+            outSockets = new Socket[ number_of_destination_islands ];
+            outWriters = new DataOutputStream[ number_of_destination_islands ];
+            running = new boolean[ number_of_destination_islands ];
+            outgoingIds = new String[ number_of_destination_islands ];
+
+            // open connections to each of the destination islands
+            for( int y = 0 ; y < number_of_destination_islands ; y++ )
+                {
+                // get the address and the port
+                String address = fromServer.readUTF().trim();
+                int port = fromServer.readInt();
+                try
+                    {
+                    try
+                        {
+                        state.output.message( "Trying to connect to " + address + " : " + port );
+                        // try opening a connection
+                        outSockets[y] = new Socket( address, port );
+                        }
+                    catch( UnknownHostException e )
+                        {
+                        // gracefully handle communication errors
+                        state.output.warning( "Unknown host exception while the client was opening a socket to " + address + " : " + port );
+                        running[y] = false;
+                        continue;
+                        }
+
+                    if( compressedCommunication )
+                        {
+                        /*                        
+                                                  outWriters[y] = new DataOutputStream(new CompressingOutputStream(outSockets[y].getOutputStream()));
+                                                  // read the mailbox's id, then write my own id
+                                                  outgoingIds[y] = new DataInputStream(new CompressingInputStream(outSockets[y].getInputStream())).readUTF().trim();
+                        */
+                        
+                        OutputStream compressedo = Output.makeCompressingOutputStream(outSockets[y].getOutputStream());
+                        InputStream compressedi = Output.makeCompressingInputStream(outSockets[y].getInputStream());
+                        if (compressedi == null || compressedo == null) 
+                            state.output.fatal( "You do not appear to have JZLib installed on your system, and so may must have compression turned off for IslandExchange.  "+ 
+                                "To get JZLib, download from the ECJ website or from http://www.jcraft.com/jzlib/");
+                        outWriters[y] = new DataOutputStream(compressedo);
+                        outgoingIds[y] = new DataInputStream(compressedi).readUTF().trim();
+                        }
+                    else
+                        {
+                        outWriters[y] = new DataOutputStream(outSockets[y].getOutputStream());
+
+                        // read the mailbox's id, then write my own id
+                        outgoingIds[y] = new DataInputStream(outSockets[y].getInputStream()).readUTF().trim();
+                        }
+                        
+                    outWriters[y].writeUTF(ownId);
+                    outWriters[y].flush();
+            
+                    running[y] = true;
+                    }
+                catch( IOException e )
+                    {
+                    // this is caused if the server had problems locating information
+                    // on the mailbox of the other island, therefore remember the
+                    // communication with this island is not setup properly
+                    state.output.warning( "IO exception while the client was opening sockets to other islands' mailboxes :" + e );
+                    running[y] = false;
+                    }
+                }
+
+            // synchronization stuff: tells the server it finished connecting to other mailboxes
+            toServer.writeUTF( OKAY );
+            toServer.flush();
+
+            // wait for the run signal
+            fromServer.readUTF();
+
+            }
+        catch( IOException e )
+            {
+            state.output.fatal( "Error communicating to the server." );
+            }
+
+        // at this point, the mailbox is looking for incoming messages
+        // form other islands. we have to exit the function. there is
+        // one more thing to be done: to check for the server sending a
+        // FOUND signal. In order to do this, we set the socket to the
+        // server as non-blocking, and verify that for messages from the
+        // server in the runComplete function
+        try
+            {
+            serverSocket.setSoTimeout( FOUND_TIMEOUT );
+            }
+        catch( SocketException e )
+            {
+            state.output.fatal( "Could not set the connection to the server to non-blocking." );
+            }
+
+        }
+
+    /** Initializes contacts with other processes, if that's what you're doing.  Called after restarting from a checkpoint. */
+    public void reinitializeContacts(EvolutionState state)
+        {
+        // This function is almost the same as initializeContacts.
+        // The only main difference is that when reinitializeContacts
+        // is called, it's called because I started up from a checkpoint file.
+        // This means that I'm in the middle of evolution, so the modulo
+        // and start might cause me to update more recently than if I had
+        // started fresh.  But maybe it won't make a difference in this method
+        // if the way I determine when I'm firing off migrants is on a
+        // generation-by-generation basis.
+
+        initializeContacts( state );
+
+        }
+
+
+
+    public Population preBreedingExchangePopulation(EvolutionState state)
+        {
+        // sending individuals to other islands
+        // BUT ONLY if my modulo and offset are appropriate for this
+        // generation (state.generation)
+        // I am responsible for returning a population.  This could
+        // be a new population that I created fresh, or I could modify
+        // the existing population and return that.
+
+        // else, check whether the emigrants need to be sent
+        if( ( state.generation >= offset ) &&
+            ( ( modulo == 0 ) || ( ( ( state.generation - offset ) % modulo ) == 0 ) ) )
+            {
+
+            // send the individuals!!!!
+
+            // for each of the islands where we have to send individuals
+            for( int x = 0 ; x < number_of_destination_islands ; x++ )
+                try
+                    {
+
+                    // check whether the communication is ok with the current island
+                    if( running[x] )
+                        {
+
+                        if (chatty) state.output.message( "Sending " + size + " emigrants to island " + outgoingIds[x] );
+
+                        // for each of the subpopulations
+                        for( int subpop = 0 ; subpop < state.population.subpops.length ; subpop++ )
+                            {
+                            // send the subpopulation
+                            outWriters[x].writeInt( subpop );
+
+                            // send the number of individuals to be sent
+                            // it's better to send this information too, such that islands can (potentially)
+                            // send different numbers of individuals
+                            outWriters[x].writeInt( size );
+
+                            // select "size" individuals and send then to the destination as emigrants
+                            immigrantsSelectionMethod.prepareToProduce( state, subpop, 0 );
+                            for( int y = 0 ; y < size ; y++ ) // send all necesary individuals
+                                {
+                                int index = immigrantsSelectionMethod.produce( subpop, state, 0 );
+                                state.population.subpops[subpop].individuals[index].
+                                    writeIndividual( state, outWriters[x] );
+                                outWriters[x].flush();  // just in case the individuals didn't do a println
+                                }
+                            immigrantsSelectionMethod.finishProducing( state, subpop, 0 ); // end the selection step
+                            }
+                        }
+                    }
+                catch( IOException e )
+                    {
+                    running[x] = false;
+                    }
+            }
+
+        return state.population;
+
+        }
+
+
+    public Population postBreedingExchangePopulation(EvolutionState state)
+        {
+        // receiving individuals from other islands
+        // same situation here of course.
+
+        // if synchronous communication, synchronize with the mailbox
+        // if( ( state.generation >= offset ) && synchronous &&
+        //    ( ( modulo == 0 ) || ( ( ( state.generation - offset ) % modulo ) == 0 ) ) )
+        if (synchronous)
+            {
+            state.output.message( "Waiting for synchronization...." );
+
+            // set the socket to the server to blocking
+            try
+                {
+                serverSocket.setSoTimeout( 0 );
+                }
+            catch( SocketException e )
+                {
+                state.output.fatal( "Could not set the connection to the server to blocking." );
+                }
+
+            try
+                {
+                // send the sync message
+                toServer.writeUTF( SYNC );
+                toServer.flush();
+                // wait for the okay message
+                String temp = fromServer.readUTF();
+                if( temp.equals( IslandExchangeServer.GOODBYE ) )
+                    {
+                    alreadyReadGoodBye = true;
+                    }
+                }
+            catch( IOException e )
+                {
+                state.output.fatal( "Could not communicate to the server. Exiting...." );
+                }
+
+            // set the socket to the server to non-blocking
+            try
+                {
+                serverSocket.setSoTimeout( FOUND_TIMEOUT );
+                }
+            catch( SocketException e )
+                {
+                state.output.fatal( "Could not set the connection to the server to non-blocking." );
+                }
+            //state.output.message( "Synchronized. Reading individuals...." );
+            }
+
+        // synchronize, because immigrants is also accessed by the mailbox thread
+        synchronized( mailbox.immigrants )
+            {
+            for( int x = 0 ; x < mailbox.immigrants.length ; x++ )
+                {
+                if( mailbox.nImmigrants[x] > 0 )
+                    {
+                    if (chatty) state.output.message( "Immigrating " +  mailbox.nImmigrants[x] + " individuals from mailbox for subpopulation " + x );
+
+                    boolean[] selected = new boolean[ state.population.subpops[x].individuals.length ];
+                    int[] indeces = new int[ mailbox.nImmigrants[x] ];
+                    for( int i = 0 ; i < selected.length ; i++ )
+                        selected[i] = false;
+                    indsToDieSelectionMethod.prepareToProduce( state, x, 0 );
+                    for( int i = 0 ; i < mailbox.nImmigrants[x] ; i++ )
+                        {
+                        do {
+                            indeces[i] = indsToDieSelectionMethod.produce( x, state, 0 );
+                            } while( selected[indeces[i]] );
+                        selected[indeces[i]] = true;
+                        }
+                    indsToDieSelectionMethod.finishProducing( state, x, 0 );
+
+                    // there is no need to check for the differences in size: the mailbox.immigrants,
+                    // state.population.subpops and the mailbox.person2die should have the same size
+                    for( int y = 0 ; y < mailbox.nImmigrants[x] ; y++ )
+                        {
+
+                        // read the individual
+                        state.population.subpops[x].
+                            individuals[ indeces[y] ] = mailbox.immigrants[x][y];
+
+                        // reset the evaluated flag (the individuals are not evaluated in the current island */
+                        state.population.subpops[x].
+                            individuals[ indeces[y] ].evaluated = false;
+
+                        }
+
+                    // reset the number of immigrants in the mailbox for the current subpopulation
+                    // this doesn't need another synchronization, because the thread is already synchronized
+                    mailbox.nImmigrants[x] = 0;
+
+                    }
+                }
+
+            }
+
+        return state.population;
+        }
+
+    // if the GOODBYE message sent by the server gets read in the wrong place, this
+    // variable is set to true
+    boolean alreadyReadGoodBye = false;
+
+    // keeps the message to be returned next time on runComplete
+    String message;
+
+    /** Called after preBreedingExchangePopulation(...) to evaluate whether or not
+        the exchanger wishes the run to shut down (with ec.EvolutionState.R_FAILURE).
+        This would happen for two reasons.  First, another process might have found
+        an ideal individual and the global run is now over.  Second, some network
+        or operating system error may have occurred and the system needs to be shut
+        down gracefully.
+        This function does not return a String as soon as it wants to exit (another island found
+        the perfect individual, or couldn't connect to the server). Instead, it sets a flag, called
+        message, to remember next time to exit. This is due to a need for a graceful
+        shutdown, where checkpoints are working properly and save all needed information. */
+    public String runComplete(EvolutionState state)
+        {
+
+        // first test the flag, and exit if it was previously set
+        if( message != null ) // if an error occured earlier
+            {
+            return message;
+            }
+
+        // check whether the server sent a FOUND message.
+        // if it did, check whether it should exit or not
+        try
+            {
+            // read a line. if it is successful, it means that the server sent a FOUND message
+            // (this is the only message the server sends right now), and it should set the flag
+            // for exiting next time when in this procedure
+            String ww = fromServer.readUTF();
+            if( ww != null || alreadyReadGoodBye ) // FOUND message sent from the server
+                {
+                // we should exit because some other individual has
+                // found the perfect fit individual
+                if( state.quitOnRunComplete )
+                    {
+                    message = "Exit: Another island found the perfect individual.";
+                    state.output.message( "Another island found the perfect individual. Exiting...." );
+                    toServer.writeUTF( OKAY );
+                    toServer.flush();
+                    }
+                else
+                    {
+                    state.output.message( "Another island found the perfect individual." );
+                    }
+                }
+            else // ( ww == null ) // the connection with the server was closed
+                {
+                // we should exit, because we cannot communicate with the
+                // server anyway
+                message = "Exit: Could not communicate with the server.";
+                state.output.warning( "Could not communicate with the server. Exiting...." );
+                }
+            }
+        catch( InterruptedIOException e )
+            {
+            // here don't do anything: it reaches this point when the server is on, but nobody found
+            // the perfect individual. in this case, it should just return null, so that the
+            // execution continues
+            }
+        catch( IOException e )
+            {
+            // some weird error
+            // report it in a warning
+            state.output.warning( "Some weird IO exception reported by the system in the IslandExchange::runComplete function.  Is it possible that the server has crashed?" );
+            }
+
+        return null;
+        }
+
+    /** Closes contacts with other processes, if that's what you're doing.  Called at the end of an evolutionary run. result is either ec.EvolutionState.R_SUCCESS or ec.EvolutionState.R_FAILURE, indicating whether or not an ideal individual was found. */
+    public void closeContacts(EvolutionState state, int result)
+        {
+        // if the run was successful (perfect individual was found)
+        // then send a message to the server that it was found
+        if( result == EvolutionState.R_SUCCESS )
+            {
+            try
+                {
+                toServer.writeUTF( FOUND );
+                toServer.flush();
+                }
+            catch( IOException e ) {}
+            }
+
+        // close socket to server
+        try
+            {
+            serverSocket.close();
+            }
+        catch( IOException e )
+            {
+            }
+
+        state.output.message( "Shutting down the mailbox" );
+        // close the mailbox and wait for the thread to terminate
+        mailbox.shutDown();
+        mailboxThread.interrupt();
+        try
+            {
+            mailboxThread.join();
+            }
+        catch( InterruptedException e )
+            {
+            }
+        state.output.message( "Mailbox shut down" );
+
+        // close out-going sockets
+        for( int x = 0 ; x < number_of_destination_islands ; x++ )
+            {
+            // catch each exception apart (don't take into consideration the running variables)
+            try
+                {
+                if( running[x] )
+                    outSockets[x].close();
+                }
+            catch( IOException e )
+                {
+                }
+            }
+
+        // if the island also hosts the server, wait till it terminates
+        if( iAmServer )
+            {
+            state.output.message( "Shutting down the server" );
+            try
+                {
+                serverThread.join();
+                }
+            catch( InterruptedException e )
+                {
+                }
+            state.output.message( "Server shut down" );
+            }
+
+        }
+
+    /* (non-Javadoc)
+     * @see ec.EvolutionState#finish(int)
+     */
+    public void finish(int result) {
+        }
+
+    /* (non-Javadoc)
+     * @see ec.EvolutionState#startFromCheckpoint()
+     */
+    public void startFromCheckpoint() {
+        }
+
+    /* (non-Javadoc)
+     * @see ec.EvolutionState#startFresh()
+     */
+    public void startFresh() {
+        }
+
+    /* (non-Javadoc)
+     * @see ec.EvolutionState#evolve()
+     */
+    public int evolve()
+        throws InternalError {
+        return 0;
+        }
+        
+    }
+
+/** Class that contains all the mailbox functionality. It is supposed to wait on a new thread for incoming
+    immigrants from other islands (it will receive in the constructor the number of islands that will send
+    messages to the current island). Waiting on sockets is non-blocking, such that the order in which the
+    islands send messages is unimportant. When immigrants are received, they are stored in a special buffer
+    called immigrants. The storage is managed in a queue-like fashion, such that when the storage is full,
+    the first immigrants that came are erased (hopefully the storage will be emptied fast enough such that
+    this case doesn't appear too often).
+    All accesses to the "immigrants" variable (also applies to nImmigrants) should be done only in the presence
+    of synchronization, because there might be other threads using them too. The number of immigrants for each
+    of the subpopulations (nImmigrants[x]) is between 0 and the size of the queue structure (received as a
+    parameter in the constructor). */
+class IslandExchangeMailbox implements Runnable
+    {
+
+    /** How much to wait before starting checking for immigrants */
+    public static final int SLEEP_BETWEEN_CHECKING_FOR_IMMIGRANTS = 1000;
+
+    /** How much to wait on a socket for a message, before starting to wait on another socket */
+    public static final int CHECK_TIMEOUT = 1000;
+
+    /** How much to wait while synchronizing */
+    public static final int SYNCHRONIZATION_SLEEP = 100;
+
+    /**  storage for the incoming immigrants: 2 sizes: the subpopulation and the index of the emigrant */
+    public Individual[][] immigrants;
+
+    /** the number of immigrants in the storage for each of the subpopulations */
+    public int[] nImmigrants;
+
+    // auxiliary variables to manage the queue storages
+    int[] person2die;
+
+    // the socket where it listens for incomming messages
+    ServerSocket serverSocket;
+
+    // the number of islands that send messages to the current mailbox
+    int n_incoming;
+
+    // whether the information on sockets is compressed or not (receives this information in the constructor)
+    boolean compressedCommunication;
+
+    // the sockets and readers for receiving incoming messages
+    Socket[] inSockets;
+    DataInputStream[] dataInput;
+    String[] incomingIds;      // so we can print out nice names for our incoming connections
+
+    // the state of the islands it is communicating to
+    boolean[] running;
+
+    // the state (to display messages mainly)
+    EvolutionState state;
+
+    // synchronization variable
+    Boolean syncVar;
+
+    // My ID
+    String myId;
+    
+    boolean chatty;
+
+    /**
+       Public constructor used to initialize most of the parameters of the mailbox:
+       state_p : the EvolutionState, used mainly for displaying messages
+       port : the port used to listen for incoming messages
+       n_incoming_p : the number of islands that will send messages to the current island
+       how_many : how many immigrants to manage in the queue-like storage for each of the subpopulations
+    */
+    public IslandExchangeMailbox( final EvolutionState state_p, int port, int n_incoming_p, int how_many, String _myId, boolean chatty, boolean _compressedCommunication )
+        {
+        myId = _myId;
+        compressedCommunication = _compressedCommunication;
+        
+        this.chatty = chatty;
+    
+        // initialize public variables from the parameters of the constructor
+        state = state_p;
+        n_incoming = n_incoming_p;
+
+        Parameter p_numsubpops = new Parameter( ec.Initializer.P_POP ).push( ec.Population.P_SIZE );
+        int numsubpops = state.parameters.getInt(p_numsubpops,null,1);
+        if ( numsubpops == 0 )
+            {
+            // later on, Population will complain with this fatally, so don't
+            // exit here, just deal with it and assume that you'll soon be shut
+            // down
+            }
+
+        // allocate the storages:
+        // - immigrants = storage for the immigrants that will come to the current island
+        //   - first dimension: the number of subpopulations
+        //   - second dimension: how many immigrants to store for each of the subpopulations.
+        // - person2die = where to insert next in the queue structure "immigrants"
+        // - nImmigrants = how many immigrants there are in the storage "immigrants" for each of the subpopulations
+        immigrants = new Individual[ numsubpops ][ how_many ];
+        person2die = new int[ numsubpops ];
+        nImmigrants = new int[ numsubpops ];
+
+        // set the synchronization variable to false (it will be set to true to signal exiting the waiting loop)
+        syncVar = Boolean.FALSE;
+
+        // create the ServerSocket to listen to incoming messages
+        try
+            {
+            serverSocket = new ServerSocket( port, n_incoming );
+            }
+        catch( IOException e )
+            {
+            state.output.fatal( "Could not start mailbox for incoming messages.  Perhaps the port (" + port + ") is bad?\n...or someone else already has it?");
+            }
+
+        // allocate the sockets and the readers (will be used in the near future)
+        inSockets = new Socket[ n_incoming ];
+        dataInput = new DataInputStream[ n_incoming ];
+        incomingIds = new String[ n_incoming ];
+
+        // allocate the status of the different readers
+        running = new boolean[ n_incoming ];
+
+        }
+
+    /** The main functionality of the mailbox: waiting for incoming messages and dealing with the incoming immigrants */
+    public void run()
+        {
+
+        // wait for the "n_incoming" incoming connections from different islands, and initialize
+        // the sockets and the readers to communicate with (receive messages from) them. All the
+        // sockets are set to be non-blocking, such that they can be checked alternatively without
+        // waiting for messages on a particular one.
+        for( int x = 0 ; x < n_incoming ; x++ )
+            {
+            try
+                {
+                inSockets[x] = serverSocket.accept();
+
+                DataOutputStream dataOutput;
+
+                if( compressedCommunication )
+                    {
+                    /*
+                      dataInput[x] = new DataInputStream(new CompressingInputStream(inSockets[x].getInputStream()));
+                      dataOutput = new DataOutputStream(new CompressingOutputStream(inSockets[x].getOutputStream()));
+                    */
+                    OutputStream compressedo = Output.makeCompressingOutputStream(inSockets[x].getOutputStream());
+                    InputStream compressedi = Output.makeCompressingInputStream(inSockets[x].getInputStream());
+                    if (compressedi == null || compressedo == null) 
+                        state.output.fatal( "You do not appear to have JZLib installed on your system, and so may must have compression turned off for IslandExchange.  "+ 
+                            "To get JZLib, download from the ECJ website or from http://www.jcraft.com/jzlib/");
+
+                    dataInput[x] = new DataInputStream(compressedi);
+                    dataOutput = new DataOutputStream(compressedo);
+                    }
+                else
+                    {
+                    dataInput[x] = new DataInputStream(inSockets[x].getInputStream());
+                    dataOutput = new DataOutputStream(inSockets[x].getOutputStream());
+                    }
+
+                // send my id, then read an id
+                dataOutput.writeUTF(myId);
+                dataOutput.flush();
+                incomingIds[x] = dataInput[x].readUTF().trim();    
+
+                state.output.message( "Island " + incomingIds[x] + " connected to my mailbox" );
+
+                // set the socket to non-blocking
+                inSockets[x].setSoTimeout( CHECK_TIMEOUT );
+                running[x] = true;
+                }
+            catch (IOException e)
+                {
+                running[x] = false;
+                state.output.fatal( "An exception was generated while creating communication structures for island " + x + ".  Here it is: " + e );
+                }
+            }
+
+        state.output.message( "All islands have connected to my client." );
+
+        // variable used for deciding (based on the synchronized variable "syncVar") when to exit
+        boolean shouldExit = false;
+
+        // enter the main loop
+        do
+            {
+
+            // wait some (do not check all the time, cause it would be a waste of time and computational resources)
+            try
+                {
+                Thread.sleep( SLEEP_BETWEEN_CHECKING_FOR_IMMIGRANTS );
+                }
+            catch( InterruptedException e )
+                {
+                }
+
+            // for each of the connections established with the islands
+            for( int x = 0 ; x < n_incoming ; x++ )
+                {
+                if( running[x] )
+                    {
+                    try
+                        {
+                        // enter an infinite loop to receive all the messages form the "x"s island
+                        // it will exit the loop as soon as there are no more messages coming from
+                        // the "x"s island (non-blocking socket)
+                        while( true )
+                            {
+                            // read the subpopulation where the immigrants need to be inserted. In case there
+                            // is no incoming message, an exception will be generated and the infinite loop
+                            // will be exited (the mailbox will search the next socket (communication link)
+                            // for incoming messages
+                            int subpop = dataInput[x].readInt();
+                            
+                            // if it gets to this point, it means that a number of individuals will be sent
+                            // it is the time to set up the receiving storages
+                            
+                            // set the socket to blocking for reading the individuals
+                            try
+                                {
+                                inSockets[x].setSoTimeout( 0 );
+                                }
+                            catch( SocketException e )
+                                {
+                                state.output.warning( "Could not set the socket to blocking while receiving individuals in the mailbox." );
+                                }
+                            
+                            // how many individuals will be received in the current dialogue?
+                            int how_many_to_come = dataInput[x].readInt();
+                            
+                            if (chatty) state.output.message( "Receiving " + how_many_to_come + " immigrants for subpopulation "  + subpop + " from island " + incomingIds[x]);
+
+                            // synchronize on the immigrants (such that other threads cannot access it during its
+                            // being modified)
+                            synchronized( immigrants )
+                                {
+                                
+                                // in case the immigrants buffer was emptied, the person2die is not reset (it is not public)
+                                // so we have to reset it now
+                                if( nImmigrants[subpop] == 0 ) // if it was reset
+                                    person2die[subpop] = 0; // reset the person2die[x]
+                                
+                                // loop in order to receive all the incoming individuals in the current dialogue
+                                for( int ind = 0 ; ind < how_many_to_come ; ind++ )
+                                    {
+                                    // read the individual
+                                    try
+                                        {
+                                        // read the emigrant in the storage
+                                        immigrants[subpop][person2die[subpop]] = state.population.subpops[subpop].species.
+                                            newIndividual( state, dataInput[x] );
+
+                                        //state.output.message( "Individual received." );
+                                        
+                                        // increase the queue index
+                                        if( person2die[subpop] == immigrants[subpop].length - 1 )
+                                            person2die[subpop] = 0;
+                                        else
+                                            person2die[subpop]++;
+                                        
+                                        // can increment it without synchronization, as we do synchronization on the immigrants
+                                        if( nImmigrants[subpop] < immigrants[subpop].length )
+                                            nImmigrants[subpop]++;
+
+                                        }
+                                    catch( IOException e )
+                                        {
+                                        // i hope it will also never happen :)
+                                        state.output.message( "IO exception while communicating with an island" );
+                                        running[x] = false;
+                                        continue;
+                                        }
+                                    catch( NumberFormatException e )
+                                        {
+                                        // it happens when the socket is closed and cannot be doing any reading
+                                        state.output.message( "IO exception while communicating with an island" );
+                                        running[x] = false;
+                                        continue;
+                                        }
+                                    }
+                                } // end synchronized block on "immigrants"
+                            
+                            // set the socket to non-blocking (after current set of immigrants is over)
+                            try
+                                {
+                                inSockets[x].setSoTimeout( CHECK_TIMEOUT );
+                                }
+                            catch( SocketException e )
+                                {
+                                state.output.warning( "Could not set the socket to non-blocking while receiving individuals in the mailbox." );
+                                }
+                            }
+                        }
+                    catch( InterruptedIOException e )
+                        {
+                        // here everything is ok
+                        // just that there were no messages
+                        }
+                    catch( IOException e )
+                        {
+                        // now this is not nice
+                        // report the error so that the programmer can fix it (hopefully)
+                        state.output.message( "IO exception while communicating with an island" );
+                        running[x] = false;
+                        }
+                    catch( NumberFormatException e )
+                        {
+                        // error received when some sockets break
+                        state.output.message( "Socket closed" );
+                        running[x] = false;
+                        }
+                    }
+                }
+
+            // again with synchronization, try to access the syncVar to check whether the mailbox needs to finish
+            // running (maybe some other island already found the perfect individual, or the resources of the current
+            // run have been wasted)
+            synchronized( syncVar )
+                {
+                // get the value of the syncVar. If it is true, we should exit.
+                shouldExit = syncVar.booleanValue();
+                }
+            }
+        while( !shouldExit );
+
+        // close the sockets (don't care about the running, but deal with exceptions)
+        try
+            {
+            // close the ServerSocket
+            serverSocket.close();
+            }
+        catch( IOException e )
+            {
+            }
+        for( int x = 0 ; x < n_incoming ; x++ )
+            {
+            try
+                {
+                // close the sockets to communicate (receive messages) with the other islands
+                inSockets[x].close();
+                }
+            catch( IOException e )
+                {
+                continue;
+                }
+            }
+
+        }
+
+    /**
+       Method used to shutdown the mailbox. What it does is that it closes all communication links (sockets)
+       and sets the syncVar to true (such that if the run() method is run on another thread, it will exit the
+       loop and terminate.
+    */
+    public void shutDown()
+        {
+
+        // set the syncVar to true (such that if another thread executes this.run(), it will exit the main loop
+        // (hopefully, the information from the server was correct
+        synchronized( syncVar )
+            {
+            syncVar = Boolean.TRUE;
+            }
+
+        }
+
+    /**
+       Return the port of the ServerSocket (where the islands where the other islands should
+       connect in order to send their emigrants).
+    */
+    public int getPort()
+        {
+        // return the port of the ServerSocket
+        return serverSocket.getLocalPort();
+        }
+
+    }
+
+/**
+   The IslandExchangeServer is the class that manages the main server that coordinates all the islands. The class
+   implements Runnable (for running on a different thread).
+*/
+class IslandExchangeServer implements Runnable
+    {
+    
+    /*
+
+      The server-specific parameters look roughly like this:
+
+      exch.server-port = 8021
+      exch.num-islands = 3
+      exch.island.0.id = SurvivorIsland
+      exch.island.0.num-mig = 1
+      exch.island.0.mig.0 = GilligansIsland
+      exch.island.0.size = 5
+      exch.island.0.mod = 2
+      exch.island.0.start = 4
+      exch.island.1.id = GilligansIsland
+      exch.island.1.mod = 1
+      exch.island.1.start = 2
+      exch.island.1.size = 10
+      exch.island.1.num-mig = 2
+      exch.island.1.mig.0 = SurvivorIsland
+      exch.island.1.mig.1 = GilligansIsland
+      exch.island.2.id = BermudaIsland
+      exch.island.2.mod = 2
+      ...
+    */
+
+    //// Server information
+
+    /** The server port */
+    public static final String P_SERVER_PORT = "server-port";
+
+    /** The number of islands */
+    public static final String P_NUM_ISLANDS = "num-islands";
+
+    /** The parameter for the island's information */
+    public static final String P_ISLAND = "island";
+
+    /** The id */
+    public static final String P_ID = "id";
+
+    // The number of islands that will send emigrants to the current island
+    public static final String P_NUM_INCOMING_MIGRATING_COUNTRIES = "num-incoming-mig";
+
+    /** The number of islands where emigrants will be sent */
+    public static final String P_NUM_MIGRATING_COUNTRIES = "num-mig";
+
+    /** the parameter for migrating islands' ids */
+    public static final String P_MIGRATING_ISLAND = "mig";
+
+    /** The size of the mailbox (for each of the subpopulations) */
+    public static final String P_MAILBOX_CAPACITY = "mailbox-capacity";
+
+    /** The parameter for the modulo (how many generations should pass between consecutive sendings of individuals */
+    public static final String P_MODULO = "mod";
+
+    /** The number of emigrants to be sent */
+    public static final String P_SIZE = "size";
+
+    /** How many generations to pass at the beginning of the evolution before the first emigration from the current island */
+    public static final String P_OFFSET = "start";
+
+    /** Whether the execution should be synchronous or asynchronous */
+    public static final String P_SYNCHRONOUS = "sync";
+
+    /** The run message to be sent to the clients */
+    public static final String RUN = "run";
+
+    /** How much to wait for the found message (on a non-blocking socket) */
+    public static final int FOUND_TIMEOUT = 100;
+
+    /** How much to sleep between checking for a FOUND message */
+    public static final int SLEEP_TIME = 100;
+
+    /** The final message to be sent to all islands when an individual has been found */
+    public static final String GOODBYE = "bye-bye";
+
+    /** The found message */
+    public static final String FOUND = IslandExchange.FOUND;
+
+    /** The okay message */
+    public static final String OKAY = IslandExchange.OKAY;
+
+    /** The synchronize message */
+    public static final String SYNC = IslandExchange.SYNC;
+
+/** A class indicating all the information the server knows about
+    a given island, including its mod, size, offset, and all the
+    migrating islands it hooks to, etc. */
+    public class IslandExchangeIslandInfo
+        {
+        /** how often to send individuals */
+        public int modulo;
+        /** the mailbox capacity (for each of the subpopulations) */
+        public int mailbox_capacity;
+        /** what generation to start sending individuals */
+        public int offset;
+        // how many individuals to send
+        public int size;
+        // to how many islands to send individuals
+        public int num_mig;
+        // the ids of the contries to send individuals to
+        public String[] migrating_island_ids;
+        // how many islands will send individuals to the mailbox
+        public int num_incoming;
+
+        // also later filled in:
+        // the address of the mailbox where to receive information
+        public String address;
+        // the port of the mailbox
+        public int port;
+        }
+
+    // The number of islands in the topology
+    int numIslands;
+
+    // The port of the server
+    int serverPort;
+
+    // the server's socket
+    ServerSocket serverSocket;
+
+    // Hashtable for faster lookup of information regarding islands
+    Hashtable info;
+
+    // Hashtable to count how many islands send individuals to each of the islands
+    Hashtable info_immigrants;
+
+    EvolutionState state;
+
+    // Index of island ids sorted by parameter file
+    String[] island_ids;
+    
+    // Index of island ids sorted by order of connection
+    String[] connected_island_ids;
+
+
+    // variables used if the execution is synchronous
+    // int global_modulo, global_offset;
+    boolean synchronous;
+
+    // how many individuals asked to be synchronized (when it reaches the total number of
+    // running clients, the server resets this variable and allows everybody to continue running)
+    boolean[] who_is_synchronized;
+
+    /** This setup should get called from the IslandExchange setup method. */
+    public void setupServerFromDatabase(final EvolutionState state_p, final Parameter base)
+        {
+
+        // Store the evolution state for further use in other functions ( ie. run )
+        state = state_p;
+
+        // Don't bother with getting the default base -- we're a singleton!
+
+        Parameter p;
+
+        // get the number of islands
+        p = base.push( P_NUM_ISLANDS );
+        numIslands = state.parameters.getInt( p, null, 1 );
+        if( numIslands == 0 )
+            state.output.fatal( "The number of islands must be >0.", p );
+
+        // get the port of the server
+        p = base.push( P_SERVER_PORT );
+        serverPort = state.parameters.getInt( p, null, 1 );
+        if( serverPort == 0 )
+            state.output.fatal( "The server port must be >0.", p );
+        
+        // information on the islands = hashtable of ID and socket information
+        info = new Hashtable( numIslands );
+
+        // initialize the hash table to count how many islands send individuals
+        // to each of the islands
+        info_immigrants = new Hashtable( numIslands );
+
+        // allocate the ids sorted by parameter file
+        island_ids = new String[ numIslands ];
+        
+        // allocate the ids sorted by connection
+        connected_island_ids = new String[ numIslands ] ;
+
+        // check whether the execution is synchronous or asynchronous
+        // if it is synchronous, there should be two parameters in the parameters file:
+        // the global modulo and offset (such that the islands coordinate smoothly)
+        p = base.push( P_SYNCHRONOUS );
+
+        // get the value of the synchronous parameter (default is false)
+        synchronous = state.parameters.getBoolean( p, null, false );
+
+        // if synchronous, read the other two global parameters
+        if( synchronous )
+            {
+            state.output.message( "The communication will be synchronous." );
+
+/*
+// get the global modulo
+p = base.push( P_MODULO );
+global_modulo = state.parameters.getInt( p, null, 1 );
+if( global_modulo == 0 )
+state.output.fatal( "Parameter not found, or it has an incorrect value.", p );
+            
+// get the global offset
+p = base.push( P_OFFSET );
+global_offset = state.parameters.getInt( p, null, 0 );
+if( global_offset == -1 )
+state.output.fatal( "Parameter not found, or it has an incorrect value.", p );
+*/
+            }
+        else
+            {
+
+            state.output.message( "The communication will be asynchronous." );
+
+            }
+
+        // get a new local base
+        Parameter islandBase = base.push( P_ISLAND );
+
+        // load the island topology
+        for( int x = 0 ; x < numIslands ; x++ )
+            {
+
+            IslandExchangeIslandInfo ieii = new IslandExchangeIslandInfo();
+
+            Parameter localBase = islandBase.push( "" + x );
+
+            // get the id of the current island
+            p = localBase.push( P_ID );
+            island_ids[x] = state.parameters.getStringWithDefault( p, null, "" );
+            if( island_ids[x].equals("") )
+                state.output.fatal( "Parameter not found.", p );
+
+            // get the mailbox capacity of the imigration from the current island
+            p = localBase.push( P_MAILBOX_CAPACITY );
+            ieii.mailbox_capacity = state.parameters.getInt( p, base.push(P_MAILBOX_CAPACITY), 0 );
+            if( ieii.mailbox_capacity == -1 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p, base.push(P_MAILBOX_CAPACITY) );
+
+            // get the size of the imigration from the current island
+            p = localBase.push( P_SIZE );
+            ieii.size = state.parameters.getInt( p, base.push(P_SIZE), 0 );
+            if( ieii.size == -1 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p, base.push(P_SIZE) );
+
+            // if synchronous execution, use the global modulo and offset
+            /* if( synchronous )
+               {
+               ieii.modulo = global_modulo;
+               ieii.offset = global_offset;
+               }
+               else
+               {*/
+            // get the modulo of the imigration from the current island
+            p = localBase.push( P_MODULO );
+            ieii.modulo = state.parameters.getInt( p, base.push(P_MODULO), 1 );
+            if( ieii.modulo == 0 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p , base.push(P_MODULO));
+
+            // get the offset of the imigration from the current island
+            p = localBase.push( P_OFFSET );
+            ieii.offset = state.parameters.getInt( p, base.push(P_OFFSET), 0 );
+            if( ieii.offset == -1 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p, base.push(P_OFFSET) );
+            /*     } */
+
+            // mark as uninitialized
+            ieii.port = -1;
+
+            // insert the id in the hashset with the ids of the islands
+            info.put( island_ids[x], ieii );
+            }
+
+        // get the information on destination islands (with checking for consistency)
+        for( int x = 0 ; x < numIslands ; x++ )
+            {
+
+            IslandExchangeIslandInfo ieii = (IslandExchangeIslandInfo)info.get( island_ids[x] );
+
+            if( ieii == null )
+                {
+                state.output.error( "Inexistent information for island " + island_ids[x] + " stored in the server's information database." );
+                continue;
+                }
+
+            Parameter localBase = islandBase.push( "" + x );
+
+            // get the number of islands where individuals should be sent
+            p = localBase.push( P_NUM_MIGRATING_COUNTRIES );
+            ieii.num_mig = state.parameters.getInt( p, null, 0 );
+            if( ieii.num_mig == -1 )
+                state.output.fatal( "Parameter not found, or it has an incorrect value.", p );
+
+            // if there is at least 1 destination islands
+            if( ieii.num_mig > 0 )
+                {
+
+                // allocate the storage for ids
+                ieii.migrating_island_ids = new String[ ieii.num_mig ];
+
+                // store a new base parameter
+                Parameter ll;
+                ll = localBase.push( P_MIGRATING_ISLAND );
+
+                // for each of the islands
+                for( int y = 0 ; y < ieii.num_mig ; y++ )
+                    {
+
+                    // read the id & check for errors
+                    ieii.migrating_island_ids[y] = state.parameters.getStringWithDefault( ll.push(""+y), null, null );
+                    if( ieii.migrating_island_ids[y] == null )
+                        state.output.fatal( "Parameter not found.", ll.push(""+y) );
+                    else if( !info.containsKey( ieii.migrating_island_ids[y] ) )
+                        state.output.fatal( "Unknown island.", ll.push(""+y) );
+                    else
+                        {
+                        // insert this knowledge into the hashtable for counting how many islands
+                        // send individuals to each island
+                        Integer integer = (Integer)info_immigrants.get( ieii.migrating_island_ids[y] );
+                        if( integer == null )
+                            info_immigrants.put( ieii.migrating_island_ids[y],
+                                new Integer(1) );
+                        else
+                            info_immigrants.put( ieii.migrating_island_ids[y],
+                                new Integer( integer.intValue() + 1 ) );
+                        }
+                    }
+                }
+
+            // save the information back in the hash table
+            // info.put( island_ids[x], ieii );                         // unneccessary -- Sean
+
+            }
+
+        for( int x = 0 ; x < numIslands ; x++ )
+            {
+
+            IslandExchangeIslandInfo ieii = (IslandExchangeIslandInfo)info.get( island_ids[x] );
+
+            if( ieii == null )
+                {
+                state.output.fatal( "Inexistent information for island " + island_ids[x] + " stored in the server's information database." );
+                }
+
+            Integer integer = (Integer)info_immigrants.get( island_ids[x] );
+
+            // if the information does not exist in the hasthable,
+            // it means no islands send individuals there
+            if( integer == null )
+                ieii.num_incoming = 0;
+            else
+                ieii.num_incoming = integer.intValue();
+
+            // save the information back in the hash table
+            // info.put( island_ids[x], ieii );                 // unneccessary -- Sean
+
+            }
+
+        // allocate and reset this variable to false
+        who_is_synchronized = new boolean[ numIslands ];
+
+        for( int x = 0 ; x < numIslands ; x++ )
+            who_is_synchronized[x] = false;
+
+        }
+
+    /** The main function running in the thread */
+    public void run()
+        {
+
+        // sockets to communicate to each of the islands
+        Socket[] con = new Socket[numIslands];
+
+        // readers and writters for communication with each island
+        DataInputStream[] dataIn = new DataInputStream[numIslands];
+        DataOutputStream[] dataOut = new DataOutputStream[numIslands];
+
+
+
+        // whether each client is working (and communicating with the server) or not
+        boolean[] clientRunning = new boolean[numIslands];
+
+        // initialize the running status of all clients
+        for( int x = 0 ; x < numIslands ; x++ )
+            clientRunning[x] = true;
+
+        try
+            {
+            // create a server
+            serverSocket = new ServerSocket(serverPort,numIslands);
+            }
+        catch ( IOException e )
+            {
+            state.output.fatal( "Error creating a socket on port " + serverPort );
+            }
+
+        // for each of the islands
+        for(int x=0;x<numIslands;x++)
+            {
+            try
+                {
+                // set up connection with the island
+                con[x] = serverSocket.accept();
+
+                // initialize the reader and the writer
+                dataIn[x] = new DataInputStream(con[x].getInputStream());
+                dataOut[x] = new DataOutputStream(con[x].getOutputStream());
+
+                // read the id
+                connected_island_ids[x] = dataIn[x].readUTF().trim();
+
+                state.output.message( "Island " + connected_island_ids[x] + " logged in" );
+
+                // check whether the id appears in the information at the server
+                if( !info.containsKey( connected_island_ids[x] ) )
+                    {
+                    state.output.error( "Incorrect ID (" + connected_island_ids[x] + ")" );
+                    clientRunning[x] = false;
+                    continue;
+                    }
+
+                IslandExchangeIslandInfo ieii = (IslandExchangeIslandInfo)info.get( connected_island_ids[x] );
+
+                // redundant check, i know....
+                if( ieii == null )
+                    {
+                    state.output.error( "Can't get IslandExchangeInfo for " + connected_island_ids[x]  );
+                    clientRunning[x] = false;
+                    continue;
+                    }
+
+                // check whether an island with this id already registered with the server
+                if( ieii.port >= 0 )
+                    {
+                    state.output.error( "Multiple islands are claiming the same ID (" + connected_island_ids[x] + ")" );
+                    clientRunning[x] = false;
+                    continue;
+                    }
+            
+                // send the number of ids that will be send through the communication link
+                dataOut[x].writeInt( ieii.num_incoming );
+
+                // send the capacity of the mailbox
+                dataOut[x].writeInt( ieii.mailbox_capacity );
+                                
+                dataOut[x].flush();
+
+                // read the address and port of the island
+                ieii.address = dataIn[x].readUTF().trim();
+                ieii.port = dataIn[x].readInt();
+
+                state.output.message( "" + x + ": Island " + connected_island_ids[x] + " has address " +
+                    ieii.address + " : " + ieii.port );
+
+                // re-insert the information in the hash table
+                // info.put( id, ieii );                                // unnecessary -- Sean
+                }
+            catch( IOException e )
+                {
+                state.output.error( "Could not open connection #" + x );
+                clientRunning[x] = false;
+                }
+            }
+
+        state.output.exitIfErrors();
+
+        // By this time, all mailboxes have been started and
+        // they should be waiting for incoming messages. this is because
+        // in order to send the server the information about the address and port
+        // of the mailbox, they have to start them first. This is the reason
+        // that makes us be able to start connecting without other synchronization
+        // stuff right at this point.
+
+        // Now, I think, we've got a 1:1 mapping of keys to items in the info hashtable
+        // So we tell everyone who they will communicate to
+
+        for( int x = 0 ; x < numIslands ; x++ )
+            {
+            if( clientRunning[x] )
+                {
+                IslandExchangeIslandInfo ieii = (IslandExchangeIslandInfo)info.get( connected_island_ids[x] );
+
+                if( ieii == null )
+                    {
+                    state.output.warning( "There is no information about island " + connected_island_ids[x]);
+                    clientRunning[x] = false;
+                    continue;
+                    }
+
+                try
+                    {
+                    // send the synchronous, modulo, offset and size information to the current islands
+                    if( synchronous )
+                        dataOut[x].writeInt( 1 );
+                    else
+                        dataOut[x].writeInt( 0 );
+                    dataOut[x].writeInt( ieii.modulo );
+                    dataOut[x].writeInt( ieii.offset );
+                    dataOut[x].writeInt( ieii.size );
+
+                    // send the number of address-port pairs that will be sent
+                    dataOut[x].writeInt( ieii.num_mig );
+
+                    for( int y = 0 ; y < ieii.num_mig ; y++ )
+                        {
+                        IslandExchangeIslandInfo temp;
+
+                        temp = (IslandExchangeIslandInfo)info.get( ieii.migrating_island_ids[y] );
+
+                        if( temp == null )
+                            {
+                            state.output.warning( "There is incorrect information on the island " + connected_island_ids[x]  );
+                            dataOut[x].writeUTF( " " );
+                            dataOut[x].writeInt( -1 );
+                            }
+                        else
+                            {
+                            state.output.message( "Island " + connected_island_ids[x] + " should connect to island " +
+                                ieii.migrating_island_ids[y] + " at " + temp.address + " : " + temp.port );
+                            dataOut[x].writeUTF( temp.address );
+                            dataOut[x].writeInt( temp.port );
+                            }
+                        }
+                    dataOut[x].flush();
+                    }
+                catch( IOException e )
+                    {
+                    // other errors while reading
+                    state.output.message("Server: Island " + island_ids[x] + " dropped connection");
+                    clientRunning[x] = false;
+                    continue;
+                    }
+                catch( NullPointerException e )
+                    {
+                    // other errors while reading
+                    state.output.message("Server: Island " + island_ids[x] + " dropped connection");
+                    clientRunning[x] = false;
+                    try
+                        {
+                        dataIn[x].close();
+                        dataOut[x].close();
+                        con[x].close();
+                        }
+                    catch( IOException f )
+                        {
+                        }
+                    continue;
+                    }
+                }
+            }
+
+        try
+            {
+            // Next we wait until everyone acknowledges this
+            for(int x=0;x<dataIn.length;x++)
+                {
+                dataIn[x].readUTF();
+                }
+
+            // Now we tell everyone to start running
+            for(int x=0;x<dataOut.length;x++)
+                {
+                dataOut[x].writeUTF( RUN );
+                dataOut[x].flush();
+                }
+            }
+        catch( IOException e )
+            {
+            }
+
+        // Okay we've sent off our information.  Now we wait until a client
+        // tells us that he's found the solution, or until all the clients
+        // have broken connections 
+        
+        for(int x=0;x<con.length;x++)
+            {
+            try
+                {
+                con[x].setSoTimeout(FOUND_TIMEOUT);
+                }
+            catch( SocketException e )
+                {
+                state.output.error( "Could not set the connect with island " + x + " to non-blocking." );
+                }
+            }
+
+        boolean shouldExit = false;
+
+        while(!shouldExit)
+            {
+            // check whether there is at least one client running
+            // otherwise the server might continue functioning just because the last client crashed or finished connection
+            shouldExit = true;
+            for( int x = 0 ; x < dataOut.length ; x++ )
+                if( clientRunning[x] )
+                    {
+                    shouldExit = false;
+                    break;
+                    }
+            if( shouldExit )
+                break;
+
+            // sleep a while
+            try
+                {
+                Thread.sleep(SLEEP_TIME);
+                }
+            catch( InterruptedException e )
+                {
+                }
+
+            String ww;
+
+            for(int x=0;x<dataOut.length;x++)
+                {
+                if (clientRunning[x])
+                    {
+
+                    // initialize ww
+                    ww = "";
+
+                    // check to see if he's still up, and if he's
+                    // sent us a "I found it" signal
+                    try
+                        {
+                        ww = dataIn[x].readUTF().trim();
+                        }
+                    catch( InterruptedIOException e )
+                        {
+                        // means that it run out of time and got no message,
+                        // so it should just continue with the other sockets
+                        continue;
+                        }
+                    catch( IOException e )
+                        {
+                        // other errors while reading
+                        state.output.message("Server: Island " + island_ids[x] + " dropped connection");
+                        clientRunning[x] = false;
+                        continue;
+                        }
+                    catch( NullPointerException e )
+                        {
+                        // other errors while reading
+                        state.output.message("Server: Island " + island_ids[x] + " dropped connection");
+                        clientRunning[x] = false;
+                        try
+                            {
+                            dataIn[x].close();
+                            dataOut[x].close();
+                            con[x].close();
+                            }
+                        catch( IOException f )
+                            {
+                            }
+                        continue;
+                        }
+
+                    if ( ww == null )  // the connection has been broken
+                        {
+                        state.output.message("Server: Island " + island_ids[x] + " dropped connection");
+                        clientRunning[x] = false;
+                        try
+                            {
+                            dataIn[x].close();
+                            dataOut[x].close();
+                            con[x].close();
+                            }
+                        catch( IOException e )
+                            {
+                            }
+                        }
+                    else if( ww.equals( FOUND ) ) // he found it!
+                        {
+                        // inform everyone that they need to shut down --
+                        // we do not need to wrap
+                        // our println statements in anything, they just
+                        // return even if the client has broken the connection
+                        for(int y=0;y<dataOut.length;y++)
+                            {
+                            if (clientRunning[y])
+                                {
+                                try
+                                    {
+                                    dataOut[y].writeUTF(GOODBYE);
+                                    dataOut[y].close();
+                                    dataIn[y].close();
+                                    con[y].close();
+                                    }
+                                catch( IOException e )
+                                    {
+                                    }
+                                }
+                            }
+                        // now we can just get out of all this and
+                        // quit the thread 
+                        shouldExit=true;
+                        break;
+                        }
+                    else if( ww.equals( SYNC ) )
+                        {
+                        who_is_synchronized[x] = true;
+
+                        boolean complete_synchronization = true;
+
+                        for( int y = 0 ; y < numIslands ; y++ )
+                            complete_synchronization = complete_synchronization &&
+                                ( ( ! clientRunning[y] ) || who_is_synchronized[y] );
+
+                        // if the number of total running islands is smaller than the
+                        // number of islands that ask for synchronization, let them continue
+                        // running
+                        if( complete_synchronization )
+                            {
+
+                            for( int y = 0 ; y < numIslands ; y++ )
+                                {
+                                // send the okay message (the client can continue executing)
+                                if( clientRunning[y] )
+                                    try
+                                        {
+                                        dataOut[y].writeUTF( OKAY );
+                                        dataOut[y].flush();
+                                        }
+                                    catch( IOException e ) {}
+                                // reset the who_is_synchronized variable
+                                who_is_synchronized[y] = false;
+                                }
+                            }
+
+                        }
+                    }
+                }
+            }
+        state.output.message( "Server Exiting" );    
+        }
+
+    /** Here we spawn off the thread on ourselves */
+    public Thread spawnThread()
+        {
+        Thread thread = new Thread( this );
+        thread.start();
+        return thread;
+        }
+
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/README	(revision 6152)
@@ -0,0 +1,155 @@
+This package contains two implementations of the Exchange facility in ECJ to
+perform island models.  The first implementation:
+
+	ec.exchange.InterPopulationExchange
+
+... works within a single evolutionary process, and treats each subpopulation 
+as a separate "island", performing a synchronous island model among the
+subpopulations.  This is mostly of academic interest, as it only runs on a 
+single evolutionary process.  Note that it's also incompatable with other
+uses of subpopulations, such as coevolution.  See the inter.params file for
+an example.
+
+
+The second implementation:
+
+	ec.exchange.IslandExchange
+
+... is an elaborate multi-process, multi-machine island model.  The system
+can perform both synchronous and asynchronous island models of any topology
+you like.  It is graceful in handling islands which disappear but cannot handle
+new islands or replacement islands.  The system is (or should be!) entirely
+compatible with the distributed evaluator, so you can have multiple islands,
+each with their own little master/slave evaluation facility.  The system also
+handles (or should) checkpointing properly.
+
+IslandExchange requires that you define an ECJ process as a "server" and
+the others as "clients".  If you like, a process can serve both as a server
+and as a client.  The clients all connect to the server and are told by the
+server how to hook up with one another in the desired topology.  The server
+also communicates signals to the clients, notably telling them to shut 
+themselves down when one of the clients has discovered an optimal solution.
+
+The directories
+
+	3-Island	8-Island
+
+...contain examples of 3- and 8-island models where the server is also a
+client.  The directory
+
+	2-Island
+
+... contains an example of a simple 2-Island model with a separate server 
+(thus 2 clients and 1 server).  Note that to run the server separately, you
+fire up ECJ not with ec.Evolve but with ec.exchange.IslandExchange.  See the
+README file in that directory for more information.
+
+There are a number of options in the island model, described more fully
+in the IslandExchange class documentation.  Here's a quick overview of some
+of them.
+
+A process is told to be a server (possibly in addition to being a client) with
+the parameter
+
+	exch.i-am-server=true
+
+Servers work by listening in on a socket port.  You specify this port as an
+integer, ideally above 2000 or so.  The clients will all need to know this
+port number as well.  The port is defined as:
+
+	exch.server-port= ...
+
+Communication between clients is by default compressed.  Note that Java's
+compression routines are broken (they don't support PARTIAL_FLUSH), so we
+have to rely on a third-party library called JZLIB.  You can get the jar
+file for this library on the ECJ main web page or at
+http://www.jcraft.com/jzlib/
+
+To turn compression OFF for some reason, you'd say
+
+	exch.compression = false
+
+A synchronous island model (where all islands send and receive at the same
+time) is defined by the server parameter:
+
+	exch.sync=true
+
+If this is the case, then the server can specify when the at what generation
+the exchanges begin with
+
+	exch.start= ...
+
+... and also specify the interval between exchanges as:
+
+	exch.mode= ...
+
+By default, ECJ does *asynchronous* exchanges instead, where each island is
+told independently what generation it should start at and what interval it
+should use, and the islands are free to go at their own pace rather than wait
+for the other islands synchronously.  
+
+Islands each have a "mailbox" which receives incoming individuals from the 
+other islands, and after breeding they check and empty that mailbox, 
+replacing some individuals in the current population with the incoming 
+immigrants.  The selection procedure for the individuals to be replaced is by 
+default random selection, but you can change that (see below).
+
+The server defines the number of islands as:
+
+	exch.num-islands= ...
+
+Each island is defined with several parameters in the server's parameter files.
+In the examples below, replace n with the numbers 0 through the number of
+islands (minus 1).
+
+	exch.island.n.id	The name of island number n (a string)
+	exch.island.n.num-mig	How many islands this island sends to.
+	exch.island.n.mig.m	The name of island number m that this island
+				sends to.  (m is a number from 0 to
+				exch.island.n.num-mig minus 1).
+	exch.island.n.size
+	exch.size (default)	How many individuals this island sends to
+				each of the other islands at one time.
+	exch.island.n.start	
+	exch.start (default)	What generation the island should start sending
+				(only used if asynchronous)
+	exch.island.n.mod	
+	exch.mod (default)	The interval between sends (only used with
+				asynchronous)
+	exch.island.n.mailbox-capacity	
+	exch.mailbox-capacity (default)	How large the island's mailbox should
+					be.  This should be large enough to
+					accept enough individuals from other
+					islands, but not so big that it's
+					larger than your population size!
+					The mailbox will overflow if full.
+					You'll need to tune this size if
+					you have some islands that are much
+					faster at sending out individuals
+					than others are at incorporating them.
+
+Once your server has defined all these topology elements, you just need to make
+some clients.  Client parameters are quite simple.  The primary ones are:
+
+	exch.server-addr	The IP address of the server, so the client
+				knows where to connect and get its marching
+				orders.
+	exch.server-port	The socket port of the server.
+	exch.client-port	The desired socket port of the client that
+				other clients will connect to it via to set up
+				the island model.  This should be different 
+				than server-port if you have a client which is
+				also a server.
+	exch.id			The name of the client's island.  The server
+				will use this name information to determine the
+				topology as above.
+	exch.select		The selection method used to pick individuals
+				to emigrate TO other islands.
+	exch.select-to-die	The selection method used to pick individuals
+				to be replaced by incoming immigrants.  By
+				default this is random selection.
+
+There's more than this, but it's sufficient to understand what's going on in
+the example directories.  For more description of how things work, see
+the IslandExchange class documentation.
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/exchange/inter.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/exchange/inter.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/exchange/inter.params	(revision 6152)
@@ -0,0 +1,98 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+#
+# The following is an example of Inter-subpopulation exchange
+# within the same process, using three subpopulations, 
+# with the GP Ant example. In the example below, we've set
+# up three subpopulations, and the exchange is as follows:
+# subpop 0 sends inds to subpops 1 and 2, subpop 1 sends
+# inds to subpop 2, and subpop 2 sends inds to subpop 0.
+# All three subpops start exchanging immediately (after
+# population initialization) and thereafter send every two
+# generations. They exchange 3 individuals each.
+#
+# If you're looking instead for multi-process, network island
+# models, see the 3-Island and 8-Island examples
+#
+
+parent.0 = ../app/ant/ant.params
+
+pop.subpops = 3
+
+pop.subpop.0 = ec.Subpopulation
+pop.subpop.0.size = 200
+pop.subpop.0.species = ec.gp.GPSpecies
+pop.subpop.0.species.fitness = ec.gp.koza.KozaFitness
+pop.subpop.0.species.ind = ec.gp.GPIndividual
+pop.subpop.0.duplicate-retries = 100
+pop.subpop.0.species.ind.numtrees = 1
+pop.subpop.0.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.0.tc = tc0
+pop.subpop.0.species.pipe = ec.breed.MultiBreedingPipeline
+pop.subpop.0.species.pipe.generate-max = false
+pop.subpop.0.species.pipe.num-sources = 2
+pop.subpop.0.species.pipe.source.0 = ec.gp.koza.CrossoverPipeline
+pop.subpop.0.species.pipe.source.0.prob = 0.9
+pop.subpop.0.species.pipe.source.1 = ec.breed.ReproductionPipeline
+pop.subpop.0.species.pipe.source.1.prob = 0.1
+
+pop.subpop.1 = ec.Subpopulation
+pop.subpop.1.size = 200
+pop.subpop.1.species = ec.gp.GPSpecies
+pop.subpop.1.species.fitness = ec.gp.koza.KozaFitness
+pop.subpop.1.species.ind = ec.gp.GPIndividual
+pop.subpop.1.duplicate-retries = 100
+pop.subpop.1.species.ind.numtrees = 1
+pop.subpop.1.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.1.species.ind.tree.0.tc = tc0
+pop.subpop.1.species.pipe = ec.breed.MultiBreedingPipeline
+pop.subpop.1.species.pipe.generate-max = false
+pop.subpop.1.species.pipe.num-sources = 2
+pop.subpop.1.species.pipe.source.0 = ec.gp.koza.CrossoverPipeline
+pop.subpop.1.species.pipe.source.0.prob = 0.9
+pop.subpop.1.species.pipe.source.1 = ec.breed.ReproductionPipeline
+pop.subpop.1.species.pipe.source.1.prob = 0.1
+
+pop.subpop.2 = ec.Subpopulation
+pop.subpop.2.size = 200
+pop.subpop.2.species = ec.gp.GPSpecies
+pop.subpop.2.species.fitness = ec.gp.koza.KozaFitness
+pop.subpop.2.species.ind = ec.gp.GPIndividual
+pop.subpop.2.duplicate-retries = 100
+pop.subpop.2.species.ind.numtrees = 1
+pop.subpop.2.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.2.species.ind.tree.0.tc = tc0
+pop.subpop.2.species.pipe = ec.breed.MultiBreedingPipeline
+pop.subpop.2.species.pipe.generate-max = false
+pop.subpop.2.species.pipe.num-sources = 2
+pop.subpop.2.species.pipe.source.0 = ec.gp.koza.CrossoverPipeline
+pop.subpop.2.species.pipe.source.0.prob = 0.9
+pop.subpop.2.species.pipe.source.1 = ec.breed.ReproductionPipeline
+pop.subpop.2.species.pipe.source.1.prob = 0.1
+
+exch = ec.exchange.InterPopulationExchange
+
+exch.subpop.0.select = ec.select.TournamentSelection
+exch.subpop.0.mod = 2
+exch.subpop.0.start = 0
+exch.subpop.0.size = 3
+exch.subpop.0.num-dest = 2
+exch.subpop.0.dest.0 = 1
+exch.subpop.0.dest.1 = 2
+
+exch.subpop.1.select = ec.select.TournamentSelection
+exch.subpop.1.mod = 2
+exch.subpop.1.start = 0
+exch.subpop.1.size = 3
+exch.subpop.1.num-dest = 1
+exch.subpop.1.dest.0 = 2
+
+exch.subpop.2.select = ec.select.TournamentSelection
+exch.subpop.2.mod = 2
+exch.subpop.2.start = 0
+exch.subpop.2.size = 3
+exch.subpop.2.num-dest = 1
+exch.subpop.2.dest.0 = 0
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ADF.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ADF.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ADF.java	(revision 6152)
@@ -0,0 +1,277 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * ADF.java
+ * 
+ * Created: Mon Oct 25 18:42:09 1999
+ * By: Sean Luke
+ */
+
+/**
+ * An ADF is a GPNode which implements an "Automatically Defined Function",
+ * as described in Koza II.  
+ *
+ * <p>In this system, the ADF facility consists of several classes: ADF,
+ * ADM, ADFStack, ADFContext, and ADFArgument. ADFs, and their cousins
+ * ADMs ("Automatically Defined Macros [Lee Spector]"), appear as
+ * typical function nodes in a GP tree.  However, they have a special
+ * <i>associated tree</i> in the individual's tree forest which 
+ * they evaluate as a kind of a "subfunction".
+ *
+ * <p>When an ADF is evaluated, it first evaluates all of its children
+ * and stores away their results.  It then evaluates its associated tree.
+ * In the associated tree may exist one or more <i>ADF Argument Terminals</i>,
+ * defined by the ADFArgument class.  These terminal nodes are associated
+ * with a single number which represents the "argument" in the original ADF
+ * which evaluated their tree.  When an Argument Terminal is evaluated,
+ * it returns the stored result for that child number in the parent ADF.
+ * Ultimately, when the associated tree completes its evaluation, the ADF
+ * returns that value.
+ *
+ * <p>ADMs work slightly differently.  When an ADM is evaluated, it
+ * immediately evaluates its associated tree without first evaluating
+ * any children.  When an Argument Terminal is evaluated, it evaluates
+ * the subtree of the appropriate child number in the parent ADM and returns
+ * that result.  These subtrees can be evaluated many times.  When the
+ * associated tree completes its evaluation, the ADM returns that value.
+ * 
+ * <p>Obviously, if you have Argument Terminals in a tree, that tree must
+ * be only callable by ADFs and ADMs, otherwise the Argument Terminals
+ * won't have anything to return.  Furthermore, you must make sure that
+ * you don't have an Argument Terminal in a tree whose number is higher
+ * than the smallest arity (number of arguments) of a calling ADF or ADM.
+ *
+ * <p>The mechanism behind ADFs and ADMs is complex, requiring two specially-
+ * stored stacks (contained in the ADFStack object) of ADFContexts.  For
+ * information on how this mechanism works, see ADFStack.
+ *
+ *
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tree</tt><br>
+ <font size=-1>int &gt;= 0</font></td>
+ <td valign=top>(The "associated tree" of the ADF)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>name</tt><br>
+ <font size=-1>String, can be undefined</font></td>
+ <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>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.adf
+
+ * @see ec.gp.ADFStack
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ADF extends GPNode
+    {
+    public static final String P_ADF = "adf";
+    public static final String P_ASSOCIATEDTREE = "tree";
+    public static final String P_FUNCTIONNAME = "name";
+
+    /** The ADF's associated tree */
+    public int associatedTree;
+
+    /** The "function name" of the ADF, to distinguish it from other GP
+        functions you might provide.  */
+    public String name;
+    public String name() { return name; }
+
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_ADF);
+        }
+
+    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(associatedTree);
+        dataOutput.writeUTF(name);
+        }
+         
+ 
+    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        associatedTree = dataInput.readInt();
+        name = dataInput.readUTF();
+        }
+
+    /** Returns name.hashCode() + class.hashCode() + associatedTree.  Hope
+        that's reasonably random. */
+
+    public int nodeHashCode()
+        {
+        return (this.getClass().hashCode() + name.hashCode() + associatedTree);
+        }
+
+    /** Determines node equality by comparing the class, associated tree, and
+        function name of the nodes. */
+    public boolean nodeEquals(final GPNode node)
+        {
+        if (!this.getClass().equals(node.getClass()) ||
+            children.length != node.children.length) return false;
+        ADF adf = (ADF)node;
+        return (associatedTree==adf.associatedTree && name.equals(adf.name));
+        }
+
+    /** 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! */
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        
+        // does the associated tree exist?
+        
+        if (associatedTree < 0 || associatedTree > typicalIndividual.trees.length)
+            state.output.error("The node " + toStringForError() + " of individual " + 
+                individualBase + " must have an associated tree that is >= 0 and < " + typicalIndividual.trees.length);
+        else
+            {
+            
+            // is the associated tree of the correct type?  Issue an error.
+            GPInitializer initializer = ((GPInitializer)state.initializer);
+            
+            if (!constraints(initializer).returntype.compatibleWith(initializer,
+                    typicalIndividual.trees[associatedTree].constraints(initializer).treetype))
+                state.output.error("The return type of the node " + toStringForError() 
+                    + " of individual " + 
+                    individualBase + "is not type-compatible with the tree type of its associated tree.");
+            
+            GPNode[][] funcs = 
+                typicalIndividual.trees[associatedTree].
+                constraints(initializer).functionset.nodes;
+                        
+            ADFArgument validArgument[] = new ADFArgument[children.length];
+
+            for(int w=0;w<funcs.length;w++)
+                {
+                // does the tree's function set have argument terminals 
+                // that are beyond what I can provide?  (issue an error)
+                
+                GPNode[] gpfi = funcs[w];
+                for (int x=0;x<gpfi.length;x++)
+                    if (gpfi[x] instanceof ADFArgument)
+                        {
+                        ADFArgument argument = (ADFArgument)(gpfi[x]);
+                        int arg = argument.argument;
+                        if (arg >= children.length)  // uh oh
+                            state.output.error("The node " +
+                                toStringForError() + 
+                                " in individual "  + 
+                                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 " 
+                                + gpfi[x].toStringForError()); 
+                        else
+                            {
+                            if (validArgument[arg]!=null && validArgument[arg]!=argument)  // got one already
+                                state.output.warning("There exists more than one Argument terminal for argument #" 
+                                    + arg + " for the node " +
+                                    toStringForError() + 
+                                    " in individual " + 
+                                    individualBase);
+                            else validArgument[arg] = argument;
+                            
+                            // is the argument terminal of the correct return type?  Issue an error.
+                            if (!gpfi[x].constraints(initializer).returntype.compatibleWith(initializer,
+                                    constraints(initializer).childtypes[arg]))
+                                state.output.error("The node " +
+                                    toStringForError() + 
+                                    " in individual " +
+                                    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 " 
+                                    + gpfi[x].toStringForError()); 
+                            }
+                        }
+                }
+
+            // does the tree's function set have fewer argument terminals
+            // than I can provide? (issue a warning)
+            
+            for (int x=0;x<children.length;x++)
+                if (validArgument[x] == null) 
+                    state.output.warning("There is no argument terminal for argument #" 
+                        + x + " for the node " 
+                        + toStringForError() + " in individual " + 
+                        individualBase);
+            
+            }
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // we don't know our name yet, (used in toStringForError(),
+        // which is used in GPNode's setup(...) method),
+        // so WE load parameters before our parent does.
+
+        Parameter def = defaultBase();
+
+        associatedTree = 
+            state.parameters.getInt(base.push(P_ASSOCIATEDTREE),def.push(P_FUNCTIONNAME),0);
+        if (associatedTree < 0)
+            state.output.fatal(
+                "ADF/ADM node must have a positive-numbered associated tree.",
+                base.push(P_ASSOCIATEDTREE),def.push(P_FUNCTIONNAME));
+
+        name = state.parameters.getString(base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
+        if (name == null || name.equals(""))
+            {
+            name = "ADF" + (associatedTree - 1);
+            state.output.warning("ADF/ADM node for Tree " + associatedTree + " has no function name.  Using the name " + name(),
+                base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
+            }
+                        
+        if (name.length() == 1)
+            {
+            state.output.warning("Using old-style ADF/ADM name.  You should change it to something longer and more descriptive, such as ADF" + name,
+                base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
+            }
+
+        // now we let our parent set up.  
+        super.setup(state,base);
+        }
+    
+    public String toString() { return name(); }
+    
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // get a context and prepare it
+        ADFContext c = stack.get();
+        c.prepareADF(this);
+
+        // evaluate my arguments and load 'em in 
+        for(int x=0;x<children.length;x++)
+            {
+            input.copyTo(c.arguments[x]);
+            children[x].eval(state,thread,c.arguments[x],
+                stack,individual,problem);
+            }
+
+        // Now push the context onto the stack.
+        stack.push(c);
+
+        // evaluate the top of the associatedTree
+        individual.trees[associatedTree].child.eval(
+            state,thread,input,stack,individual,problem);
+
+        // pop the context off, and we're done!
+        if (stack.pop(1) != 1)
+            state.output.fatal("Stack prematurely empty for " + toStringForError());
+        }
+            
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFArgument.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFArgument.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFArgument.java	(revision 6152)
@@ -0,0 +1,115 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * ADFArgument.java
+ * 
+ * Created: Tue Oct 26 16:14:09 1999
+ * By: Sean Luke
+ */
+
+/**
+ * An ADFArgument is a GPNode which represents an ADF's 
+ * <i>argument terminal</i>, its counterpart which returns argument
+ * values in its associated function tree.  In lil-gp this is called an
+ * ARG node.
+ *
+ * <p>Obviously, if you have Argument Terminals in a tree, that tree must
+ * be only callable by ADFs and ADMs, otherwise the Argument Terminals
+ * won't have anything to return.  Furthermore, you must make sure that
+ * you don't have an Argument Terminal in a tree whose number is higher
+ * than the smallest arity (number of arguments) of a calling ADF or ADM.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>arg</tt><br>
+ <font size=-1>int &gt;= 0</font></td>
+ <td valign=top>(The related argument position for the ADF Argument Node in the associated ADF)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.adf-argument
+
+ * @see ec.gp.ADF
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ADFArgument extends GPNode 
+    {
+    public static final String P_ADFARGUMENT = "adf-argument";
+    public final static String P_ARGUMENT = "arg";
+    public static final String P_FUNCTIONNAME = "name";
+    public int argument;
+        
+    /** The "function name" of the ADFArgument, to distinguish it from other GP
+        functions you might provide.  */
+    public String name;
+    public String name() { return name; }
+
+    
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_ADFARGUMENT);
+        }
+
+    public String toString() { return name(); }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+        
+        // make sure we don't have any children...
+        if (children.length!= 0) 
+            state.output.error("Incorrect number of children for ADF Argument terminal -- should be 0.  Check the constraints.",base,def);
+
+        argument = state.parameters.getInt(base.push(P_ARGUMENT),def.push(P_ARGUMENT),0);
+        if (argument < 0)
+            state.output.fatal("Argument terminal must have a positive argument number.",
+                base.push(P_ARGUMENT),def.push(P_ARGUMENT));
+
+        name = state.parameters.getString(base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
+        if (name == null || name.equals(""))
+            {
+            name = "ARG" + argument;
+            state.output.warning("ADFArgument node for argument " + argument + " has no function name.  Using the name " + name(),
+                base.push(P_FUNCTIONNAME),def.push(P_FUNCTIONNAME));
+            }
+        }
+
+    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(argument);
+        }
+         
+ 
+    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        argument = dataInput.readInt();
+        }
+
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // get the current context
+        ADFContext c = stack.top(0);
+        if (c==null) // uh oh
+            state.output.fatal("No context with which to evaluate ADFArgument terminal " +  toStringForError() +  ".  This often happens if you evaluate a tree by hand  which is supposed to only be an ADF's associated tree.");      
+        c.evaluate(state,thread,input,stack,individual,problem,argument);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFContext.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFContext.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFContext.java	(revision 6152)
@@ -0,0 +1,196 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * ADFContext.java
+ * 
+ * Created: Tue Oct 26 13:36:46 1999
+ * By: Sean Luke
+ */
+
+/**
+ * ADFContext is the object pushed onto an ADF stack which represents
+ * the current context of an ADM or ADF function call, that is, how to
+ * get the argument values that argument_terminals need to return.
+ *
+ * <p><i>adf</i> contains the relevant ADF/ADM node. 
+ * If it's an ADF
+ * function call, then <i>arguments[]</i> contains the evaluated arguments
+ * to the ADF.  If it's an ADM function call,
+ * then <i>arguments[]</i> is set to false.
+ *
+ * <p>You set up the ADFContext object for a given ADF or ADM node with
+ * the prepareADF(...) and prepareADM(...) functions.
+ *
+ * <p>To evaluate an argument number from an ADFContext, call evaluate(...),
+ * and the results are evaluated and copied into input.
+ *
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i><tt>.data</tt><br>
+ <td valign=top>(the ADFContext's basic GPData type)</td></tr> 
+ </table>
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ADFContext implements Prototype
+    {
+    public final static String P_DATA = "data";
+    public final static String P_ADFCONTEXT = "adf-context";
+
+    public final static int INITIAL_ARGUMENT_SIZE = 2;  // seems reasonable
+
+    /** The ADF/ADM node proper */
+    public ADF adf;
+
+    /** A prototypical GPData node. */
+    public GPData arg_proto;
+
+    /** An array of GPData nodes (none of the null, when it's used) 
+        holding an ADF's arguments' return results */
+    public GPData[] arguments;
+
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_ADFCONTEXT);
+        }
+
+    public ADFContext() 
+        {
+        arguments = new GPData[INITIAL_ARGUMENT_SIZE];
+        }
+
+    public Object clone()
+        {
+        try 
+            {
+            ADFContext myobj = (ADFContext) (super.clone());
+
+            // deep-clone the context proto
+            myobj.arg_proto = (GPData)(arg_proto.clone());
+
+            // deep-clone the contexts
+            myobj.arguments = new GPData[arguments.length];
+            for(int x=0;x<myobj.arguments.length;x++)
+                myobj.arguments[x] = (GPData)(arguments[x].clone());
+
+            return myobj;
+            }
+        catch (CloneNotSupportedException e)
+            { throw new InternalError(); }
+        }
+
+ 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // load the prototype
+        Parameter p = base.push(P_DATA);
+        Parameter def = defaultBase(); 
+        Parameter d = def.push(P_DATA);
+
+        
+        if (state.parameters.exists(p,d))
+            {
+            /* arg_proto = (GPData)
+               (state.parameters.getInstanceForParameter(
+               p,d,GPData.class));
+               arg_proto.setup(state,p);
+            */
+            state.output.warning("ADF Data is deprecated -- this parameter is no longer used.  Instead, we directly use the GPData.",
+                p, d);
+            }
+//        else 
+        // snarf it from eval.problem.data, hacked up from the Problem's data type,
+        // 'cause I'm not sure if Problem's been set up yet
+                {
+                Parameter pp = new Parameter(EvolutionState.P_EVALUATOR).
+                    push(Evaluator.P_PROBLEM).push(GPProblem.P_DATA);
+                Parameter dd = GPDefaults.base().push(GPProblem.P_GPPROBLEM).
+                    push(GPProblem.P_DATA);
+
+                //state.output.warning("No ADF GPData specified; using (and setting up) from\n " 
+                //    + pp + "\nor default base " + dd, p,d);
+                arg_proto = (GPData)
+                    (state.parameters.getInstanceForParameter(pp,dd,GPData.class));
+                arg_proto.setup(state,pp);  // note setting up from Problem's base!
+                }
+
+        // clone off the prototype
+        for (int x=0;x<INITIAL_ARGUMENT_SIZE;x++)
+            arguments[x] = (GPData)(arg_proto.clone());
+        }
+
+
+    /** Evaluates the argument number in the current context */
+    public void evaluate(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem,
+        final int argument)
+        {
+        // do I have that many arguments?
+        if (argument >= adf.children.length || argument < 0)  // uh oh 
+            {
+            individual.printIndividual(state,0);
+            state.output.fatal("Invalid argument number for " + adf.errorInfo());
+            }
+
+        // Am I an ADM or an ADF?
+        if (adf==null)
+            state.output.fatal("ADF is null for " + adf.errorInfo());
+        else if (adf instanceof ADF)  // it's an ADF
+            arguments[argument].copyTo(input);
+        else // it's an ADM
+            {
+            // get rid of my context temporarily
+            if (stack.moveOntoSubstack(1)!=1)
+                state.output.fatal("Substack prematurely empty for "  + adf.errorInfo());
+
+            // Call the GPNode
+            adf.children[argument].eval(state,thread,input,stack,individual,problem);
+            
+            // restore my context
+            if (stack.moveFromSubstack(1)!=1)
+                state.output.fatal("Stack prematurely empty for " + adf.errorInfo());
+            }
+        }
+
+    
+    /** Increases arguments to accommodate space if necessary.
+        Sets adf to a.
+        You need to then fill out the arguments yourself. */
+    public final void prepareADF(ADF a)
+        {
+        // set to the length requested or longer
+        if (a.children.length > arguments.length)
+            {
+            GPData[] newarguments = new GPData[a.children.length];
+            System.arraycopy(arguments,0,newarguments,0,arguments.length);
+            // fill gap -- ugh, luckily this doesn't happen but a few times
+            for(int x=arguments.length;x<newarguments.length;x++)
+                newarguments[x] = (GPData)(arg_proto.clone());
+            arguments = newarguments;
+            }
+        adf = a;
+        }
+
+    /** Sets adf to a */
+    public final void prepareADM(ADM a)
+        {
+        adf = a;
+        }
+
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFStack.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFStack.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ADFStack.java	(revision 6152)
@@ -0,0 +1,280 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * ADFStack.java
+ * 
+ * Created: Mon Oct 25 19:48:12 1999
+ * By: Sean Luke
+ */
+
+/**
+ * ADFStack is a special data object used to hold ADF data.
+ * This object is a weird beast and takes some explaining.
+ * It consists of a main stack, a secondary "substack", and a "reserve" area 
+ * (also implemented as a stack,
+ * but it doesn't have to be).  The reserve is used to "recycle" objects
+ * rather than having to create then new every time.
+ *
+ * <P>When an ADF is evaluated, it first
+ * evaluates its children, then it calls push() on the ADFstack.
+ * push() either creates a new ADFContext, or it fetches one from the
+ * reserve if possible.  It then pushes the context on the main stack,
+ * and also returns the context.  The ADF fills the context's arguments
+ * with the results of its childrens' evaluation, and sets numargs to 
+ * the number of
+ * arguments, then evaluates the
+ * ADF's associated function tree, 
+ *
+ * <p>When an ADM is evaluated, it calls push() on the ADFstack.
+ * The ADM then fills the context's adm node with itself, and sets numargs
+ * to the number of children it has.  Then it calls the ADM's associated
+ * function tree.
+ *
+ * <p>In that tree, if an argument terminal of value <i>n</i> is evaluated,
+ * the argument terminal calls evaluate(...) on the top context 
+ * on the ADF stack and returns the result.
+ * This method does different things depending on whether the top context
+ * represented an ADF or an ADM.  If it was an ADF, the context simply sets
+ * input to the value of argument <i>n</i> in the context's argument list,
+ * and returns input.  If it was an ADM, the context pops itself off the
+ * stack and pushes itself on the substack (to set up the right context
+ * for evaluating an original child of the ADM), then evaluates child <i>n</i>
+ * of the ADM, then pops itself off the substack and pushes itself back
+ * on the stack to restore the context.  Input is set to the evaluated
+ * results, and input is returned.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>context</tt><br>
+ <font size=-1>classname, inherits and != ec.gp.GPContext</font></td>
+ <td valign=top>(the stack's GPContext class)</td></tr> 
+ </table>
+
+ <p><b>Parameters</b><br>
+ gp.adf-stack
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>context</tt><br>
+ <td valign=top>(context_proto)</td></tr> 
+ </table>
+ 
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ADFStack implements Prototype 
+    {
+    public static final String P_ADFSTACK = "adf-stack";
+    public static final String P_ADF = "adf";
+    public static final String P_CONTEXT = "context";
+    public ADFContext context_proto;
+    public static final int INITIAL_STACK_SIZE = 2;  // seems like a good size
+    protected int onStack;
+    protected int onSubstack;
+    protected int inReserve;
+    protected ADFContext[] stack;
+    protected ADFContext[] substack;
+    protected ADFContext[] reserve;
+
+    public ADFStack() 
+        { 
+        stack = new ADFContext[INITIAL_STACK_SIZE];
+        substack = new ADFContext[INITIAL_STACK_SIZE];
+        reserve = new ADFContext[INITIAL_STACK_SIZE];
+        onStack=0;
+        onSubstack = 0;
+        inReserve = 0;
+        }
+
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_ADFSTACK);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // load our prototype
+
+        Parameter p = base.push(P_CONTEXT);
+        Parameter d = defaultBase().push(P_CONTEXT);
+
+        context_proto = (ADFContext)
+            (state.parameters.getInstanceForParameterEq(p,d,ADFContext.class));
+        context_proto.setup(state,p);
+        }
+
+    public Object clone()
+        {
+        try
+            {
+            ADFStack myobj = (ADFStack) (super.clone());
+
+            // deep-cloned stuff
+            myobj.context_proto = (ADFContext)(context_proto.clone());
+
+            // clone the stack arrays -- dunno if this is faster than new ADFContext[...]
+            myobj.stack = (ADFContext[])(stack.clone());
+            myobj.substack = (ADFContext[])(substack.clone());
+            myobj.reserve = (ADFContext[])(reserve.clone());
+
+            // fill 'em up
+            for(int x=0;x<onStack;x++)
+                myobj.stack[x] = (ADFContext)(stack[x].clone());
+            for(int x=0;x<onSubstack;x++)
+                myobj.substack[x] = (ADFContext)(substack[x].clone());
+            for(int x=0;x<inReserve;x++)
+                myobj.reserve[x] = (ADFContext)(reserve[x].clone());
+            return myobj;
+            }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+    
+    /** Returns an ADFContext from the stack's reserve, or creates one
+        fresh if there are none in reserve.  While you can throw this
+        ADFContext away if you like, it'd be good if you actually didn't
+        call this function unless you expected to push the 
+        context onto the stack with push(ADFContext obj) -- karma!
+    */
+    public final ADFContext get()
+        {
+        // Remove one from reserve
+
+        ADFContext obj;
+        if (inReserve>0) obj = reserve[--inReserve];
+        else obj = (ADFContext)(context_proto.clone());  // hopefully that doesn't have to happen too many times
+        return obj;
+        }
+
+
+    /** Pushes an ADFContext onto the main stack.  The best way to get an
+        ADFContext to push onto the stack is with get(). Returns obj. */
+
+    public final ADFContext push(ADFContext obj)
+        {
+        // Double stack if necessary
+        if (onStack==stack.length)
+            {
+            ADFContext[] newstack = new ADFContext[stack.length * 2];
+            System.arraycopy(stack,0,newstack,0,stack.length);
+            stack = newstack;
+            }
+
+        // Add to stack
+        stack[onStack++] = obj;
+        
+        // return it
+        return obj;
+        }
+
+
+    /** Pops off <i>n</i> items from the stack, if possible. Returns
+        the number of items actually popped off. */ 
+    public final int pop(int n)
+        {
+        int x;
+        for(x = 0 ; x < n; x++)
+            {
+            // Anything left on the stack?
+            if (onStack==0) break;
+
+            // Remove one from stack
+            ADFContext obj = stack[--onStack];
+            
+            // Double reserve if necessary
+            if (inReserve==reserve.length)
+                {
+                ADFContext[] newreserve = new ADFContext[reserve.length * 2];
+                System.arraycopy(reserve,0,newreserve,0,reserve.length);
+                reserve = newreserve;
+                }
+            
+            // Add to reserve
+            reserve[inReserve++] = obj;         
+            }
+        return x;
+        }
+    
+
+
+
+    /** Returns the <i>n</i>th item in the stack (0-indexed), or null if
+        this goes to the bottom of the stack. */
+    public final ADFContext top(int n)
+        {
+        // is this beyond the stack?
+        if (onStack-n <= 0) return null;
+        else return stack[onStack-n-1];
+        }
+
+
+    /** Moves <i>n</i> items onto the substack (pops them off the stack and pushes them onto the substack).  Returns the actual number of items for which this was done. */
+    public final int moveOntoSubstack(int n)
+        {
+        int x;
+        for(x=0;x<n;x++)
+            {
+            // is the stack empty?
+            if (onStack==0) break;  // uh oh
+            
+            // Remove one from stack
+            ADFContext obj = stack[--onStack];
+            
+            // Double substack if necessary
+            if (onSubstack == substack.length)
+                {
+                ADFContext[] newsubstack = new ADFContext[substack.length * 2];
+                System.arraycopy(substack,0,newsubstack,0,substack.length);
+                substack = newsubstack;
+                }
+            
+            // Add to substack
+            substack[onSubstack++] = obj;
+            }
+        return x;
+        }
+
+    /** Moves <i>n</i> items onto the stack (popss them off the substack and pushes them onto the stack). Returns the actual number of items moved from the Substack onto the main stack */
+    public final int moveFromSubstack(int n)
+        {
+        int x;
+        for(x=0;x<n;x++)
+            {
+            // is the substack empty?
+            if (onSubstack==0) break; // uh oh
+            
+            // Remove one from stack
+            ADFContext obj = substack[--onSubstack];
+
+            // Double stack if necessary
+            if (onStack==stack.length)
+                {
+                ADFContext[] newstack = new ADFContext[stack.length * 2];
+                System.arraycopy(stack,0,newstack,0,stack.length);
+                stack = newstack;
+                }
+            
+            // Add to stack
+            stack[onStack++] = obj;
+            }
+        return x;
+        }
+
+    /** Pops off all items on the stack and the substack. */
+    public final void reset()
+        {
+        if (onSubstack>0) moveFromSubstack(onSubstack);
+        if (onStack>0) pop(onStack);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ADM.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ADM.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ADM.java	(revision 6152)
@@ -0,0 +1,49 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+
+/* 
+ * ADM.java
+ * 
+ * Created: Tue Oct 26 15:29:57 1999
+ * By: Sean Luke
+ */
+
+/**
+ * An ADM is an ADF which doesn't evaluate its arguments beforehand, but
+ * instead only evaluates them (and possibly repeatedly) when necessary
+ * at runtime.  For more information, see ec.gp.ADF.
+ * @see ec.gp.ADF
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ADM extends ADF
+    {
+    public void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem)
+        {
+        // prepare a context
+        ADFContext c = stack.push(stack.get());
+        c.prepareADM(this);
+        
+        // evaluate the top of the associatedTree
+        individual.trees[associatedTree].child.eval(
+            state,thread,input,stack,individual,problem);
+
+        // pop the context off, and we're done!
+        if (stack.pop(1) != 1)
+            state.output.fatal("Stack prematurely empty for " + toStringForError());
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ERC.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ERC.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ERC.java	(revision 6152)
@@ -0,0 +1,233 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * ERC.java
+ * 
+ * Created: Mon Oct 25 18:22:15 1999
+ * By: Sean Luke
+ */
+
+/**
+ * ERC is an abstract GPNode which implements Ephemeral Random Constants,
+ * as described in Koza I.  An ERC is a node which, when first instantiated,
+ * gets set to some random constant value which it always returns from
+ * then on, even after being crossed over into other individuals.
+ * In order to implement an ERC, you need to override several methods below.
+ *
+ * <h2>Impementing an ERC</h2>
+ *
+ * A basic no-frills ERC needs to have the following things:
+ *
+ * <ul>
+ * <li>The data holding the ERC (perhaps a float or a couple of floats)
+ * <li>An implementation of the <b>eval</b> method which returns the appropriate
+ *     data when the node is evaluated.
+ * <li>Possibly an implementation of the <b>clone</b> method to copy that data
+ *     properly.  If your ERC data is just a simple or immutable type
+ *     (like an int or a string), you don't need write a clone() method;
+ *     the default one works fine.  But if your data is an array or other
+ *     mutable object, you'll need to override the clone() method to copy
+ *     the array.  
+ *
+ * <li>An implementation of the <b>resetNode</b> method to randomize the
+ *     data once cloned from the prototype.  This essentially "initializes"
+ *     your ERC.
+ *
+ * <li>An implementation of the <b>encode</b> method which presents the
+ *     ERC as a String.  If you don't plan on writing individuals out to
+ *     files in a fashion that enables them to be read back in again later,
+ *     but only care to print out individuals for statistics purposes, 
+ *     you can implement this to just
+ *     write <tt>"" + <i>value</i></tt>, where <i>value</i> is your data.
+ *
+ * <li>An implementation of the <b>nodeEquals</b> method to return true if
+ *     the other node is also an ERC of the same type, and it has the
+ *     same ERC data as yourself.
+ *
+ *
+ * </ul>
+ * 
+ * A more advanced ERC will need some of the following gizmos:
+ * 
+ * <ul>
+ *
+ * <li>If you have ERCs of different class types (for example, a vector ERC
+ *      and a floating-point scalar ERC), you will wish to distinguish them
+ *      when they're printed to files.  To do this,  override the <b>name</b> 
+ *      method to return different strings for each of them (perhaps "vec" versus "").
+ *
+ * <li>If you want to write your ERCs to files such that they can be read
+ *      back in again, you'll need to override the <b>encode</b> method
+ *      to write using the <tt>ec.util.Code</tt> class.  Further, you'll need to
+ *      override the <b>decode</b> method to read in the individual using the
+ *      <tt>ec.util.Code</tt> and <tt>ec.util.DecodeReturn</tt> classes.  The
+ *      default version -- which is wrong -- returns <tt>false</tt>.
+ *      When you do this, you'll probably also want to override the <b>toStringForHumans()</b>
+ *      method to return a simple string form of the ERC: perhaps just a number
+ *      or a vector like "<7.24, 9.23>".  This is because by default <b>toStringForHumans()</b>
+ *      calls <b>toString()</b>, which in turn calls <b>encode</b>, which you have
+ *      just overidden to be more computer-ish.
+ *
+ * <li>ERCs can be mutated using a custom mutator pipeline, for example the
+ *     <b>ec.gp.breed.MutateERCPipeline</b>.  If you expect to mutate your ERCs,
+ *     you may wish to override the <b>mutateERC</b> method to do something
+ *     more subtle than its default setting (which just randomizes the
+ *     ERC again, by calling resetNode).
+ * 
+ * <li>The default <b>nodeHashCode</b> implementation is poor and slow (it
+ *     creates a string using encode() and then hashes the sting).  You might
+ *     create a better (and probably simpler) hash code function.
+ *
+ * <li>If you're going to use facilities such as the Island Model or the distributed
+ *     evaluator, you'll need to implement the <b>writeNode</b> and <b>readNode</b>
+ *     methods to read/write the node to DataInput/DataOutput.  The default implementations
+ *     just throw errors.
+ *
+ * <li>If you need to set up your ERC class from the parameter file, do so in the <b>setup</b> method.
+ *
+ * </ul>
+ *
+ * <p> See the <b>ec.app.regression.func.RegERC</b> class for an example of a simple but "fuly-implemented"
+ * ERC.  A slightly more complicated example can be found in <b>ec.app.lawnmower.func.LawnERC</b>.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class ERC extends GPNode
+    {
+    /** Returns the lowercase "name" of this ERC function class, some
+        simple, short name which distinguishes this class from other ERC
+        function classes you're using.  If you have more than one ERC function,
+        you need to distinguish them here.  By default the value is "ERC",
+        which works fine for a single ERC function in the function set.
+        Whatever the name is, it should
+        generally only have letters, numbers, or hyphens or underscores in it.
+        No whitespace or other characters. */
+    public String name() { return "ERC"; }
+
+    /** Usually ERCs don't have children, and this default implementation makes certain of it. 
+        But if you want to override this, you're welcome to. */
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        {
+        super.checkConstraints(state,tree,typicalIndividual,individualBase);
+        // make sure we don't have any children.  This is the typical situation for an ERC.
+        if (children.length!= 0) state.output.error("Incorrect number of children for the node " + toStringForError() + " (should be 0)");
+        }
+
+    /** Remember to override this to randomize your ERC after it has been cloned.  The prototype will not ever receive this method call. */
+    public abstract void resetNode(final EvolutionState state, int thread);
+
+    /** Implement this to do ERC-to-ERC comparisons. */
+    public abstract boolean nodeEquals(final GPNode node);
+
+    /** Implement this to hash ERCs, along with other nodes, in such a way that two
+        "equal" ERCs will usually hash to the same value. The default value, which 
+        may not be very good, is a combination of the class hash code and the hash
+        code of the string returned by encode().  You might make a better hash value. */
+    public int nodeHashCode() { return super.nodeHashCode() ^ encode().hashCode(); }
+
+    /** 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() + [ + ... + ] */
+    public String toStringForHumans() 
+        { return toString(); }
+
+    /** This defaults to simply name() + "[" + encode() + "]".   You probably shouldn't deviate from this. */
+    public String toString() 
+        { return name() + "[" + encode() + "]"; }
+
+    /** Encodes data from the ERC, using ec.util.Code.  */
+    public abstract String encode();
+
+    /** Decodes data into the ERC from dret.  Return true if you sucessfully
+        decoded, false if you didn't.  Don't increment dret.pos's value beyond
+        exactly what was needed to decode your ERC.  If you fail to decode,
+        you should make sure that the position and data in the dret are exactly
+        as they were originally. */
+    public boolean decode(final DecodeReturn dret)
+        {
+        return false;
+        }
+
+    /** Mutates the node's "value".  This is called by mutating operators
+        which specifically <i>mutate</i> the "value" of ERCs, as opposed to 
+        replacing them with whole new ERCs. The default form of this function
+        simply calls resetNode(state,thread), but you might want to modify
+        this to do a specialized form of mutation, applying gaussian
+        noise for example. */
+
+    public void mutateERC(final EvolutionState state, final int thread)
+        {
+        resetNode(state,thread);
+        }
+
+    /** To successfully write to a DataOutput, you must override this to write your specific ERC data out.  The
+        default implementation issues a fatal error. */
+    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        state.output.fatal("writeNode(EvolutionState,DataInput) not implemented in " + getClass().getName());
+        }
+
+    /** To successfully read from a DataOutput, you must override this to read your specific ERC data in.  The
+        default implementation issues a fatal error. */
+    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        state.output.fatal("readNode(EvolutionState,DataInput) not implemented in " + getClass().getName());
+        }
+
+    public GPNode readNode(final DecodeReturn dret) 
+        {
+        int len = dret.data.length();
+        int originalPos = dret.pos;
+        
+        // get my name
+        String str2 = name() + "[";
+        int len2 = str2.length();
+
+        if (dret.pos + len2 >= len)  // uh oh, not enough space
+            return null;
+
+        // check it out
+        for(int x=0; x < len2 ; x++)
+            if (dret.data.charAt(dret.pos + x) != str2.charAt(x))
+                return null;
+
+        // looks good!  try to load this sucker.
+        dret.pos += len2;
+        ERC node = (ERC) lightClone();
+        if (!node.decode(dret)) 
+            { dret.pos = originalPos; return null; }  // couldn't decode it
+
+        // the next item should be a "]"
+        
+        if (dret.pos >= len)
+            { dret.pos = originalPos; return null; }
+        if (dret.data.charAt(dret.pos) != ']') 
+            { dret.pos = originalPos; return null; }
+        
+        // Check to make sure that the ERC's all there is
+        if (dret.data.length() > dret.pos+1)
+            {
+            char c = dret.data.charAt(dret.pos+1);
+            if (!Character.isWhitespace(c) &&
+                c != ')' && c != '(') // uh oh
+                { dret.pos = originalPos; return null; }
+            }   
+
+        dret.pos++;
+
+        return node;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPAtomicType.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPAtomicType.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPAtomicType.java	(revision 6152)
@@ -0,0 +1,45 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+
+/* 
+ * GPAtomicType.java
+ * 
+ * Created: Fri Aug 27 21:16:45 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A GPAtomicType is a simple, atomic GPType.  For more information, see GPType.
+ @see ec.gp.GPType
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class GPAtomicType extends GPType
+    {
+    /** Use this constructor for GPAtomic Type unless you know what you're doing */
+    public GPAtomicType(final String n) { name = n; }
+
+    /** Don't use this constructor unless you call setup(...) immediately after it. */
+    public GPAtomicType() { }
+
+    public final boolean compatibleWith(final GPInitializer initializer, final GPType t)
+        {
+        // if the type is me, then I'm compatible with it
+        if (t.type==type) return true;
+        
+        // if the type an atomic type, then return false
+        else if (t.type < initializer.numAtomicTypes) return false;
+        
+        // if the type is < 0 (it's a set type), then I'm compatible
+        // if I'm contained in it.  Use its sparse array.
+        else return ((GPSetType)t).types_sparse[type];
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPBreedingPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPBreedingPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPBreedingPipeline.java	(revision 6152)
@@ -0,0 +1,54 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+
+/* 
+ * GPBreedingPipeline.java
+ * 
+ * Created: Tue Sep 14 19:38:09 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A GPBreedingPipeline is a BreedingPipeline which produces only
+ * members of some subclass of GPSpecies.   This is just a convenience
+ * superclass for many of the breeding pipelines here; you don't have
+ * to be a GPBreedingPipeline in order to breed GPSpecies or anything. 
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class GPBreedingPipeline extends BreedingPipeline 
+    {
+    /** Standard parameter for node-selectors associated with a GPBreedingPipeline */
+    public static final String P_NODESELECTOR = "ns";
+
+    /** Standard parameter for tree fixing */
+    public static final String P_TREE = "tree";
+
+    /** Standard value for an unfixed tree */
+    public static final int TREE_UNFIXED = -1;
+
+
+    /** Returns true if <i>s</i> is a GPSpecies. */
+    public boolean produces(final EvolutionState state,
+        final Population newpop,
+        final int subpopulation,
+        final int thread)
+        {
+        if (!super.produces(state,newpop,subpopulation,thread)) return false;
+
+        // we produce individuals which are owned by subclasses of GPSpecies
+        if (newpop.subpops[subpopulation].species instanceof GPSpecies)
+            return true;
+        return false;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPData.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPData.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPData.java	(revision 6152)
@@ -0,0 +1,57 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GPData.java
+ * 
+ * Created: Mon Oct 25 19:37:18 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPData is the parent class of data transferred between GPNodes.
+ * If performed correctly, there need be only one GPData instance 
+ * ever created in the evaluation of many individuals. 
+
+ <p><b>Default Base</b><br>
+ gp.data
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class GPData implements Prototype
+    {
+    public static final String P_GPDATA = "data";
+
+    /** Modifies gpd so that gpd is equivalent to us. You may
+        safely assume that gpd is of the same class as we are.
+        Do not share pointers with the other object, except to
+        read-only data: instead, copy any read-write data as necessary. */
+    public abstract void copyTo(final GPData gpd);
+
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_GPDATA);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        }
+
+    public Object clone()
+        {
+        try { return super.clone(); }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPDefaults.java	(revision 6152)
@@ -0,0 +1,37 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * GPDefaults.java
+ * 
+ * Created: Tue Oct 12 17:44:47 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A static class that returns the base for "default values" which GP-style
+ * operators use, rather than making the user specify them all on a per-
+ * species basis.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class GPDefaults implements DefaultsForm
+    {
+    public static final String P_GP = "gp";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_GP);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPFunctionSet.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPFunctionSet.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPFunctionSet.java	(revision 6152)
@@ -0,0 +1,339 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import java.io.*;
+import ec.*;
+import ec.util.*;
+import java.util.*;
+
+/* 
+ * GPFunctionSet.java
+ * 
+ * Created: Wed Oct 13 22:35:06 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPFunctionSet is a Clique which represents a set of GPNode prototypes
+ * forming a standard function set for forming certain trees in individuals.
+ * GPFunctionSets instances have unique names with which they're referenced by
+ * GPTreeConstraints objects indicating that they're used for certain trees.
+ * GPFunctionSets store their GPNode Prototypes in three hashtables,
+ * one for all nodes, one for nonterminals, and one for terminals.  Each
+ * hashed item is an array of GPNode objects,
+ * hashed by the return type of the GPNodes in the array.
+ *
+ * GPFunctionSets also contain prototypical GPNode nodes which they
+ * clone to form their arrays.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of function set.  Must be different from other function set instances)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of functions in the function set)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>func.</tt><i>n</i><br>
+ <font size=-1>classname, inherits and != ec.gp.GPNode</font></td>
+ <td valign=top>(class of function node <i>n</i> in the set)</td></tr>
+
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>func.</tt><i>n</i></td>
+ <td>function node <i>n</i></td></tr>
+ </table>
+ 
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPFunctionSet implements Clique
+    {
+    public final static String P_NAME = "name";
+    public final static String P_FUNC = "func";
+    public final static String P_SIZE = "size";
+
+    /** Name of the GPFunctionSet */
+    public String name;
+
+    /** The nodes that our GPTree can use: arrays of nodes hashed by type. */
+    public Hashtable nodes_h;
+    /** The nodes that our GPTree can use: nodes[type][thenodes]. */
+    public GPNode[][] nodes;
+    /** The nonterminals our GPTree can use: arrays of nonterminals hashed by type. */
+    public Hashtable nonterminals_h;
+    /** The nonterminals our GPTree can use: nonterminals[type][thenodes]. */
+    public GPNode[][] nonterminals;
+    /** The terminals our GPTree can use: arrays of terminals hashed by type. */
+    public Hashtable terminals_h;
+    /** The terminals our GPTree can use: terminals[type][thenodes]. */
+    public GPNode[][] terminals;
+
+
+    // some convenience methods which speed up various kinds
+    // of mutation operators
+
+    /** The nodes that our GPTree can use, hashed by name(). */
+    public Hashtable nodesByName;
+
+    /** Nodes == a given arity, that is: nodesByArity[type][arity][thenodes] */
+    public GPNode[][][]nodesByArity;
+
+    /** Nonterminals <= a given arity, that is: nonterminalsUnderArity[type][arity][thenodes] --
+        this will be O(n^2).  Obviously, the number of nonterminals at arity slot 0 is 0.*/
+    public GPNode[][][]nonterminalsUnderArity;
+
+    /** Nonterminals >= a given arity, that is: nonterminalsOverArity[type][arity][thenodes] --
+        this will be O(n^2).  Obviously, the number of nonterminals at arity slot 0 is all the 
+        nonterminals of that type. */
+    public GPNode[][][]nonterminalsOverArity;
+    
+    /** Returns the name. */
+    public String toString() { return name; }
+
+
+    /** Sets up all the GPFunctionSet, loading them from the parameter
+        file.  This must be called before anything is called which refers
+        to a type by name. */
+
+    /** Sets up the arrays based on the hashtables */
+
+    public void postProcessFunctionSet()
+        {
+        nodes = new GPNode[nodes_h.size()][];
+        terminals = new GPNode[terminals_h.size()][];
+        nonterminals = new GPNode[nonterminals_h.size()][];
+
+        Enumeration e = nodes_h.keys();
+        while(e.hasMoreElements())
+            {
+            GPType gpt = (GPType)(e.nextElement());
+            GPNode[] gpfi = (GPNode[])(nodes_h.get(gpt));
+            nodes[gpt.type] = gpfi;
+            }
+        e = nonterminals_h.keys();
+        while(e.hasMoreElements())
+            {
+            GPType gpt = (GPType)(e.nextElement());
+            GPNode[] gpfi = (GPNode[])(nonterminals_h.get(gpt));
+            nonterminals[gpt.type] = gpfi;
+            }
+        e = terminals_h.keys();
+        while(e.hasMoreElements())
+            {
+            GPType gpt = (GPType)(e.nextElement());
+            GPNode[] gpfi = (GPNode[])(terminals_h.get(gpt));
+            terminals[gpt.type] = gpfi;
+            }
+
+        // set up arity-based arrays
+        // first, determine the maximum arity
+        int max_arity=0;
+        for(int x=0;x<nodes.length;x++)
+            for(int y=0;y<nodes[x].length;y++)
+                if (max_arity < nodes[x][y].children.length)
+                    max_arity = nodes[x][y].children.length;
+
+        // next set up the == array
+        nodesByArity = new GPNode[nodes.length][max_arity+1][];
+        for(int x=0;x<nodes.length;x++)
+            for(int a = 0; a <= max_arity; a++)
+                {
+                // how many nodes do we have?
+                int num_of_a = 0;
+                for(int y=0;y<nodes[x].length;y++)
+                    if (nodes[x][y].children.length == a) num_of_a++;
+                // allocate and fill
+                nodesByArity[x][a] = new GPNode[num_of_a];
+                int cur_a = 0;
+                for(int y=0;y<nodes[x].length;y++)
+                    if (nodes[x][y].children.length == a )
+                        nodesByArity[x][a][cur_a++] = nodes[x][y];
+                }
+
+        // now set up the <= nonterminals array
+        nonterminalsUnderArity = new GPNode[nonterminals.length][max_arity+1][];
+        for(int x=0;x<nonterminals.length;x++)
+            for (int a = 0;a <= max_arity; a++)
+                {
+                // how many nonterminals do we have?
+                int num_of_a = 0;
+                for(int y=0;y<nonterminals[x].length;y++)
+                    if (nonterminals[x][y].children.length <= a) num_of_a++;
+                // allocate and fill
+                nonterminalsUnderArity[x][a] = new GPNode[num_of_a];
+                int cur_a = 0;
+                for(int y=0;y<nonterminals[x].length;y++)
+                    if (nonterminals[x][y].children.length <= a )
+                        nonterminalsUnderArity[x][a][cur_a++] = nonterminals[x][y];
+                }
+
+
+
+        // now set up the >= nonterminals array
+        nonterminalsOverArity = new GPNode[nonterminals.length][max_arity+1][];
+        for(int x=0;x<nonterminals.length;x++)
+            for (int a = 0;a <= max_arity; a++)
+                {
+                // how many nonterminals do we have?
+                int num_of_a = 0;
+                for(int y=0;y<nonterminals[x].length;y++)
+                    if (nonterminals[x][y].children.length >= a) num_of_a++;
+                // allocate and fill
+                nonterminalsOverArity[x][a] = new GPNode[num_of_a];
+                int cur_a = 0;
+                for(int y=0;y<nonterminals[x].length;y++)
+                    if (nonterminals[x][y].children.length >= a )
+                        nonterminalsOverArity[x][a][cur_a++] = nonterminals[x][y];
+                }
+        }
+
+
+
+
+    /** Must be done <i>after</i> GPType and GPNodeConstraints have been set up */
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // What's my name?
+        name = state.parameters.getString(base.push(P_NAME),null);
+        if (name==null)
+            state.output.fatal("No name was given for this function set.",
+                base.push(P_NAME));
+        // Register me
+        GPFunctionSet old_functionset = (GPFunctionSet)(((GPInitializer)state.initializer).functionSetRepository.put(name,this));
+        if (old_functionset != null)
+            state.output.fatal("The GPFunctionSet \"" + name + "\" has been defined multiple times.", base.push(P_NAME));
+
+        // How many functions do I have?
+        int numFuncs = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (numFuncs < 1)
+            state.output.error("The GPFunctionSet \"" + name + "\" has no functions.",
+                base.push(P_SIZE));
+        
+        nodesByName = new Hashtable();
+
+        Parameter p = base.push(P_FUNC);
+        Vector tmp = new Vector();
+        for(int x = 0; x < numFuncs; x++)
+            {
+            // load
+            Parameter pp = p.push(""+x);
+            GPNode gpfi = (GPNode)(state.parameters.getInstanceForParameter(
+                    pp, null, GPNode.class));
+            gpfi.setup(state,pp);
+
+            // add to my collection
+            tmp.addElement(gpfi);
+                        
+            // Load into the nodesByName hashtable
+            GPNode[] nodes = (GPNode[])(nodesByName.get(gpfi.name()));
+            if (nodes == null)
+                nodesByName.put(gpfi.name(), new GPNode[] { gpfi });
+            else
+                {
+                // O(n^2) but uncommon so what the heck.
+                GPNode[] nodes2 = new GPNode[nodes.length + 1];
+                System.arraycopy(nodes, 0, nodes2, 0, nodes.length);
+                nodes2[nodes2.length - 1] = gpfi;
+                nodesByName.put(gpfi.name(), nodes2);
+                }
+            }
+
+        // Make my hash tables
+        nodes_h = new Hashtable();
+        terminals_h = new Hashtable();
+        nonterminals_h = new Hashtable();
+
+        // Now set 'em up according to the types in GPType
+
+        Enumeration e = ((GPInitializer)state.initializer).typeRepository.elements();
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        while(e.hasMoreElements())
+            {
+            GPType typ = (GPType)(e.nextElement());
+            
+            // make vectors for the type.
+            Vector nodes_v = new Vector();
+            Vector terminals_v = new Vector();
+            Vector nonterminals_v = new Vector();
+
+            // add GPNodes as appropriate to each vector
+            Enumeration v = tmp.elements();
+            while (v.hasMoreElements())
+                {
+                GPNode i = (GPNode)(v.nextElement());
+                if (typ.compatibleWith(initializer,i.constraints(initializer).returntype))
+                    {
+                    nodes_v.addElement(i);
+                    if (i.children.length == 0)
+                        terminals_v.addElement(i);
+                    else nonterminals_v.addElement(i);
+                    }
+                }
+
+            // turn nodes_h' vectors into arrays
+            GPNode[] ii = new GPNode[nodes_v.size()];
+            nodes_v.copyInto(ii);
+            nodes_h.put(typ,ii);
+
+            // turn terminals_h' vectors into arrays
+            ii = new GPNode[terminals_v.size()];
+            terminals_v.copyInto(ii);
+            terminals_h.put(typ,ii);
+
+            // turn nonterminals_h' vectors into arrays
+            ii = new GPNode[nonterminals_v.size()];
+            nonterminals_v.copyInto(ii);
+            nonterminals_h.put(typ,ii);
+            }
+
+        // I don't check to see if the generation mechanism will be valid here
+        // -- I check that in GPTreeConstraints, where I can do the weaker check
+        // of going top-down through functions rather than making sure that every
+        // single function has a compatible argument function (an unneccessary check)
+
+        state.output.exitIfErrors();  // because I promised when I called n.setup(...)
+
+        // postprocess the function set
+        postProcessFunctionSet();
+        }
+
+
+    /** Returns the function set for a given name.
+        You must guarantee that after calling functionSetFor(...) one or
+        several times, you call state.output.exitIfErrors() once. */
+
+    public static GPFunctionSet functionSetFor(final String functionSetName,
+        final EvolutionState state)
+        {
+        GPFunctionSet set = (GPFunctionSet)(((GPInitializer)state.initializer).functionSetRepository.get(functionSetName));
+        if (set==null)
+            state.output.error("The GP function set \"" + functionSetName + "\" could not be found.");
+        return set;
+        }
+
+
+    private void writeObject(ObjectOutputStream out) throws IOException
+        {
+        // this wastes an hashtable pointer, but what the heck.
+
+        out.defaultWriteObject();
+        }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+        {
+        in.defaultReadObject();
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPIndividual.java	(revision 6152)
@@ -0,0 +1,310 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * GPIndividual.java
+ * 
+ * Created: Fri Aug 27 17:07:45 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPIndividual is an Individual used for GP evolution runs.
+ * GPIndividuals contain, at the very least, a nonempty array of GPTrees.
+ * You can use GPIndividual directly, or subclass it to extend it as
+ * you see fit.
+ 
+ * <P>GPIndividuals have two clone methods: clone() and lightClone().  clone() is
+ * a deep clone method as usual.  lightClone() is a light clone which does not copy
+ * the trees.
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  Because GPIndividuals are often very large,
+ * <b>GPIndividual has overridden these methods -- they work differently than in Individual (the superclass).</b>  In specific:
+ * <b>readIndividual</b> by default reads in the fitness and the evaluation flag, then calls <b>parseGenotype</b> 
+ * to read in the trees (via GPTree.readTree(...)).
+ * However <b>printIndividual</b> by default prints the fitness and evaluation flag, and prints all the trees
+ * by calling GPTree.printTree(...).  It does not call <b>genotypeToString</b> at all.  This
+ * is because it's very wasteful to build up a large string holding the printed form of the GPIndividual 
+ * just to pump it out a stream once.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only. Because GPIndividuals are often very large,
+ * <b>GPIndividual has overridden this methods -- it works differently than in Individual (the superclass).</b>  In specific:
+ * <b>printIndividual</b> by default prints the fitness and evaluation flag, and prints all the trees
+ * by calling GPTree.printTreeForHumans(...).  It does not call <b>genotypeToStringForHumans</b> at all.  This
+ * is because it's very wasteful to build up a large string holding the printed form of the GPIndividual 
+ * just to pump it out a stream once.
+ *
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the GPTree array (by having each GPTree read/write
+ * itself).  If you add instance variables to GPIndividual, you'll need to read/write those variables as well.
+
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>numtrees</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of trees in the GPIndividual)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.</tt><i>n</i><br>
+ <font size=-1>classname, inherits or = ec.gp.GPTree</font></td>
+ <td valign=top>(class of tree <i>n</i> in the individual)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.individual
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tree.</tt><i>n</i></td>
+ <td>tree <i>n</i> in the individual</td></tr>
+ </table>
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPIndividual extends Individual
+    {
+    public static final String P_NUMTREES = "numtrees";
+    public static final String P_TREE = "tree";
+    
+    public GPTree[] trees;
+    
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_INDIVIDUAL);
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false;  // GPIndividuals are special.
+        GPIndividual i = (GPIndividual)ind;
+        if (trees.length != i.trees.length) return false;
+        // this default version works fine for most GPIndividuals.
+        for(int x=0;x<trees.length;x++)
+            if (!(trees[x].treeEquals(i.trees[x]))) return false;
+        return true;
+        }
+    
+    public int hashCode()
+        {
+        // stolen from GPNode.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+        
+        for(int x=0;x<trees.length;x++)
+            hash =
+                // Rotate hash and XOR
+                (hash << 1 | hash >>> 31 ) ^
+                trees[x].treeHashCode();
+        return hash;
+        }
+
+    /** Sets up a prototypical GPIndividual with those features which it
+        shares with other GPIndividuals in its species, and nothing more. */
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+
+        Parameter def = defaultBase();
+
+        // set my evaluation to false
+        evaluated = false;
+
+        // how many trees?
+        int t = state.parameters.getInt(base.push(P_NUMTREES),def.push(P_NUMTREES),1);  // at least 1 tree for GP!
+        if (t <= 0) 
+            state.output.fatal("A GPIndividual must have at least one tree.",
+                base.push(P_NUMTREES),def.push(P_NUMTREES));
+        
+        // load the trees
+        trees = new GPTree[t];
+
+        for (int x=0;x<t;x++)
+            {
+            Parameter p = base.push(P_TREE).push(""+x);
+            trees[x] = (GPTree)(state.parameters.getInstanceForParameterEq(
+                    p,def.push(P_TREE).push(""+x),GPTree.class));
+            trees[x].owner = this;
+            trees[x].setup(state,p);
+            }
+        
+        // now that our function sets are all associated with trees,
+        // give the nodes a chance to determine whether or not this is
+        // going to work for them (especially the ADFs).
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        for (int x=0;x<t;x++)
+            {
+            for(int w = 0;w < trees[x].constraints(initializer).functionset.nodes.length;w++)
+                {
+                GPNode[] gpfi = trees[x].constraints(initializer).functionset.nodes[w];
+                for (int y = 0;y<gpfi.length;y++)
+                    gpfi[y].checkConstraints(state,x,this,base);
+                }
+            }
+        // because I promised with checkConstraints(...)
+        state.output.exitIfErrors();
+        }
+
+
+    /** Verification of validity of the GPIndividual -- strictly for debugging purposes only */
+    public final void verify(EvolutionState state)
+        {
+        if (!(state.initializer instanceof GPInitializer))
+            { state.output.error("Initializer is not a GPInitializer"); return; }
+            
+        GPInitializer initializer = (GPInitializer)(state.initializer);
+
+        if (trees==null) 
+            { state.output.error("Null trees in GPIndividual."); return; }
+        for(int x=0;x<trees.length;x++) if (trees[x]==null) 
+                                            { state.output.error("Null tree (#"+x+") in GPIndividual."); return; }
+        for(int x=0;x<trees.length;x++)
+            trees[x].verify(state);
+        state.output.exitIfErrors();
+        }
+
+    /** Prints just the trees of the GPIndividual.  Broken out like this to be used by GEIndividual to avoid
+        re-printing the fitness and evaluated premables. */
+    public void printTrees(final EvolutionState state, final int log)
+        {
+        for(int x=0;x<trees.length;x++)
+            {
+            state.output.println("Tree " + x + ":",log);
+            trees[x].printTreeForHumans(state,log);
+            }
+        }
+
+    public void printIndividualForHumans(final EvolutionState state, final int log)
+        {
+        state.output.println(EVALUATED_PREAMBLE + (evaluated ? "true" : "false"), log);
+        fitness.printFitnessForHumans(state,log);
+        printTrees(state,log);
+        }
+
+    public void printIndividual(final EvolutionState state, final int log)
+        {
+        state.output.println(EVALUATED_PREAMBLE + Code.encode(evaluated), log);
+        fitness.printFitness(state,log);
+        for(int x=0;x<trees.length;x++)
+            {
+            state.output.println("Tree " + x + ":",log);
+            trees[x].printTree(state,log);
+            }   
+        }
+            
+    public void printIndividual(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println(EVALUATED_PREAMBLE + Code.encode(evaluated));
+        fitness.printFitness(state,writer);
+        for(int x=0;x<trees.length;x++)
+            {
+            writer.println("Tree " + x + ":");
+            trees[x].printTree(state,writer);
+            }   
+        }
+        
+    /** Overridden for the GPIndividual genotype. */
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(trees.length);
+        for(int x=0;x<trees.length;x++)
+            trees[x].writeTree(state,dataOutput);
+        }
+
+    /** Overridden for the GPIndividual genotype. */
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int treelength = dataInput.readInt();
+        if (trees == null || treelength != trees.length) // wrong size!
+            state.output.fatal("Number of trees differ in GPIndividual when reading from readGenotype(EvolutionState, DataInput).");
+        for(int x=0;x<trees.length;x++)
+            trees[x].readTree(state,dataInput);
+        }
+
+    public void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // Read my trees
+        for(int x=0;x<trees.length;x++)
+            {
+            reader.readLine();  // throw it away -- it's the tree indicator
+            trees[x].readTree(state,reader);
+            }
+        }
+
+    /** Deep-clones the GPIndividual.  Note that you should not deep-clone the prototypical GPIndividual
+        stored in GPSpecies: they contain blank GPTrees with null roots, and this method,
+        which calls GPTree.clone(), will produce a NullPointerException as a result. Instead, you probably
+        want to use GPSpecies.newIndividual(...) if you're thinking of playing with the prototypical
+        GPIndividual. */
+        
+    public Object clone()
+        {
+        // a deep clone
+                
+        GPIndividual myobj = (GPIndividual)(super.clone());
+
+        // copy the tree array
+        myobj.trees = new GPTree[trees.length];
+        for(int x=0;x<trees.length;x++)
+            {
+            myobj.trees[x] = (GPTree)(trees[x].clone());  // force a deep clone
+            myobj.trees[x].owner = myobj;  // reset owner away from me
+            }
+        return myobj;
+        }
+
+    /** Like clone(), but doesn't force the GPTrees to deep-clone themselves. */
+    public GPIndividual lightClone()
+        {
+        // a light clone
+        GPIndividual myobj = (GPIndividual)(super.clone());
+        
+        // copy the tree array
+        myobj.trees = new GPTree[trees.length];
+        for(int x=0;x<trees.length;x++)
+            {
+            myobj.trees[x] = (GPTree)(trees[x].lightClone());  // note light-cloned!
+            myobj.trees[x].owner = myobj;  // reset owner away from me
+            }
+        return myobj;
+        }
+
+    /** Returns the "size" of the individual, namely, the number of nodes
+        in all of its subtrees.  */
+    public long size()
+        {
+        long size = 0;
+        for(int x=0;x<trees.length;x++)
+            size += trees[x].child.numNodes(GPNode.NODESEARCH_ALL);
+        return size;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPInitializer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPInitializer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPInitializer.java	(revision 6152)
@@ -0,0 +1,311 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import ec.simple.SimpleInitializer;
+import ec.util.Parameter;
+import ec.EvolutionState;
+
+/* 
+ * GPInitializer.java
+ * 
+ * Created: Tue Oct  5 18:40:02 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPInitializer is a SimpleInitializer which sets up all the Cliques,
+ * ( the initial
+ * [tree/node]constraints, types, and function sets) for the GP system.
+ * 
+ * <p>Note that the Cliques must be set up in a very particular order:
+
+ <ol><li>GPType</li><li>GPNodeConstraints</li><li>GPFunctionSets</li><li>GPTreeConstraints</li></ol>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><tt>gp.type</tt></td>
+ <td>GPTypes</td></tr>
+ <tr><td valign=top><tt>gp.nc</tt></td>
+ <td>GPNodeConstraints</td></tr>
+ <tr><td valign=top><tt>gp.tc</tt></td>
+ <td>GPTreeConstraints</td></tr>
+ <tr><td valign=top><tt>gp.fs</tt></td>
+ <td>GPFunctionSets</td></tr>
+
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPInitializer extends SimpleInitializer 
+    {
+    // used just here, so far as I know :-)
+    public static final int SIZE_OF_BYTE = 256;
+    public final static String P_TYPE = "type";
+    public final static String P_NODECONSTRAINTS = "nc";
+    public final static String P_TREECONSTRAINTS = "tc";
+    public final static String P_FUNCTIONSETS = "fs";
+    public final static String P_SIZE = "size";
+    public final static String P_ATOMIC = "a";
+    public final static String P_SET = "s";
+    
+    /**
+     * TODO Comment these members.
+     * TODO Make clients of these members more efficient by reducing unnecessary casting.
+     */
+    public Hashtable typeRepository;
+    public GPType[] types;
+    public int numAtomicTypes;
+    public int numSetTypes;
+    
+    public Hashtable nodeConstraintRepository;
+    public GPNodeConstraints[] nodeConstraints;
+    public byte numNodeConstraints;
+    
+    public Hashtable functionSetRepository;
+
+    public Hashtable treeConstraintRepository;
+    public GPTreeConstraints[] treeConstraints;
+    public byte numTreeConstraints;
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        /**
+         * TODO Move setup methods to the corresponding GP type.
+         */
+        // This is a good place to set up the types.  We use our own base off the
+        // default GP base.  This MUST be done before loading constraints.
+        setupTypes(state,GPDefaults.base().push(P_TYPE));
+
+        // Now let's load our constraints and function sets also.
+        // This is done in a very specific order, don't change it or things
+        // will break.
+        setupNodeConstraints(
+            state,GPDefaults.base().push(P_NODECONSTRAINTS));
+        setupFunctionSets(
+            state,GPDefaults.base().push(P_FUNCTIONSETS));
+        setupTreeConstraints(
+            state,GPDefaults.base().push(P_TREECONSTRAINTS));
+        }
+
+    /** Sets up all the types, loading them from the parameter file.  This
+        must be called before anything is called which refers to a type by
+        name. */
+
+    public void setupTypes(final EvolutionState state,
+        final Parameter base)
+        {
+        state.output.message("Processing GP Types");
+        
+        typeRepository = new Hashtable();
+        numAtomicTypes = numSetTypes = 0;
+        
+        // How many atomic types do we have?
+        int x = state.parameters.getInt(base.push(P_ATOMIC).push(P_SIZE),null,1);
+        if (x<=0) 
+            state.output.fatal("The number of GP atomic types must be at least 1.",base.push(P_ATOMIC).push(P_SIZE));
+        
+        // Load our atomic types
+        
+        for(int y=0;y<x;y++)
+            new GPAtomicType().setup(state,base.push(P_ATOMIC).push(""+y));
+        
+        // How many set types do we have?
+        if (state.parameters.exists(base.push(P_SET).push(P_SIZE), null))
+            {
+            x =  state.parameters.getInt(base.push(P_SET).push(P_SIZE),null,1);
+            if (x<0) 
+                state.output.fatal("The number of GP set types must be at least 0.",base.push(P_SET).push(P_SIZE));
+            }
+        else // no set types
+            x = 0;
+        
+        // Load our set types
+        
+        for(int y=0;y<x;y++)
+            new GPSetType().setup(state,base.push(P_SET).push(""+y));
+        
+        // Postprocess the types
+        postProcessTypes();
+        }
+    
+    /** Assigns unique integers to each atomic type, and sets up compatibility
+        arrays for set types.  If you add new types (heaven forbid), you
+        should call this method again to get all the types set up properly. 
+        However, you will have to set up the function sets again as well,
+        as their arrays are based on these type numbers. */
+    public void postProcessTypes()
+        {
+        // assign positive integers and 0 to atomic types
+        int x = 0;
+        Enumeration e = typeRepository.elements();
+        while(e.hasMoreElements())
+            {
+            GPType t = (GPType)(e.nextElement());
+            if (t instanceof GPAtomicType)
+                { t.type = x; x++; }
+            }
+        
+        // at this point, x holds the number of atomic types.
+        numAtomicTypes = x;
+        
+        // assign additional positive integers to set types
+        // and set up arrays for the set types
+        e = typeRepository.elements();
+        while(e.hasMoreElements())
+            {
+            GPType t = (GPType)(e.nextElement());
+            if (t instanceof GPSetType)
+                {
+                ((GPSetType)t).postProcessSetType(numAtomicTypes);
+                t.type = x; x++;
+                }
+            }
+        
+        // at this point, x holds the number of set types + atomic types
+        numSetTypes = x - numAtomicTypes;
+        
+        // make an array for convenience.  Presently rarely used.
+        types = new GPType[numSetTypes + numAtomicTypes];
+        e = typeRepository.elements();
+        while(e.hasMoreElements())
+            {
+            GPType t = (GPType)(e.nextElement());
+            types[t.type] = t;
+            }
+        }
+    
+    
+    /** Sets up all the GPNodeConstraints, loading them from the parameter
+        file.  This must be called before anything is called which refers
+        to a type by name. */
+    
+    public void setupNodeConstraints(
+        final EvolutionState state,
+        final Parameter base)
+        {
+        state.output.message("Processing GP Node Constraints");
+        
+        nodeConstraintRepository = new Hashtable();
+        nodeConstraints = new GPNodeConstraints[SIZE_OF_BYTE];
+        numNodeConstraints = 0;
+        
+        // How many GPNodeConstraints do we have?
+        int x = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (x<=0) 
+            state.output.fatal("The number of GP node constraints must be at least 1.",
+                base.push(P_SIZE));
+        
+        // Load our constraints
+        for (int y=0;y<x;y++)
+            {
+            GPNodeConstraints c;
+            // Figure the constraint class
+            if (state.parameters.exists(base.push(""+y), null))
+                c = (GPNodeConstraints)(state.parameters.getInstanceForParameterEq(
+                        base.push(""+y),null,GPNodeConstraints.class));
+            else
+                {
+                state.output.message("No GP Node Constraints specified, assuming the default class: ec.gp.GPNodeConstraints for " +  base.push(""+y));
+                c = new GPNodeConstraints();
+                }
+            c.setup(state,base.push(""+y));
+            }
+        
+        // set our constraints array up
+        Enumeration e = nodeConstraintRepository.elements();
+        while(e.hasMoreElements())
+            {
+            GPNodeConstraints c = (GPNodeConstraints)(e.nextElement());
+            c.constraintNumber = numNodeConstraints;
+            nodeConstraints[numNodeConstraints] = c;
+            numNodeConstraints++;
+            }
+        }
+    
+    
+    public void setupFunctionSets(final EvolutionState state,
+        final Parameter base)
+        {
+        state.output.message("Processing GP Function Sets");
+        
+        functionSetRepository = new Hashtable();
+        // How many GPFunctionSets do we have?
+        int x = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (x<=0) 
+            state.output.fatal("The number of GPFunctionSets must be at least 1.",base.push(P_SIZE));
+        
+        // Load our FunctionSet
+        for (int y=0;y<x;y++)
+            {
+            GPFunctionSet c;
+            // Figure the GPFunctionSet class
+            if (state.parameters.exists(base.push(""+y), null))
+                c = (GPFunctionSet)(state.parameters.getInstanceForParameterEq(
+                        base.push(""+y),null,GPFunctionSet.class));
+            else
+                {
+                state.output.message("No GPFunctionSet specified, assuming the default class: ec.gp.GPFunctionSet for " + base.push(""+y));
+                c = new GPFunctionSet();
+                }
+            c.setup(state,base.push(""+y));
+            }
+        }
+        
+
+    /** Sets up all the GPTreeConstraints, loading them from the parameter
+        file.  This must be called before anything is called which refers
+        to a type by name. */
+        
+    public void setupTreeConstraints(
+        final EvolutionState state,
+        final Parameter base)
+        {
+        state.output.message("Processing GP Tree Constraints");
+            
+        treeConstraintRepository = new Hashtable();
+        treeConstraints = new GPTreeConstraints[SIZE_OF_BYTE];
+        numTreeConstraints = 0;
+        // How many GPTreeConstraints do we have?
+        int x = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (x<=0) 
+            state.output.fatal("The number of GP tree constraints must be at least 1.",base.push(P_SIZE));
+            
+        // Load our constraints
+        for (int y=0;y<x;y++)
+            {
+            GPTreeConstraints c;
+            // Figure the constraint class
+            if (state.parameters.exists(base.push(""+y), null))
+                c = (GPTreeConstraints)(state.parameters.getInstanceForParameterEq(
+                        base.push(""+y),null,GPTreeConstraints.class));
+            else
+                {
+                state.output.message("No GP Tree Constraints specified, assuming the default class: ec.gp.GPTreeConstraints for " + base.push(""+y));
+                c = new GPTreeConstraints();
+                }
+            c.setup(state,base.push(""+y));
+            }
+            
+        // set our constraints array up
+        Enumeration e = treeConstraintRepository.elements();
+        while(e.hasMoreElements())
+            {
+            GPTreeConstraints c = (GPTreeConstraints)(e.nextElement());
+            c.constraintNumber = numTreeConstraints;
+            treeConstraints[numTreeConstraints] = c;
+            numTreeConstraints++;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNode.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNode.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNode.java	(revision 6152)
@@ -0,0 +1,1391 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import java.io.*;
+import ec.util.*;
+import ec.EvolutionState;
+
+/* 
+ * GPNode.java
+ * 
+ * Created: Fri Aug 27 17:14:12 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPNode is a GPNodeParent which is the abstract superclass of
+ * all GP function nodes in trees.  GPNode contains quite a few functions
+ * for cloning subtrees in special ways, counting the number of nodes
+ * in subtrees in special ways, and finding specific nodes in subtrees.
+ *
+ * GPNode's lightClone() method does not clone its children (it copies the
+ * array, but that's it).  If you want to deep-clone a tree or subtree, you
+ * should use one of the cloneReplacing(...) methods instead.
+ *
+ * <p>GPNodes contain a number of important items:
+ * <ul><li>A <i>constraints</i> object which defines the name of the node,
+ * its arity, and its type constraints. This
+ * object is shared with all GPNodes of the same function name/arity/returntype/childtypes.
+ * <li>A <i>parent</i>.  This is either another GPNode, or (if this node
+ * is the root) a GPTree.
+ * <li>Zero or more <i>children</i>, which are GPNodes.
+ * <li>An argument position in its parent.
+ * </ul>
+ *
+
+ * <p>In addition to serialization for checkpointing, GPNodes may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeNode(...,DataOutput)/readNode(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives a GPNode in binary.  It is the most efficient approach to sending
+ * GPNodes over networks, etc.  The default versions of writeNode/readNode both generate errors.
+ * GPNode subclasses should override them to provide more functionality, particularly if you're planning on using
+ * ECJ in a distributed fashion.  Both of these functions are called by GPNode's readRootedTree/writeRootedTree
+ * respectively, which handle the reading/printing of the trees as a whole.
+ *
+ * <li><b>printNode(...,PrintWriter)/readNode(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives a GPNode in text encoded such that the GPNode is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  Both of these functions are called by GPNode's readRootedTree/writeRootedTree
+ * respectively, which handle the reading/printing of the trees as a whole.  Notably readRootedNode
+ * will try to determine what kind of node is next, then call <b>readNode</b> on the prototype for that
+ * node to generate the node.  <b>printNode</b> by default calls toString() and
+ * prints the result, though subclasses often override this to provide additional functionality (notably
+ * ERCs).
+ *
+ * <li><b>printNodeForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints a GPNode in a fashion intended for human consumption only.
+ * <b>printNodeForHumans</b> by default calls toStringForHumans() (which by default calls toString()) and
+ * prints the result.  printNodeForHumans is called by <b>printRootedTreeForHumans</b>, which handles
+ * printing of the entire GPNode tree.
+ * </ul>
+
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>nc</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of the node constraints for the GPNode)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.node
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class GPNode implements GPNodeParent, Prototype
+    {
+    public static final String P_NODE = "node";
+    public static final String P_NODECONSTRAINTS = "nc";
+    public static final String GPNODEPRINTTAB = "    ";
+    public static final int MAXPRINTBYTES = 40;
+
+    public static final int NODESEARCH_ALL = 0;
+    public static final int NODESEARCH_TERMINALS = 1;
+    public static final int NODESEARCH_NONTERMINALS = 2;
+    public static final int NODESEARCH_CUSTOM = 3;
+
+    public static final int SITUATION_NEWIND = 0;
+    public static final int SITUATION_MUTATION = 1;
+    
+    // beats me if Java compilers will take advantage of the int->byte shortening.
+    // They may want everything aligned, in which case they may buffer the object
+    // anyway, hope not!
+
+    /** The GPNode's parent.  4 bytes.  :-(  But it really helps simplify breeding. */
+    public GPNodeParent parent;
+    public GPNode children[];
+    /** The argument position of the child in its parent. 
+        This is a byte to save space (GPNode is the critical object space-wise) -- 
+        besides, how often do you have 256 children? You can change this to a short
+        or int easily if you absolutely need to.  It's possible to eliminate even
+        this and have the child find itself in its parent, but that's an O(children[])
+        operation, and probably not inlinable, so I figure a byte is okay. */
+    public byte argposition;
+    /** The GPNode's constraints.  This is a byte to save space -- how often do
+        you have 256 different GPNodeConstraints?  Well, I guess it's not infeasible.
+        You can increase this to an int without much trouble.  You typically 
+        shouldn't access the constraints through this variable -- use the constraints(state)
+        method instead. */
+    public byte constraints;
+
+    /* Returns the GPNode's constraints.  A good JIT compiler should inline this. */
+    public final GPNodeConstraints constraints(final GPInitializer initializer) 
+        { 
+        return initializer.nodeConstraints[constraints]; 
+        }
+
+    /** The default base for GPNodes -- defined even though
+        GPNode is abstract so you don't have to in subclasses. */
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_NODE);
+        }
+
+    /** You ought to override this method to check to make sure that the
+        constraints are valid as best you can tell.  Things you might
+        check for:
+
+        <ul>
+        <li> children.length is correct
+        <li> certain arguments in constraints.childtypes are 
+        swap-compatible with each other
+        <li> constraints.returntype is swap-compatible with appropriate 
+        arguments in constraints.childtypes
+        </ul>
+        
+        You can't check for everything, of course, but you might try some
+        obvious checks for blunders.  The default version of this method
+        is empty for now, but you should still call super.checkConstraints(state)
+        just to be certain.
+
+        The ultimate caller of this method must guarantee that he will eventually
+        call state.output.exitIfErrors(), so you can freely use state.output.error
+        instead of state.output.fatal(), which will help a lot.
+        
+        Warning: this method may get called more than once.
+    */
+
+    public void checkConstraints(final EvolutionState state,
+        final int tree,
+        final GPIndividual typicalIndividual,
+        final Parameter individualBase)
+        { }
+
+    /** 
+        Sets up a <i>prototypical</i> GPNode with those features all nodes of that
+        prototype share, and nothing more.  So no filled-in children, 
+        no argposition, no parent.  Yet.
+
+        This must be called <i>after</i> the GPTypes and GPNodeConstraints 
+        have been set up.  Presently they're set up in GPInitializer,
+        which gets called before this does, so we're safe. 
+        
+        You should override this if you need to load some special features on
+        a per-function basis.  Note that base hangs off of a function set, so
+        this method may get called for different instances in the same GPNode
+        class if they're being set up as prototypes for different GPFunctionSets.
+
+        If you absolutely need some global base, then you should use something
+        hanging off of GPDefaults.base().
+
+        The ultimate caller of this method must guarantee that he will eventually
+        call state.output.exitIfErrors(), so you can freely use state.output.error
+        instead of state.output.fatal(), which will help a lot.
+    */
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        // determine my constraints -- at this point, the constraints should have been loaded.
+        String s = state.parameters.getString(base.push(P_NODECONSTRAINTS),
+            def.push(P_NODECONSTRAINTS));
+        if (s==null)
+            state.output.fatal("No node constraints are defined for the GPNode " + 
+                toStringForError(),base.push(P_NODECONSTRAINTS),
+                def.push(P_NODECONSTRAINTS));
+        else constraints = GPNodeConstraints.constraintsFor(s,state).constraintNumber;
+
+        // The number of children is determined by the constraints.  Though
+        // for some special versions of GPNode, we may have to enforce certain
+        // rules, checked in children versions of setup(...)
+
+        GPNodeConstraints constraintsObj = constraints(((GPInitializer)state.initializer));
+        int len = constraintsObj.childtypes.length;
+        if (len == 0) children = constraintsObj.zeroChildren;
+        else children = new GPNode[len];
+        }
+
+    /** Returns the argument type of the slot that I fit into in my parent.  
+        If I'm the root, returns the treetype of the GPTree. */
+    public final GPType parentType(final GPInitializer initializer)
+        {
+        if (parent instanceof GPNode)
+            return ((GPNode)parent).constraints(initializer).childtypes[argposition];
+        else // it's a tree root
+            return ((GPTree)parent).constraints(initializer).treetype;
+        }
+
+
+    /** Verification of validity of the node in the tree -- strictly for debugging purposes only */
+    final int verify(EvolutionState state, GPFunctionSet set, int index)
+        {
+        if (!(state.initializer instanceof GPInitializer))
+            { state.output.error("" + index + ": Initializer is not a GPInitializer"); return index+1; }
+            
+        GPInitializer initializer = (GPInitializer)(state.initializer);
+        
+        // 1. Is the parent and argposition right?
+        if (parent == null)
+            { state.output.error("" + index + ": null parent"); return index+1; }
+        if (argposition < 0)
+            { state.output.error("" + index + ": negative argposition"); return index+1; }
+        if (parent instanceof GPTree && ((GPTree)parent).child != this)
+            { state.output.error("" + index + ": I think I am a root node, but my GPTree does not think I am a root node"); return index+1; }
+        if (parent instanceof GPTree && argposition != 0)
+            { state.output.error("" + index + ": I think I am a root node, but my argposition is not 0"); return index+1; }
+        if (parent instanceof GPNode && argposition >= ((GPNode)parent).children.length)
+            { state.output.error("" + index + ": argposition outside range of parent's children array"); return index+1; }
+        if (parent instanceof GPNode && ((GPNode)parent).children[argposition] != this)
+            { state.output.error("" + index + ": I am not found in the provided argposition ("+argposition+") of my parent's children array"); return index+1; }
+
+        // 2. Are the parents and argpositions right for my kids? [need to double check]
+        if (children==null)
+            { state.output.error("" + index + ": Null Children Array"); return index+1; }
+        for(int x=0;x<children.length;x++)
+            {
+            if (children[x] == null)
+                { state.output.error("" + index + ": Null Child (#" + x + " )"); return index+1; }
+            if (children[x].parent != this)
+                { state.output.error("" + index + ": child #"+x+" does not have me as a parent"); return index+1; }
+            if (children[x].argposition < 0)
+                { state.output.error("" + index + ": child #"+x+" argposition is negative"); return index+1; }
+            if (children[x].argposition != x)
+                { state.output.error("" + index + ": child #"+x+" argposition does not match position in the children array"); return index+1; }
+            }
+        
+        // 3. Do I have valid constraints?
+        if (constraints < 0 || constraints >= initializer.numNodeConstraints)
+            { state.output.error("" + index + ": Preposterous node constraints (" + constraints + ")"); return index+1; }
+        
+        // 4. Am I swap-compatable with my parent?
+        if (parent instanceof GPNode && !constraints(initializer).returntype.compatibleWith(initializer, 
+                ((GPNode)(parent)).constraints(initializer).childtypes[argposition]))
+            { state.output.error("" + index + ": Incompatable GP type between me and my parent"); return index+1; }
+        if (parent instanceof GPTree && !constraints(initializer).returntype.compatibleWith(initializer,
+                ((GPTree)(parent)).constraints(initializer).treetype))
+            { state.output.error("" + index + ": I am root, but incompatable GP type between me and my tree return type"); return index+1; }
+        
+        // 5. Is my class in the GPFunctionSet?
+        GPNode[] nodes = set.nodesByArity[constraints(initializer).returntype.type][children.length];
+        boolean there = false;
+        for(int x=0;x<nodes.length;x++)
+            if (nodes[x].getClass() == this.getClass()) { there = true; break; }
+        if (!there)
+            { state.output.error("" + index + ": I'm not in the function set."); return index+1; }
+            
+        // otherwise we've passed -- go to next node
+        index++;
+        for(int x=0;x<children.length;x++)
+            index = children[x].verify(state, set, index);
+        state.output.exitIfErrors();
+        return index;
+        }
+
+
+    /** Returns true if I can swap into node's position. */
+
+    public final boolean swapCompatibleWith(final GPInitializer initializer,
+        final GPNode node)
+        {
+        // I'm atomically compatible with him; a fast check
+        if (constraints(initializer).returntype==node.constraints(initializer).returntype)  // no need to check for compatibility
+            return true;
+
+        // I'm set compatible with his parent's swap-position
+        GPType type;
+        if (node.parent instanceof GPNode)  // it's a GPNode
+            type = 
+                ((GPNode)(node.parent)).constraints(initializer).childtypes[node.argposition];
+        else // it's a tree root; I'm set compatible with the GPTree type
+            type = 
+                ((GPTree)(node.parent)).constraints(initializer).treetype;
+        
+        return constraints(initializer).returntype.compatibleWith(initializer,type);
+        }
+
+    /** Returns the number of nodes, constrained by g.test(...)
+        in the subtree for which this GPNode is root.  This might
+        be sped up by caching the value.  O(n). */
+    public int numNodes(final GPNodeGatherer g)
+        {
+        int s=0;
+        for(int x=0;x<children.length;x++) s += children[x].numNodes(g);
+        return s + (g.test(this) ? 1 : 0);
+        }
+
+    /** Returns the number of nodes, constrained by nodesearch,
+        in the subtree for which this GPNode is root.
+        This might be sped up by cacheing the value somehow.  O(n). */
+    public int numNodes(final int nodesearch)
+        {
+        int s=0;
+        for(int x=0;x<children.length;x++) s += children[x].numNodes(nodesearch);
+        return s + ((nodesearch==NODESEARCH_ALL ||
+                (nodesearch==NODESEARCH_TERMINALS && children.length==0) ||
+                (nodesearch==NODESEARCH_NONTERMINALS && children.length>0)) ? 1 : 0);
+        }
+
+    /** Returns the depth of the tree, which is a value >= 1.  O(n). */
+    public int depth()
+        {
+        int d=0;
+        int newdepth;
+        for(int x=0;x<children.length;x++)
+            {
+            newdepth = children[x].depth();
+            if (newdepth>d) d = newdepth;
+            }
+        return d + 1;
+        }
+        
+    /** Returns the path length of the tree, which is the sum of all paths from all nodes to the root.   O(n). */
+    public int pathLength(int nodesearch) { return pathLength(NODESEARCH_ALL, 0); }
+    
+    int pathLength(int nodesearch, int currentDepth)
+        {
+        int sum = currentDepth;
+        if (nodesearch == NODESEARCH_NONTERMINALS && children.length==0 ||  // I'm a leaf, don't include me
+            nodesearch == NODESEARCH_TERMINALS && children.length > 0)  // I'm a nonleaf, don't include me
+            sum = 0;
+            
+        for(int x=0;x<children.length;x++)
+            sum += pathLength(nodesearch, currentDepth + 1);
+        return sum;
+        }
+        
+    /** Returns the mean depth of the tree, which is path length (sum of all paths from all nodes to the root) divided by the number of nodes.  O(n). */
+    int meanDepth(int nodesearch)
+        {
+        return pathLength(nodesearch) / numNodes(nodesearch);
+        }
+
+    /** Returns the depth at which I appear in the tree, which is a value >= 0. O(ln n) avg.*/
+    public int atDepth()
+        {
+        // -- new code, no need for recursion
+        GPNodeParent cparent = parent;
+        int count=0;
+
+        while(cparent!=null && cparent instanceof GPNode)
+            {
+            count++;
+            cparent = ((GPNode)(cparent)).parent;
+            }
+        return count;
+
+        /* // -- old code
+           if (parent==null) return 0;
+           if (!(parent instanceof GPNode))  // found the root!
+           return 0;
+           else return 1 + ((GPNode)parent).atDepth();
+        */
+        }
+
+    /** Returns the p'th node, constrained by nodesearch,
+        in the subtree for which this GPNode is root.
+        Use numNodes(nodesearch) to determine the total number.  Or if
+        you used numNodes(g), then when
+        nodesearch == NODESEARCH_CUSTOM, g.test(...) is used
+        as the constraining predicate.
+        p ranges from 0 to this number minus 1. O(n). The
+        resultant node is returned in <i>g</i>.*/
+    public int nodeInPosition(int p, final GPNodeGatherer g, final int nodesearch)
+        {
+        // am I of the type I'm looking for?
+        if (nodesearch==NODESEARCH_ALL ||
+            (nodesearch==NODESEARCH_TERMINALS && children.length==0) ||
+            (nodesearch==NODESEARCH_NONTERMINALS && children.length>0) ||
+            (nodesearch==NODESEARCH_CUSTOM && g.test(this)))
+            {
+            // is the count now at 0?  Is it me?
+            if (p==0)
+                {
+                g.node = this; 
+                return -1; // found it
+                }
+            // if it's not me, drop the count by 1
+            else p--;
+            }
+        
+        // regardless, check my children if I've not returned by now
+        for(int x=0;x<children.length;x++)
+            {
+            p = children[x].nodeInPosition(p,g,nodesearch);
+            if (p==-1) return -1; // found it
+            }
+        return p;
+        }
+
+    /** Returns the root ancestor of this node.  O(ln n) average case,
+        O(n) worst case. */
+
+    public GPNodeParent rootParent()
+        {
+
+        // -- new code, no need for recursion
+        GPNodeParent cparent = this;
+        while(cparent!=null && cparent instanceof GPNode)
+            cparent = ((GPNode)(cparent)).parent;
+        return cparent; 
+        }
+
+    /** Returns true if the subtree rooted at this node contains subnode.  O(n). */
+    public boolean contains(final GPNode subnode)
+        {
+        if (subnode==this) return true;
+        for(int x=0;x<children.length;x++)
+            if (children[x].contains(subnode)) return true;
+        return false;
+        }
+
+
+    /** Starts a node in a new life immediately after it has been cloned.
+        The default version of this function does nothing.  The purpose of
+        this function is to give ERCs a chance to set themselves to a new
+        random value after they've been cloned from the prototype.
+        You should not assume that the node is properly connected to other
+        nodes in the tree at the point this method is called. */
+
+    public void resetNode(final EvolutionState state, final int thread) { }
+
+    /** A convenience function for identifying a GPNode in an error message */
+    public String errorInfo() { return "GPNode " + toString() + " in the function set for tree " + ((GPTree)(rootParent())).treeNumber(); }
+
+
+    public GPNode lightClone()
+        { 
+        try
+            {
+            GPNode obj = (GPNode)(super.clone());
+            int len = children.length;
+            if (len == 0) obj.children = children;  // we'll share arrays -- probably just using GPNodeConstraints.zeroChildren anyway
+            else obj.children = new GPNode[len];
+            return obj;
+            }
+        catch (CloneNotSupportedException e)
+            { throw new InternalError(); } // never happens
+        }
+
+    /** Deep-clones the tree rooted at this node, and returns the entire
+        copied tree.  The result has everything set except for the root
+        node's parent and argposition.  This method is identical to
+        cloneReplacing for historical reasons, except that it returns
+        the object as an Object, not a GPNode. */    
+ 
+    public Object clone()
+        { 
+        GPNode newnode = (GPNode)(lightClone());
+        for(int x=0;x<children.length;x++)
+            {
+            newnode.children[x] = (GPNode)(children[x].cloneReplacing()); 
+            // if you think about it, the following CAN'T be implemented by
+            // the children's clone method.  So it's set here.
+            newnode.children[x].parent = newnode;
+            newnode.children[x].argposition = (byte)x;
+            }
+        return newnode;
+        }
+
+    /** Deep-clones the tree rooted at this node, and returns the entire
+        copied tree.  The result has everything set except for the root
+        node's parent and argposition.  This method is identical to
+        cloneReplacing for historical reasons, except that it returns
+        the object as a GPNode, not an Object. 
+        @deprecated use clone() instead.
+    */    
+ 
+    public final GPNode cloneReplacing() 
+        {
+        return (GPNode)clone();
+        }
+
+
+    /** Deep-clones the tree rooted at this node, and returns the entire
+        copied tree.  If the node oldSubtree is located somewhere in this
+        tree, then its subtree is replaced with a deep-cloned copy of
+        newSubtree.  The result has everything set except for the root
+        node's parent and argposition. */
+ 
+    public final GPNode cloneReplacing(final GPNode newSubtree, final GPNode oldSubtree) 
+        {
+        if (this==oldSubtree)
+            return newSubtree.cloneReplacing();
+        else
+            {
+            GPNode newnode = (GPNode)(lightClone());
+            for(int x=0;x<children.length;x++)
+                {
+                newnode.children[x] = (GPNode)(children[x].cloneReplacing(newSubtree,oldSubtree)); 
+                // if you think about it, the following CAN'T be implemented by
+                // the children's clone method.  So it's set here.
+                newnode.children[x].parent = newnode;
+                newnode.children[x].argposition = (byte)x;
+                }
+            return newnode;     
+            }
+        }
+
+
+
+    /** Deep-clones the tree rooted at this node, and returns the entire
+        copied tree.  If the node oldSubtree is located somewhere in this
+        tree, then its subtree is replaced with
+        newSubtree (<i>not</i> a copy of newSubtree).  
+        The result has everything set except for the root
+        node's parent and argposition. */
+ 
+    public final GPNode cloneReplacingNoSubclone(final GPNode newSubtree, final GPNode oldSubtree) 
+        {
+        if (this==oldSubtree)
+            {
+            return newSubtree;
+            }
+        else
+            {
+            GPNode newnode = (GPNode)(lightClone());
+            for(int x=0;x<children.length;x++)
+                {
+                newnode.children[x] = (GPNode)(children[x].cloneReplacingNoSubclone(newSubtree,oldSubtree)); 
+                // if you think about it, the following CAN'T be implemented by
+                // the children's clone method.  So it's set here.
+                newnode.children[x].parent = newnode;
+                newnode.children[x].argposition = (byte)x;
+                }
+            return newnode;     
+            }
+        }
+
+
+
+
+
+
+    /** Deep-clones the tree rooted at this node, and returns the entire
+        copied tree.  If a node in oldSubtrees is located somewhere in this
+        tree, then its subtree is replaced with a deep-cloned copy of the
+        subtree rooted at its equivalent number in 
+        newSubtrees.  The result has everything set except for the root
+        node's parent and argposition. */
+ 
+    public final GPNode cloneReplacing(final GPNode[] newSubtrees, final GPNode[] oldSubtrees) 
+        {
+        // am I a candidate?
+        int candidate = -1;
+        for(int x=0;x<oldSubtrees.length;x++)
+            if (this==oldSubtrees[x]) { candidate=x; break; }
+
+        if (candidate >= 0)
+            return newSubtrees[candidate].cloneReplacing(newSubtrees,oldSubtrees);
+        else
+            {
+            GPNode newnode = (GPNode)(lightClone());
+            for(int x=0;x<children.length;x++)
+                {
+                newnode.children[x] = (GPNode)(children[x].cloneReplacing(newSubtrees,oldSubtrees)); 
+                // if you think about it, the following CAN'T be implemented by
+                // the children's clone method.  So it's set here.
+                newnode.children[x].parent = newnode;
+                newnode.children[x].argposition = (byte)x;
+                }
+            return newnode;     
+            }
+        }
+
+
+    
+    /** Clones a new subtree, but with the single node oldNode 
+        (which may or may not be in the subtree) 
+        replaced with a newNode (not a clone of newNode).  
+        These nodes should be
+        type-compatible both in argument and return types, and should have
+        the same number of arguments obviously.  This function will <i>not</i>
+        check for this, and if they are not the result is undefined. */
+
+
+    public final GPNode cloneReplacingAtomic(final GPNode newNode, final GPNode oldNode) 
+        {
+        int numArgs;
+        GPNode curnode;
+        if (this==oldNode)
+            {
+            numArgs = Math.max(newNode.children.length,children.length);
+            curnode = newNode;
+            }
+        else
+            {
+            numArgs = children.length;
+            curnode = (GPNode)lightClone();
+            }
+
+        // populate
+
+        for(int x=0;x<numArgs;x++)
+            {
+            curnode.children[x] = (GPNode)(children[x].cloneReplacingAtomic(newNode,oldNode)); 
+            // if you think about it, the following CAN'T be implemented by
+            // the children's clone method.  So it's set here.
+            curnode.children[x].parent = curnode;
+            curnode.children[x].argposition = (byte)x;
+            }
+        return curnode;
+        }
+
+
+
+
+
+    /** Clones a new subtree, but with each node in oldNodes[] respectively
+        (which may or may not be in the subtree) replaced with
+        the equivalent
+        nodes in newNodes[] (and not clones).  
+        The length of oldNodes[] and newNodes[] should
+        be the same of course.  These nodes should be
+        type-compatible both in argument and return types, and should have
+        the same number of arguments obviously.  This function will <i>not</i>
+        check for this, and if they are not the result is undefined. */
+
+
+    public final GPNode cloneReplacingAtomic(final GPNode[] newNodes, final GPNode[] oldNodes) 
+        {
+        int numArgs;
+        GPNode curnode;
+        int found = -1;
+        
+        for(int x=0;x<newNodes.length;x++)
+            {
+            if (this==oldNodes[x]) { found=x; break; }
+            }
+
+        if (found > -1)
+            {
+            numArgs = Math.max(newNodes[found].children.length,
+                children.length);
+            curnode = newNodes[found];
+            }
+        else
+            {
+            numArgs = children.length;
+            curnode = (GPNode)lightClone();
+            }
+
+        // populate
+
+        for(int x=0;x<numArgs;x++)
+            {
+            curnode.children[x] = (GPNode)(children[x].cloneReplacingAtomic(newNodes,oldNodes)); 
+            // if you think about it, the following CAN'T be implemented by
+            // the children's clone method.  So it's set here.
+            curnode.children[x].parent = curnode;
+            curnode.children[x].argposition = (byte)x;
+            }
+        return curnode;
+        }
+
+
+
+
+
+    /** Replaces the node with another node in its position in the tree. 
+        newNode should already have been cloned and ready to go.
+        We presume that the other node is type-compatible and
+        of the same arity (these things aren't checked).  */
+        
+    public final void replaceWith(final GPNode newNode)
+        {
+        // copy the parent and argposition
+        newNode.parent = parent;
+        newNode.argposition = argposition;
+        
+        // replace the parent pointer
+        if (parent instanceof GPNode)
+            ((GPNode)(parent)).children[argposition] = newNode;
+        else
+            ((GPTree)(parent)).child = newNode;
+            
+        // replace the child pointers
+        for(byte x = 0;x<children.length;x++)
+            {
+            newNode.children[x] = children[x];
+            newNode.children[x].parent = newNode;
+            newNode.children[x].argposition = x;
+            }
+        }
+    
+    /** Returns true if I and the provided node are the same kind of
+        node -- that is, we could have both been cloned() and reset() from
+        the same prototype node.  The default form of this function returns
+        true if I and the node have the same class, the same length children
+        array, and the same constraints.  You may wish to override this in
+        certain circumstances.   Here's an example of how nodeEquivalentTo(node)
+        differs from nodeEquals(node): two ERCs, both of
+        the same class, but one holding '1.23' and the other holding '2.45', which
+        came from the same prototype node in the same function set.
+        They should NOT be nodeEquals(...) but *should* be nodeEquivalent(...). */
+    public boolean nodeEquivalentTo(GPNode node)
+        {
+        return (this.getClass().equals(node.getClass()) && 
+            children.length == node.children.length &&
+            constraints == node.constraints);
+        }
+
+
+    /** Returns a hashcode usually associated with all nodes that are 
+        equal to you (using nodeEquals(...)).  The default form
+        of this method returns the hashcode of the node's class.
+        ERCs in particular probably will want to override this method.
+    */
+    public int nodeHashCode()
+        {
+        return (this.getClass().hashCode());
+        }
+
+    /** Returns a hashcode associated with all the nodes in the tree.  
+        The default version adds the hash of the node plus its child
+        trees, rotated one-off each time, which seems reasonable. */
+    public int rootedTreeHashCode()
+        {
+        int hash = nodeHashCode();
+
+        for(int x=0;x<children.length;x++)
+            // rotate hash and XOR
+            hash =
+                (hash << 1 | hash >>> 31 ) ^
+                children[x].rootedTreeHashCode();
+        return hash;
+        }
+
+    /** Returns true if I am the "genetically" identical to this node, and our
+        children arrays are the same length, though
+        we may have different parents and children.  The default form
+        of this method simply calls the much weaker nodeEquivalentTo(node).  
+        You may need to override this to perform exact comparisons, if you're
+        an ERC, ADF, or ADM for example.  Here's an example of how nodeEquivalentTo(node)
+        differs from nodeEquals(node): two ERCs, both of
+        the same class, but one holding '1.23' and the other holding '2.45', which
+        came from the same prototype node in the same function set.
+        They should NOT be nodeEquals(...) but *should* be nodeEquivalent(...).  */
+    public boolean nodeEquals(final GPNode node)
+        {
+        return nodeEquivalentTo(node);
+        }
+
+    /** Returns true if the two rooted trees are "genetically" equal, though
+        they may have different parents.  O(n). */
+    public boolean rootedTreeEquals(final GPNode node)
+        {
+        if (!nodeEquals(node)) return false;
+        for (int x=0;x<children.length;x++)
+            if (!(children[x].rootedTreeEquals(node.children[x])))
+                return false;
+        return true;
+        }
+
+    /** Prints out a human-readable and Lisp-like atom for the node, 
+        and returns the number of bytes in the string that you sent
+        to the log (use print(),
+        not println()).  The default version gets the atom from
+        toStringForHumans(). 
+    */
+    public int printNodeForHumans(final EvolutionState state,
+        final int log)
+        {
+        return printNodeForHumans(state, log, Output.V_VERBOSE);
+        }
+
+    /** Prints out a human-readable and Lisp-like atom for the node, 
+        and returns the number of bytes in the string that you sent
+        to the log (use print(),
+        not println()).  The default version gets the atom from
+        toStringForHumans(). 
+        @deprecated Verbosity no longer has an effect. 
+    */
+    public int printNodeForHumans(final EvolutionState state,
+        final int log, 
+        final int verbosity)
+        {
+        String n = toStringForHumans();
+        state.output.print(n,log);
+        return n.length();
+        }
+
+
+    /** Prints out a COMPUTER-readable and Lisp-like atom for the node, which
+        is also suitable for readNode to read, and returns
+        the number of bytes in the string that you sent to the log (use print(),
+        not println()).  The default version gets the atom from toString().
+        O(1). 
+    */
+    public int printNode(final EvolutionState state, final int log)
+        {
+        printNode(state, log, Output.V_VERBOSE);
+        String n = toString();
+        return n.length();
+        }
+
+    /** Prints out a COMPUTER-readable and Lisp-like atom for the node, which
+        is also suitable for readNode to read, and returns
+        the number of bytes in the string that you sent to the log (use print(),
+        not println()).  The default version gets the atom from toString().
+        O(1). 
+        @deprecated Verbosity no longer has an effect. 
+    */
+    public int printNode(final EvolutionState state, final int log, 
+        final int verbosity)
+        {
+        String n = toString();
+        state.output.print(n,log);
+        return n.length();
+        }
+
+
+    /** Prints out a COMPUTER-readable and Lisp-like atom for the node, which
+        is also suitable for readNode to read, and returns
+        the number of bytes in the string that you sent to the log (use print(),
+        not println()).  The default version gets the atom from toString().
+        O(1). */
+
+    public int printNode(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        String n = toString();
+        writer.print(n);
+        return n.length();
+        }
+                
+    /** Returns a Lisp-like atom for the node and any nodes of the same class.
+        This will almost always be identical to the result of toString() (and the default
+        does exactly this), but for ERCs it'll be different: toString will include the
+        encoded constant data, whereas name() will not include this information and will
+        be the same for all ERCs of this type.  If two nodes are nodeEquivalentTo(...)
+        each other, then they will have the same name().  If two nodes are nodeEquals(...)
+        each other, then they will have the same toString().  */
+                
+    public String name() { return toString(); }
+
+    /** Returns a Lisp-like atom for the node which can be read in again by computer.
+        If you need to encode an integer or a float or whatever for some reason
+        (perhaps if it's an ERC), you should use the ec.util.Code library.  */
+
+    public abstract String toString();
+
+    /** Returns a Lisp-like atom for the node which is intended for human
+        consumption, and not to be read in again.  The default version
+        just calls toString(). */
+
+    public String toStringForHumans() { return toString(); }
+
+    /** Returns a description of the node that can make it easy to identify
+        in error messages (by default, at least its name and the tree it's found in).
+        It's okay if this is a reasonably expensive procedure -- it won't be called
+        a lot.  */
+
+    public String toStringForError() 
+        {
+        GPTree rootp = (GPTree)rootParent();
+        if (rootp!=null)
+            {
+            int tnum = ((GPTree)(rootParent())).treeNumber();
+            return toString() + (tnum == GPTree.NO_TREENUM ? "" : " in tree " + tnum);
+            }
+        else return toString();
+        }
+
+    /** Produces the Graphviz code for a Graphviz tree of the subtree rooted at this node.
+        For this to work, the output of toString() must not contain a double-quote. 
+        Note that this isn't particularly efficient and should only be used to generate
+        occasional trees for display, not for storing individuals or sending them over networks. */
+    public String makeGraphvizTree()
+        {
+        return "digraph g {\nnode [shape=rectangle];\n" + makeGraphvizSubtree("n") + "}\n";
+        }
+    
+    /** Produces the inner code for a graphviz subtree.  Called from makeGraphvizTree(). 
+        Note that this isn't particularly efficient and should only be used to generate
+        occasional trees for display, not for storing individuals or sending them over networks. */
+    protected String makeGraphvizSubtree(String prefix)
+        {
+        String body = prefix + "[label = \"" + toStringForHumans() + "\"];\n";
+        for(int x = 0; x < children.length; x++)
+            {
+            String newprefix;
+            if (x < 10) newprefix = prefix + x;
+            else newprefix = prefix + "n" + x;  // to distinguish it
+            
+            body = body + children[x].makeGraphvizSubtree(newprefix);
+            body = body + prefix + " -> " + newprefix + ";\n";
+            }
+        return body;
+        }
+
+    /** Produces the LaTeX code for a LaTeX tree of the subtree rooted at this node, using the <tt>epic</tt>
+        and <tt>fancybox</tt> packages, as described in sections 10.5.2 (page 307) 
+        and 10.1.3 (page 278) of <i>The LaTeX Companion</i>, respectively.  For this to
+        work, the output of toStringForHumans() must not contain any weird latex characters, notably { or } or % or \,
+        unless you know what you're doing. See the documentation for ec.gp.GPTree for information
+        on how to take this code snippet and insert it into your LaTeX file. 
+        Note that this isn't particularly efficient and should only be used to generate
+        occasional trees for display, not for storing individuals or sending them over networks. */
+    
+    public String makeLatexTree()
+        {
+        if (children.length==0)
+            return "\\gpbox{"+toStringForHumans()+"}";
+            
+        String s = "\\begin{bundle}{\\gpbox{"+toStringForHumans()+"}}";
+        for(int x=0;x<children.length;x++)
+            s = s + "\\chunk{"+children[x].makeLatexTree()+"}";
+        s = s + "\\end{bundle}";
+        return s;
+        }
+        
+    /** Producess a String consisting of the tree in pseudo-C form, given that the parent already will wrap the
+        expression in parentheses (or not).  In pseudo-C form, functions with one child are printed out as a(b), 
+        functions with more than two children are printed out as a(b, c, d, ...), and functions with exactly two
+        children are either printed as a(b, c) or in operator form as (b a c) -- for example, (b * c).  Whether
+        or not to do this depends on the setting of <tt>useOperatorForm</tt>.  Additionally, terminals will be
+        printed out either in variable form -- a -- or in zero-argument function form -- a() -- depending on
+        the setting of <tt>printTerminalsAsVariables</tt>.
+        Note that this isn't particularly efficient and should only be used to generate
+        occasional trees for display, not for storing individuals or sending them over networks. 
+    */
+                
+    public String makeCTree(boolean parentMadeParens, boolean printTerminalsAsVariables, boolean useOperatorForm)
+        {
+        if (children.length==0)
+            return (printTerminalsAsVariables ? toStringForHumans() : toStringForHumans() + "()");
+        else if (children.length==1)
+            return toStringForHumans() + "(" + children[0].makeCTree(true, printTerminalsAsVariables, useOperatorForm) + ")";
+        else if (children.length==2 && useOperatorForm)
+            return (parentMadeParens ? "" : "(") + 
+                children[0].makeCTree(false, printTerminalsAsVariables, useOperatorForm) + " " + 
+                toStringForHumans() + " " + children[1].makeCTree(false, printTerminalsAsVariables, useOperatorForm) + 
+                (parentMadeParens ? "" : ")");
+        else
+            {
+            String s = toStringForHumans() + "(" + children[0].makeCTree(true, printTerminalsAsVariables, useOperatorForm);
+            for(int x = 1; x < children.length;x++)
+                s = s + ", " + children[x].makeCTree(true, printTerminalsAsVariables, useOperatorForm);
+            return s + ")";
+            }
+        }
+
+    /**
+       Produces a tree for human consumption in Lisp form similar to that generated by printTreeForHumans().
+       Note that this isn't particularly efficient and should only be used to generate
+       occasional trees for display, not for storing individuals or sending them over networks.
+    */
+    public String makeLispTree()
+        {
+        if (children.length==0)
+            return toStringForHumans();
+        else
+            {
+            String s = "(" + toStringForHumans();
+            for(int x=0;x<children.length;x++)
+                s = s + " " + children[x].makeLispTree();
+            return s + ")";
+            }
+        }
+
+
+    /** Prints out the tree on a single line, with no ending \n, in a fashion that can
+        be read in later by computer. O(n).  
+        You should call this method with printbytes == 0. 
+    */
+    
+    public int printRootedTree(final EvolutionState state,
+        final int log, int printbytes)
+        {
+        return printRootedTree(state, log, Output.V_VERBOSE, printbytes);
+        }
+
+
+    /** Prints out the tree on a single line, with no ending \n, in a fashion that can
+        be read in later by computer. O(n).  
+        You should call this method with printbytes == 0. 
+        @Deprecated Verbosity no longer has an effect.
+    */
+    
+    public int printRootedTree(final EvolutionState state,
+        final int log, final int verbosity,
+        int printbytes)
+        {
+        if (children.length>0) { state.output.print(" (",verbosity,log); printbytes += 2; }
+        else { state.output.print(" ",log); printbytes += 1; }
+
+        printbytes += printNode(state,log);
+
+        for (int x=0;x<children.length;x++)
+            printbytes = children[x].printRootedTree(state,log,printbytes);
+        if (children.length>0) { state.output.print(")",log); printbytes += 1; }
+        return printbytes;
+        }
+
+
+    /** Prints out the tree on a single line, with no ending \n, in a fashion that can
+        be read in later by computer. O(n).  Returns the number of bytes printed.
+        You should call this method with printbytes == 0. */
+    
+    public int printRootedTree(final EvolutionState state, final PrintWriter writer,
+        int printbytes)
+        {
+        if (children.length>0) { writer.print(" ("); printbytes += 2; }
+        else { writer.print(" "); printbytes += 1; }
+
+        printbytes += printNode(state,writer);
+
+        for (int x=0;x<children.length;x++)
+            printbytes = children[x].printRootedTree(state,writer,printbytes);
+        if (children.length>0) { writer.print(")"); printbytes += 1; }
+        return printbytes;
+        }
+
+
+    /** Prints out the tree in a readable Lisp-like multi-line fashion. O(n).  
+        You should call this method with tablevel and printbytes == 0.  
+        No ending '\n' is printed.  
+    */
+    
+    public int printRootedTreeForHumans(final EvolutionState state, final int log,
+        int tablevel, int printbytes)
+        {
+        return printRootedTreeForHumans(state, log, Output.V_VERBOSE, tablevel, printbytes);
+        }
+
+    /** Prints out the tree in a readable Lisp-like multi-line fashion. O(n).  
+        You should call this method with tablevel and printbytes == 0.  
+        No ending '\n' is printed.  
+        @deprecated Verbosity no longer has an effect.
+    */
+    
+    public int printRootedTreeForHumans(final EvolutionState state, final int log,
+        final int verbosity,
+        int tablevel, int printbytes)
+        {
+        if (printbytes>MAXPRINTBYTES)
+            { 
+            state.output.print("\n",log);
+            tablevel++;
+            printbytes = 0;
+            for(int x=0;x<tablevel;x++)
+                state.output.print(GPNODEPRINTTAB,log);
+            }
+
+        if (children.length>0) { state.output.print(" (",log); printbytes += 2; }
+        else { state.output.print(" ",log); printbytes += 1; }
+
+        printbytes += printNodeForHumans(state,log);
+
+        for (int x=0;x<children.length;x++)
+            printbytes = children[x].printRootedTreeForHumans(state,log,tablevel,printbytes);
+        if (children.length>0) { state.output.print(")",log); printbytes += 1; }
+        return printbytes;
+        }
+
+
+    /** Reads the node symbol,
+        advancing the DecodeReturn to the first character in the string
+        beyond the node symbol, and returns a new, empty GPNode of the
+        appropriate class representing that symbol, else null if the
+        node symbol is not of the correct type for your GPNode class. You may
+        assume that initial whitespace has been eliminated.  Generally should
+        be case-SENSITIVE, unlike in Lisp.  The default
+        version usually works for "simple" function names, that is, not ERCs
+        or other stuff where you have to encode the symbol. */
+    public GPNode readNode(DecodeReturn dret) 
+        {
+        int len = dret.data.length();
+
+        // get my name
+        String str2 = toString();
+        int len2 = str2.length();
+
+        if (dret.pos + len2 > len)  // uh oh, not enough space
+            return null;
+
+        // check it out
+        for(int x=0; x < len2 ; x++)
+            if (dret.data.charAt(dret.pos + x) != str2.charAt(x))
+                return null;
+
+        // looks good!  Check to make sure that
+        // the symbol's all there is
+        if (dret.data.length() > dret.pos+len2)
+            {
+            char c = dret.data.charAt(dret.pos+len2);
+            if (!Character.isWhitespace(c) &&
+                c != ')' && c != '(') // uh oh
+                return null;
+            }
+
+        // we're happy!
+        dret.pos += len2;
+        return (GPNode)lightClone();
+        }
+
+
+    public void writeRootedTree(final EvolutionState state,final GPType expectedType,
+        final GPFunctionSet set, final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(children.length);
+        boolean isTerminal = (children.length == 0);
+
+        // identify the node
+        GPNode[] gpfi = isTerminal ? 
+            set.terminals[expectedType.type] : 
+            set.nonterminals[expectedType.type];
+        
+        int index=0;
+        for( /*int index=0 */; index <gpfi.length;index++)
+            if ((gpfi[index].nodeEquivalentTo(this))) break;
+        
+        if (index==gpfi.length)  // uh oh
+            state.output.fatal("No node in the function set can be found that is equivalent to the node " + this +     
+                " when performing writeRootedTree(EvolutionState, GPType, GPFunctionSet, DataOutput).");
+        dataOutput.writeInt(index);  // what kind of node it is
+        writeNode(state,dataOutput);
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);        
+        for(int x=0;x<children.length;x++)
+            children[x].writeRootedTree(state,constraints(initializer).childtypes[x],set,dataOutput);
+        }
+
+
+    public static GPNode readRootedTree(final EvolutionState state,
+        final DataInput dataInput,
+        GPType expectedType,
+        GPFunctionSet set,
+        GPNodeParent parent,
+        int argposition) throws IOException
+        {
+        int len = dataInput.readInt();      // num children
+        int index = dataInput.readInt();    // index in function set
+        
+        boolean isTerminal = (len == 0);
+        GPNode[] gpfi = isTerminal ? 
+            set.terminals[expectedType.type] : 
+            set.nonterminals[expectedType.type];
+
+        GPNode node = ((GPNode)(gpfi[index].lightClone()));
+        
+        if (node.children == null || node.children.length != len)
+            state.output.fatal("Mismatch in number of children (" + len + 
+                ") when performing readRootedTree(...DataInput...) on " + node);
+        
+        node.parent = parent;
+        node.argposition = (byte)argposition;
+        node.readNode(state,dataInput);
+
+        // do its children
+        GPInitializer initializer = ((GPInitializer)state.initializer);        
+        for(int x=0;x<node.children.length;x++)
+            node.children[x] = readRootedTree(state,dataInput,node.constraints(initializer).childtypes[x],set, node, x);
+
+        return node;
+        }
+
+    /** Override this to write any additional node-specific information to dataOutput besides: the number of arguments, 
+        the specific node class, the children, and the parent.  The default version of this method does nothing. */
+    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        // do nothing
+        }
+        
+    /** Override this to read any additional node-specific information from dataInput besides: the number of arguments,
+        the specific node class, the children, and the parent.  The default version of this method does nothing. */
+    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        // do nothing
+        }
+
+    /** Reads the node and its children from the form printed out by printRootedTree. */
+    public static GPNode readRootedTree(int linenumber,
+        DecodeReturn dret, 
+        GPType expectedType,
+        GPFunctionSet set,
+        GPNodeParent parent,
+        int argposition,
+        EvolutionState state) 
+        {
+        final char REPLACEMENT_CHAR = '@';
+
+        // eliminate whitespace if any
+        boolean isTerminal = true;
+        int len = dret.data.length();
+        for(  ;  dret.pos < len && 
+                  Character.isWhitespace(dret.data.charAt(dret.pos)) ; dret.pos++);
+        
+        // if I'm out of space, complain
+        
+        if (dret.pos >= len)
+            state.output.fatal("Reading line " + linenumber + ": " + "Premature end of tree structure -- did you forget a close-parenthesis?\nThe tree was" + dret.data);
+         
+        // if I've found a ')', complain
+        if (dret.data.charAt(dret.pos) == ')')
+            {
+            StringBuffer sb = new StringBuffer(dret.data);
+            sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
+            dret.data = sb.toString();
+            state.output.fatal("Reading line " + linenumber + ": " + "Premature ')' which I have replaced with a '" + REPLACEMENT_CHAR + "', in tree:\n" + dret.data);
+            }
+        
+        // determine if I'm a terminal or not
+        if (dret.data.charAt(dret.pos) == '(')
+            {
+            isTerminal=false;
+            dret.pos++;
+            // strip following whitespace
+            for(  ;  dret.pos < len && 
+                      Character.isWhitespace(dret.data.charAt(dret.pos)) ; dret.pos++);
+            }
+        
+        // check again if I'm out of space
+        
+        if (dret.pos >= len)
+            state.output.fatal("Reading line " + linenumber + ": " + "Premature end of tree structure -- did you forget a close-parenthesis?\nThe tree was" + dret.data);
+        
+        // check again if I found a ')'
+        if (dret.data.charAt(dret.pos) == ')')
+            {
+            StringBuffer sb = new StringBuffer(dret.data);
+            sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
+            dret.data = sb.toString();
+            state.output.fatal("Reading line " + linenumber + ": " + "Premature ')' which I have replaced with a '" + REPLACEMENT_CHAR + "', in tree:\n" + dret.data);
+            }
+        
+        
+        // find that node!
+        GPNode[] gpfi = isTerminal ? 
+            set.terminals[expectedType.type] : 
+            set.nonterminals[expectedType.type];
+        
+        GPNode node = null;
+        for(int x=0;x<gpfi.length;x++)
+            if ((node = gpfi[x].readNode(dret)) != null) break;
+        
+        // did I find one?
+        
+        if (node==null)
+            {
+            if (dret.pos!=0) 
+                {
+                StringBuffer sb = new StringBuffer(dret.data);
+                sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
+                dret.data = sb.toString();
+                }
+            else dret.data = "" + REPLACEMENT_CHAR + dret.data;
+            state.output.fatal("Reading line " + linenumber + ": " + "I came across a symbol which I could not match up with a type-valid node.\nI have replaced the position immediately before the node in question with a '" + REPLACEMENT_CHAR + "':\n" + dret.data);
+            }
+        
+        node.parent = parent;
+        node.argposition = (byte)argposition;
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        
+        // do its children
+        for(int x=0;x<node.children.length;x++)
+            node.children[x] = readRootedTree(linenumber,dret,node.constraints(initializer).childtypes[x],set,node,x,state);
+        
+        // if I'm not a terminal, look for a ')'
+        
+        if (!isTerminal)
+            {
+            // clear whitespace
+            for(  ;  dret.pos < len && 
+                      Character.isWhitespace(dret.data.charAt(dret.pos)) ; dret.pos++);
+            
+            if (dret.pos >= len)
+                state.output.fatal("Reading line " + linenumber + ": " + "Premature end of tree structure -- did you forget a close-parenthesis?\nThe tree was" + dret.data);
+            
+            if (dret.data.charAt(dret.pos) != ')')
+                {
+                if (dret.pos!=0) 
+                    {
+                    StringBuffer sb = new StringBuffer(dret.data);
+                    sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
+                    dret.data = sb.toString();
+                    }
+                else dret.data = "" + REPLACEMENT_CHAR + dret.data;
+                state.output.fatal("Reading line " + linenumber + ": " + "A nonterminal node has too many arguments.  I have put a '" + 
+                    REPLACEMENT_CHAR + "' just before the offending argument.\n" + dret.data);
+                }
+            else dret.pos++;  // get rid of the ')'
+            }
+        
+        // return the node
+        return node;
+        }
+    
+
+    /** Evaluates the node with the given thread, state, individual, problem, and stack.
+        Your random number generator will be state.random[thread].  
+        The node should, as appropriate, evaluate child nodes with these same items
+        passed to eval(...).
+
+        <p>About <b>input</b>: <tt>input</tt> is special; it is how data is passed between
+        parent and child nodes.  If children "receive" data from their parent node when
+        it evaluates them, they should receive this data stored in <tt>input</tt>.
+        If (more likely) the parent "receives" results from its children, it should
+        pass them an <tt>input</tt> object, which they'll fill out, then it should
+        check this object for the returned value.
+
+        <p>A tree is typically evaluated by dropping a GPData into the root.  When the
+        root returns, the resultant <tt>input</tt> should hold the return value.
+
+        <p>In general, you should not be creating new GPDatas.  
+        If you think about it, in most conditions (excepting ADFs and ADMs) you 
+        can use and reuse <tt>input</tt> for most communications purposes between
+        parents and children.  
+
+        <p>So, let's say that your GPNode function implements the boolean AND function,
+        and expects its children to return return boolean values (as it does itself).
+        You've implemented your GPData subclass to be, uh, <b>BooleanData</b>, which
+        looks like 
+        
+        * <tt><pre>public class BooleanData extends GPData 
+        *    {
+        *    public boolean result;
+        *    public GPData copyTo(GPData gpd)
+        *      {
+        *      ((BooleanData)gpd).result = result;
+        *      }
+        *    }</pre></tt>
+
+        <p>...so, you might implement your eval(...) function as follows:
+
+        * <tt><pre>public void eval(final EvolutionState state,
+        *                     final int thread,
+        *                     final GPData input,
+        *                     final ADFStack stack,
+        *                     final GPIndividual individual,
+        *                     final Problem problem
+        *    {
+        *    BooleanData dat = (BooleanData)input;
+        *    boolean x;
+        *
+        *    // evaluate the first child
+        *    children[0].eval(state,thread,input,stack,individual,problem);
+        *  
+        *    // store away its result
+        *    x = dat.result;
+        *
+        *    // evaluate the second child
+        *    children[1].eval(state,thread,input,stack,individual,problem);
+        *
+        *    // return (in input) the result of the two ANDed
+        *
+        *    dat.result = dat.result && x;
+        *    return;
+        *    }
+        </pre></tt>
+    */
+    
+    public abstract void eval(final EvolutionState state,
+        final int thread,
+        final GPData input,
+        final ADFStack stack,
+        final GPIndividual individual,
+        final Problem problem);
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeBuilder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeBuilder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeBuilder.java	(revision 6152)
@@ -0,0 +1,287 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GPNodeBuilder.java
+ * 
+ * Created: Thu Oct  7 17:31:41 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPNodeBuilder is a Prototype which defines the superclass for objects
+ * which create ("grow") GP trees, whether for population initialization,
+ * subtree mutation, or whatnot.  It defines a single abstract method, 
+ * newRootedTree(...), which must be implemented to grow the tree.
+ *
+ * <p>GPNodeBuilder also provides some facilities for user-specification
+ * of probabilities of various tree sizes, which the tree builder can use
+ * as it sees fit (or totally ignore).  
+ * There are two such facilities.  First, the user might
+ * specify a minimum and maximum range for tree sizes to be picked from;
+ * trees would likely be picked uniformly from this range.  Second, the
+ * user might specify an array, <tt>num-sizes</tt> long, of probabilities of 
+ * tree sizes, in order to give a precise probability distribution. 
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>min-size</tt><br>
+ <font size=-1>int &gt;= 1, or undefined</font></td>
+ <td valign=top>(smallest valid size, see discussion above)</td></tr>
+   
+ <tr><td valign=top><i>base</i>.<tt>max-size</tt><br>
+ <font size=-1>int &gt;= <tt>min-size</tt>, or undefined</font></td>
+ <td valign=top>(largest valid size, see discussion above)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>num-sizes</tt><br>
+ <font size=-1>int &gt;= 1, or underfined</font></td>
+ <td valign=top>(number of sizes in the size distribution, see discussion above)
+ </td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>size</tt>.<i>n</i><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0</font>, or undefined</td>
+ <td valign=top>(probability of choosing size <i>n</i>.  See discussion above)
+ </td></tr>
+ </table>
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class GPNodeBuilder implements Prototype
+    {
+    /** Produces a new rooted tree of GPNodes whose root's return type is
+        swap-compatible with <i>type</i>.  When you build a brand-new
+        tree out of GPNodes cloned from the
+        prototypes stored in the GPNode[] arrays, you must remember
+        to call resetNode() on each cloned GPNode.  This gives ERCs a chance
+        to randomize themselves and set themselves up. 
+
+        <p>requestedSize is an
+        optional argument which differs based on the GPNodeBuilder used.
+        Typically it is set to a tree size that the calling method wants
+        the GPNodeBuilder to produce; the GPNodeBuilder is not obligated to
+        produce a tree of this size, but it should attempt to interpret this
+        argument as appropriate for the given algorithm.  To indicate that
+        you don't care what size the tree should be, you can pass NOSIZEGIVEN. 
+        However if the algorithm <i>requires</i> you to provide a size, it
+        will generate a fatal error to let you know. */
+
+    public static final int NOSIZEGIVEN = -1;
+    public static final int CHECK_BOUNDARY = 8;
+    public static final String P_MINSIZE = "min-size";
+    public static final String P_MAXSIZE = "max-size";
+    public static final String P_NUMSIZES = "num-sizes";
+    public static final String P_SIZE = "size";
+
+    public int minSize;  /** the minium possible size  -- if unused, it's 0 */
+    public int maxSize;  /** the maximum possible size  -- if unused, it's 0 */
+    public float[] sizeDistribution;  /* sizeDistribution[x] represents
+                                         the likelihood of size x appearing 
+                                         -- if unused, it's null */
+                        
+    /** Returns true if some size distribution (either minSize and maxSize,
+        or sizeDistribution) is set up by the user in order to pick sizes randomly. */
+    public boolean canPick()
+        {
+        return (minSize!=0 || sizeDistribution !=null);
+        }
+    
+    /** Assuming that either minSize and maxSize, or sizeDistribution, is defined,
+        picks a random size from minSize...maxSize inclusive, or randomly
+        from sizeDistribution. */ 
+    public int pickSize(final EvolutionState state, final int thread)
+        {
+        if (minSize>0)
+            {
+            // pick from minSize...maxSize
+            return state.random[thread].nextInt(maxSize-minSize+1) + minSize;
+            }
+        else if (sizeDistribution!=null)
+            {
+            // pick from distribution
+            return RandomChoice.pickFromDistribution(
+                sizeDistribution,
+                state.random[thread].nextFloat()) + 1 ;
+            }
+        else throw new InternalError("Neither minSize nor sizeDistribution is defined in GPNodeBuilder");
+        }
+
+
+    public Object clone()
+        {
+        try
+            {
+            GPNodeBuilder c = (GPNodeBuilder)(super.clone());
+
+            if (sizeDistribution != null) c.sizeDistribution = 
+                                              (float[]) (sizeDistribution.clone());
+
+            return c;
+            }
+        catch (CloneNotSupportedException e)
+            { throw new InternalError(); } // never happens
+        }
+
+
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        // min and max size
+
+        if (state.parameters.exists(base.push(P_MINSIZE),
+                def.push(P_MINSIZE)))
+            {
+            if (!(state.parameters.exists(base.push(P_MAXSIZE),
+                        def.push(P_MAXSIZE))))
+                state.output.fatal("This GPNodeBuilder has a " + 
+                    P_MINSIZE + " but not a " + P_MAXSIZE + ".");
+           
+            minSize = state.parameters.getInt(
+                base.push(P_MINSIZE), def.push(P_MINSIZE),1);
+            if (minSize==0) 
+                state.output.fatal("The GPNodeBuilder must have a min size >= 1.",
+                    base.push(P_MINSIZE), def.push(P_MINSIZE));
+            
+            maxSize = state.parameters.getInt(
+                base.push(P_MAXSIZE), def.push(P_MAXSIZE),1);
+            if (maxSize==0) 
+                state.output.fatal("The GPNodeBuilder must have a max size >= 1.",
+                    base.push(P_MAXSIZE), def.push(P_MAXSIZE));
+
+            if (minSize > maxSize)
+                state.output.fatal(
+                    "The GPNodeBuilder must have min size <= max size.",
+                    base.push(P_MINSIZE), def.push(P_MINSIZE));
+            }
+        else if (state.parameters.exists(base.push(P_MAXSIZE),
+                def.push(P_MAXSIZE)))
+            state.output.fatal("This GPNodeBuilder has a " + 
+                P_MAXSIZE + " but not a " + P_MINSIZE + ".",
+                base.push(P_MAXSIZE), def.push(P_MAXSIZE));
+
+        // load sizeDistribution
+
+        else if (state.parameters.exists(base.push(P_NUMSIZES),
+                def.push(P_NUMSIZES)))
+            {
+            int siz = state.parameters.getInt(
+                base.push(P_NUMSIZES), def.push(P_NUMSIZES),1);
+            if (siz==0)
+                state.output.fatal("The number of sizes in the GPNodeBuilder's distribution must be >= 1. ");
+            sizeDistribution = new float[siz];
+            if (state.parameters.exists(base.push(P_SIZE).push("0"),
+                    def.push(P_SIZE).push("0")))
+                state.output.warning(
+                    "GPNodeBuilder does not use size #0 in the distribution",
+                    base.push(P_SIZE).push("0"),
+                    def.push(P_SIZE).push("0"));
+            
+            float sum = 0.0f;
+            for(int x=0;x<siz;x++)
+                {
+                sizeDistribution[x] = state.parameters.getFloat(
+                    base.push(P_SIZE).push(""+(x+1)), 
+                    def.push(P_SIZE).push(""+(x+1)), 0.0f);
+                if (sizeDistribution[x]<0.0)
+                    {
+                    state.output.warning(
+                        "Distribution value #" + x + " negative or not defined, assumed to be 0.0",
+                        base.push(P_SIZE).push(""+(x+1)), 
+                        def.push(P_SIZE).push(""+(x+1)));
+                    sizeDistribution[x] = 0.0f;
+                    }
+                sum += sizeDistribution[x];
+                }
+            if (sum>1.0)
+                state.output.warning(
+                    "Distribution sums to greater than 1.0",
+                    base.push(P_SIZE),
+                    def.push(P_SIZE));
+            if (sum==0.0)
+                state.output.fatal(
+                    "Distribution is all 0's",
+                    base.push(P_SIZE),
+                    def.push(P_SIZE));
+            
+            // normalize and prepare
+            RandomChoice.organizeDistribution(sizeDistribution);
+            }
+        }
+
+    public abstract GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize);
+        
+    /** Issues a warning that no terminal was found with a return type of the given type, and that an algorithm
+        had requested one.  If fail is true, then a fatal is issued rather than a warning.  The warning takes
+        the form of a one-time big explanatory message, followed by a one-time-per-type message. */
+    protected void warnAboutNoTerminalWithType(GPType type, boolean fail, EvolutionState state)
+        {
+        // big explanation -- appears only once
+        state.output.warnOnce("A GPNodeBuilder has been requested at least once to generate a one-node tree with " +
+            "a return value type-compatable with a certain type; but there is no TERMINAL which is type-compatable " +
+            "in this way.  As a result, the algorithm was forced to use a NON-TERMINAL, making the tree larger than " +
+            "requested, and exposing more child slots to fill, which if not carefully considered, could " +
+            "recursively repeat this problem and eventually fill all memory.");
+                
+        // shorter explanation -- appears for each node builder and type combo
+        if (fail)
+            state.output.fatal("" + this.getClass() + " can't find a terminal type-compatable with " + type + 
+                " and cannot replace it with a nonterminal.  You may need to try a different node-builder algorithm.");
+        else
+            state.output.warnOnce("" + this.getClass() + " can't find a terminal type-compatable with " + type);
+        }
+                
+    /** 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
+        had requested one.  If fail is true, then a fatal is issued rather than a warning.  The warning takes
+        the form of a one-time big explanatory message, followed by a one-time-per-type message. Returns the value of the test.
+        This form makes it easy to insert warnings into if-statements.  */
+    protected boolean warnAboutNonterminal(boolean test, GPType type, boolean fail, EvolutionState state)
+        {
+        if (test) warnAboutNonTerminalWithType(type, fail, state);
+        return test;
+        }
+         
+    /** Issues a warning that no nonterminal was found with a return type of the given type, and that an algorithm
+        had requested one.  If fail is true, then a fatal is issued rather than a warning.  The warning takes
+        the form of a one-time big explanatory message, followed by a one-time-per-type message. */
+    protected void warnAboutNonTerminalWithType(GPType type, boolean fail, EvolutionState state)
+        {
+        // big explanation -- appears only once
+        state.output.warnOnce("A GPNodeBuilder has been requested at least once to generate a tree with " +
+            "a return value type-compatable with a certain type; but there is no NON-TERMINAL which is type-compatable " +
+            "in this way.  As a result, the algorithm was forced to use a TERMINAL, making the tree smaller than " +
+            "requested.");
+                
+        // shorter explanation -- appears for each node builder and type combo
+        if (fail)
+            state.output.fatal("" + this.getClass() + " can't find a non-terminal type-compatable with " + type + 
+                " and cannot replace it with a terminal.  You may need to try a different node-builder algorithm.");
+        else
+            state.output.warnOnce("" + this.getClass() + " can't find a non-terminal type-compatable with " + type);
+        }
+
+    /** Issues a fatal error that no node (nonterminal or terminal) was found with a return type of the given type, and that an algorithm
+        had requested one.  */
+    protected void errorAboutNoNodeWithType(GPType type, EvolutionState state)
+        {
+        state.output.fatal("" + this.getClass() + " could find no terminal or nonterminal type-compatable with " + type);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeConstraints.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeConstraints.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeConstraints.java	(revision 6152)
@@ -0,0 +1,163 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+
+/* GPNodeConstraints.java
+ * 
+ * Created: Fri Aug 27 17:40:40 1999
+ * By: Sean Luke
+ *
+ */
+
+/**
+ * A GPNodeConstraints is a Clique which defines constraint information
+ * common to many different GPNode functions, namely return types,
+ * child types, and number of children. 
+ * GPNodeConstraints have unique names by which
+ * they are identified.
+ *
+ * <p>In adding new things to GPNodeConstraints, you should ask yourself
+ * the following questions: first, is this something that takes up too
+ * much memory to store in GPNodes themselves?  second, is this something
+ * that needs to be accessed very rapidly, so cannot be implemented
+ * as a method call in a GPNode?  third, can this be shared among
+ * different GPNodes, even ones representing different functions?
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of node constraints)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of node constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>returns</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(return type for node constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of child arguments for node constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>child.</tt><i>m</i><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of type for child argument <i>m</i> of node constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>prob</tt><br>
+ <font size=-1>float &gt;= 0.0</font></td>
+ <td valign=top>(auxillary probability of selection -- used by ec.gp.build.PTC1 and ec.gp.build.PTC2)</td></tr>
+
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPNodeConstraints implements Clique
+    {
+    public static final int SIZE_OF_BYTE = 256;
+    public final static String P_NAME = "name";
+    public final static String P_RETURNS = "returns";
+    public final static String P_CHILD = "child";
+    public final static String P_SIZE = "size";
+    public final static String P_PROBABILITY = "prob";
+    public final static float DEFAULT_PROBABILITY = 1.0f;
+
+    /** Probability of selection -- an auxillary measure mostly used by PTC1/PTC2
+        right now */
+    public float probabilityOfSelection;
+
+    /** The byte value of the constraints -- we can only have 256 of them */
+    public byte constraintNumber;
+
+    /** The return type for a GPNode */
+    public GPType returntype;
+
+    /** The children types for a GPNode */
+    public GPType[] childtypes;
+
+    /** The name of the GPNodeConstraints object -- this is NOT the
+        name of the GPNode */
+    public String name;
+
+    public String toString() { return name; }
+
+    /** A little memory optimization: if GPNodes have no children, they are welcome to
+        use share this zero-sized array as their children array. */
+    public GPNode zeroChildren[] = new GPNode[0];
+
+    /** This must be called <i>after</i> the GPTypes have been set up. */
+    public final void setup(final EvolutionState state, final Parameter base)
+        {
+        // What's my name?
+        name = state.parameters.getString(base.push(P_NAME),null);
+        if (name==null)
+            state.output.fatal("No name was given for this node constraints.",
+                base.push(P_NAME));
+
+        // Register me
+        GPNodeConstraints old_constraints = (GPNodeConstraints)(((GPInitializer)state.initializer).nodeConstraintRepository.put(name,this));
+        if (old_constraints != null)
+            state.output.fatal("The GP node constraint \"" + name + "\" has been defined multiple times.", base.push(P_NAME));
+
+        // What's my return type?
+        String s = state.parameters.getString(base.push(P_RETURNS),null);
+        if (s==null)
+            state.output.fatal("No return type given for the GPNodeConstraints " + name, base.push(P_RETURNS));
+        returntype = GPType.typeFor(s,state);
+
+        // Load probability of selection
+
+        if (state.parameters.exists(base.push(P_PROBABILITY),null))
+            {
+            float f = state.parameters.getFloat(base.push(P_PROBABILITY),null,0);
+            if (f < 0)
+                state.output.fatal("The probability of selection is < 0, which is not valid.",base.push(P_PROBABILITY),null);
+            probabilityOfSelection = f;
+            }
+        else probabilityOfSelection = DEFAULT_PROBABILITY;
+
+        // How many child types do I have?
+        
+        int x = state.parameters.getInt(base.push(P_SIZE),null,0);
+        if (x < 0)
+            state.output.fatal("The number of children types for the GPNodeConstraints " + name + " must be >= 0.", base.push(P_SIZE));
+
+        childtypes = new GPType[x];
+
+        Parameter p = base.push(P_CHILD);
+
+        // Load my children
+        for (x=0;x<childtypes.length;x++)
+            {
+            s = state.parameters.getString(p.push(""+x),null);
+            if (s==null)
+                state.output.fatal("Type #" + x + " is not defined for the GPNodeConstraints " + name +  ".", base.push(""+x));
+            childtypes[x] = GPType.typeFor(s,state);
+            }
+        // ...because I promised when I called typeFor(...)
+        state.output.exitIfErrors();    
+        }
+
+
+    /** You must guarantee that after calling constraintsFor(...) one or
+        several times, you call state.output.exitIfErrors() once. */
+
+    public static GPNodeConstraints constraintsFor(final String constraintsName,
+        final EvolutionState state)
+        {
+        GPNodeConstraints myConstraints = (GPNodeConstraints)(((GPInitializer)state.initializer).nodeConstraintRepository.get(constraintsName));
+        if (myConstraints==null)
+            state.output.error("The GP node constraint \"" + constraintsName + "\" could not be found.");
+        return myConstraints;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeGatherer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeGatherer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeGatherer.java	(revision 6152)
@@ -0,0 +1,35 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import java.io.Serializable;
+
+/* 
+ * GPNodeGatherer.java
+ * 
+ * Created: Fri Nov  5 17:01:13 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPNodeGatherer is a small container object for the GPNode.nodeInPosition(...)
+ * method and GPNode.numNodes(...) method. 
+ * It may be safely reused without being reinitialized.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPNodeGatherer implements Serializable
+    {
+    public GPNode node;
+
+    /** Returns true if thisNode is the kind of node to be considered in the
+        gather count for nodeInPosition(...) and GPNode.numNodes(GPNodeGatherer).
+        The default form simply returns true.  */
+    public boolean test(final GPNode thisNode) { return true; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeParent.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeParent.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeParent.java	(revision 6152)
@@ -0,0 +1,28 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.Prototype;
+
+/* 
+ * GPNodeParent.java
+ * 
+ * Created: Fri Aug 27 17:10:39 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPNodeParent is a Prototype which identifies objects which may
+ * be parents of GPNodes, namely: GPTrees and GPNodes.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface GPNodeParent
+    {
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeSelector.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeSelector.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNodeSelector.java	(revision 6152)
@@ -0,0 +1,52 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+
+/* 
+ * GPNodeSelector.java
+ * 
+ * Created: Tue Oct 12 17:08:10 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPNodeSelector is a Prototype which describes algorithms which
+ * select random nodes out of trees, typically marking them for
+ * mutation, crossover, or whatnot.  GPNodeSelectors can cache information
+ * about a tree, as they may receive the pickNode(...) method more than
+ * once on a tree.  But this should really only be done if it can be
+ * done relatively efficiently; it's not all that common.  A GPNodeSelector
+ * will be called reset() just before it is pressed into service in
+ * selecting nodes from a new tree, which gives it the chance to
+ * reset caches, etc.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface GPNodeSelector extends Prototype 
+    {
+    /** Picks a node at random from tree and returns it.   The tree
+        is located in ind, which is located in s.population[subpopulation].
+        This method will be preceded with a call to reset();
+        afterwards, pickNode(...) may be called several times for the
+        same tree.
+    */
+
+    public abstract GPNode pickNode(final EvolutionState s,
+        final int subpopulation,
+        final int thread,
+        final GPIndividual ind,
+        final GPTree tree);
+
+    /** Resets the Node Selector before a new series of pickNode()
+        if need be. */
+    public abstract void reset();
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPProblem.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPProblem.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPProblem.java	(revision 6152)
@@ -0,0 +1,96 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.util.*;
+import ec.*;
+import ec.simple.*;
+
+/* 
+ * GPProblem.java
+ * 
+ * Created: Wed Oct 27 18:07:06 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A GPProblem is a Problem which is meant to efficiently handle GP
+ * evaluation.  GPProblems hold one ADFStack, which is used to 
+ * evaluate a large number of trees without having to be garbage-collected
+ * and reallocated.  Be sure to call stack.reset() after each
+ * tree evaluation.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i><tt>.stack</tt><br>
+ <font size=-1>classname, inherits or = ec.ADFStack</font></td>
+ <td valign=top>(the class for the GPProblem's ADF Stack)</td></tr>
+ <tr><td valign=top><i>base</i><tt>.data</tt><br>
+ <font size=-1>classname, inherits and != ec.GPData</font></td>
+ <td valign=top>(the class for the GPProblem's basic GPData type)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.problem
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i><tt>.stack</tt><br>
+ <td valign=top>(stack)</td></tr> 
+ <tr><td valign=top><i>base</i><tt>.data</tt><br>
+ <td valign=top>(data)</td></tr> 
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class GPProblem extends Problem implements SimpleProblemForm
+    {
+    public final static String P_GPPROBLEM = "problem";
+    public final static String P_STACK = "stack";
+    public final static String P_DATA = "data";
+
+    /** The GPProblem's stack */
+    public ADFStack stack;
+
+    /** The GPProblems' GPData */
+    public GPData data;
+
+    /** GPProblem defines a default base so your subclass doesn't
+        absolutely have to. */
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_GPPROBLEM);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter p = base.push(P_STACK);
+        Parameter def = defaultBase();
+
+        stack = (ADFStack)
+            (state.parameters.getInstanceForParameterEq(
+                p,def.push(P_STACK),ADFStack.class));
+        stack.setup(state,p);
+
+        p = base.push(P_DATA);
+        data = (GPData)
+            (state.parameters.getInstanceForParameter(
+                p,def.push(P_DATA),GPData.class));
+        data.setup(state,p);
+        }
+
+    public Object clone()
+        {
+        GPProblem prob = (GPProblem)(super.clone());
+        
+        // deep-clone the stack; it's not shared
+        prob.stack = (ADFStack)(stack.clone());
+        return prob;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPSetType.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPSetType.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPSetType.java	(revision 6152)
@@ -0,0 +1,138 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/* 
+ * GPSetType.java
+ * 
+ * Created: Fri Aug 27 20:55:42 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A GPSetType is a GPType which contains GPAtomicTypes in a set, and is used
+ * as a generic GP type.  For more information, see GPType
+ *
+ * GPSetTypes implement their set using both a hash table and an array.
+ * if the size of the set is "significantly big", then the hash table
+ * is used to look up membership in the set (O(1), but with a big constant).
+ * If the size is small, then the array is used (O(n)).  The dividing line
+ * is determined by the constant START_USING_HASH_BEYOND, which you might
+ * play with to optimize for your system.
+ *
+ * @see ec.gp.GPType
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class GPSetType extends GPType
+    {
+    public static final String P_MEMBER = "member";
+    public static final String P_SIZE = "size";
+
+    /** A packed, sorted array of atomic types in the set */
+    public int[] types_packed;
+
+    /** A sparse array of atomic types in the set */
+    public boolean[] types_sparse;
+
+    /** The hashtable of types in the set */
+    public Hashtable types_h;
+
+    /** You should not construct new types. */
+    public GPSetType() { }
+
+
+    /** Sets up the packed and sparse arrays based on the hashtable */
+    public void postProcessSetType(int totalAtomicTypes)
+        {
+        // load the hashtable into the arrays
+        int x=0;
+        types_packed = new int[types_h.size()];
+        types_sparse = new boolean[totalAtomicTypes];
+        Enumeration e = types_h.elements();
+        while(e.hasMoreElements())
+            {
+            GPAtomicType t = (GPAtomicType)(e.nextElement());
+            types_packed[x++] = t.type;
+            types_sparse[t.type] = true;
+            }
+
+        // Sort the packed array
+        java.util.Arrays.sort(types_packed);
+        }
+
+
+    public void setup(final EvolutionState state, Parameter base)
+        {
+        super.setup(state,base);
+        
+        // Make my Hashtable
+        types_h = new Hashtable();
+
+        // How many atomic types do I have?
+        int len = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (len<=0) 
+            state.output.fatal("The number of atomic types in the GPSetType " +
+                name + " must be >= 1.",base.push(P_SIZE));
+
+        // Load the GPAtomicTypes
+        for(int x=0;x<len;x++)
+            {
+            String s = state.parameters.getString(base.push(P_MEMBER).push(""+x),null);
+            if (s==null)
+                state.output.fatal("Atomic type member #" + x + 
+                    " is not defined for the GPSetType " + name +
+                    ".",base.push(P_MEMBER).push(""+x));
+            GPType t = GPType.typeFor(s,state);
+            if (!(t instanceof GPAtomicType)) // uh oh
+                state.output.fatal("Atomic type member #" + x +
+                    " of GPSetType " + name +
+                    " is not a GPAtomicType.",
+                    base.push(P_MEMBER).push(""+x));
+
+            if (types_h.get(t)!=null)
+                state.output.warning("Atomic type member #" + x +
+                    " is included more than once in GPSetType " + 
+                    name + ".",
+                    base.push(P_MEMBER).push(""+x));
+            types_h.put(t,t);
+            }
+        }
+
+    
+    public final boolean compatibleWith(final GPInitializer initializer,final GPType t)
+        {
+        // if the type is me, then I'm compatible with it.
+        if (t.type == type) return true;
+
+        // if the type is an atomic type, then I'm compatible with it if I contain it.
+        // Use the sparse array.
+        else if (t.type < initializer.numAtomicTypes) // atomic type, faster than doing instanceof
+            return types_sparse[t.type];
+
+        // else the type is a set type.  I'm compatible with it if we contain
+        // an atomic type in common.   Use the sorted packed array.
+        else
+            {
+            GPSetType s = (GPSetType)t;
+            int x=0; int y=0;
+            for( ; x < types_packed.length && y < s.types_packed.length ; )
+                {
+                if (types_packed[x] == s.types_packed[y]) return true;
+                else if (types_packed[x] < s.types_packed[y]) x++;
+                else y++;
+                }
+            return false;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPSpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPSpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPSpecies.java	(revision 6152)
@@ -0,0 +1,117 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * GPSpecies.java
+ * 
+ * Created: Tue Aug 31 17:00:10 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPSpecies is a simple individual which is suitable as a species
+ * for GP subpopulations.  GPSpecies' individuals must be GPIndividuals,
+ * and often their pipelines are GPBreedingPipelines (at any rate,
+ * the pipelines will have to return members of GPSpecies!).
+ *
+ <p><b>Default Base</b><br>
+ gp.species
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPSpecies extends Species
+    {
+    public static final String P_GPSPECIES = "species";
+
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_GPSPECIES);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        // check to make sure that our individual prototype is a GPIndividual
+        if (!(i_prototype instanceof GPIndividual))
+            state.output.fatal("The Individual class for the Species " + getClass().getName() + " is must be a subclass of ec.gp.GPIndividual.", base );
+        }    
+
+    public Individual newIndividual(EvolutionState state, int thread) 
+        {
+        GPIndividual newind = ((GPIndividual)(i_prototype)).lightClone();
+        
+        // Initialize the trees
+        for (int x=0;x<newind.trees.length;x++)
+            newind.trees[x].buildTree(state, thread);
+
+        // Set the fitness
+        newind.fitness = (Fitness)(f_prototype.clone());
+        newind.evaluated = false;
+
+        // Set the species to me
+        newind.species = this;
+                
+        // ...and we're ready!
+        return newind;
+        }
+
+
+    // A custom version of newIndividual() which guarantees that the
+    // prototype is light-cloned before readIndividual is issued
+    public Individual newIndividual(final EvolutionState state,
+        final LineNumberReader reader)
+        throws IOException
+        {
+        GPIndividual newind = ((GPIndividual)i_prototype).lightClone();
+                
+        // Set the fitness -- must be done BEFORE loading!
+        newind.fitness = (Fitness)(f_prototype.clone());
+        newind.evaluated = false; // for sanity's sake, though it's a useless line
+
+        // load that sucker
+        newind.readIndividual(state,reader);
+
+        // Set the species to me
+        newind.species = this;
+
+        // and we're ready!
+        return newind;  
+        }
+
+
+    // A custom version of newIndividual() which guarantees that the
+    // prototype is light-cloned before readIndividual is issued
+    public Individual newIndividual(final EvolutionState state,
+        final DataInput dataInput)
+        throws IOException
+        {
+        GPIndividual newind = ((GPIndividual)i_prototype).lightClone();
+        
+        // Set the fitness -- must be done BEFORE loading!
+        newind.fitness = (Fitness)(f_prototype.clone());
+        newind.evaluated = false; // for sanity's sake, though it's a useless line
+
+        // Set the species to me
+        newind.species = this;
+
+        // load that sucker
+        newind.readIndividual(state,dataInput);
+
+        // and we're ready!
+        return newind;  
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTree.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTree.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTree.java	(revision 6152)
@@ -0,0 +1,437 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * GPTree.java
+ * 
+ * Created: Fri Aug 27 17:14:02 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPTree is a GPNodeParent which holds the root GPNode of a tree
+ * of GPNodes.  GPTrees typically fill out an array held in a GPIndividual
+ * (their "owner") and their roots are evaluated to evaluate a Genetic
+ * programming tree.
+ *
+ * GPTrees also have <i>constraints</i>, which are shared, and define items
+ * shared among several GPTrees.
+
+ * <p>In addition to serialization for checkpointing, GPTrees may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeTree(...,DataOutput)/readTree(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives a GPTree in binary.  It is the most efficient approach to sending
+ * GPTrees over networks, etc.  The default versions of writeTree/readTree call writeRootedTree/readRootedTree
+ * on their respective GPNode roots.
+ *
+ * <li><b>printTree(...,PrintWriter)/readTree(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives a GPTree in text encoded such that the GPTree is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readTree</b>
+ * largely calls readRootedTree on the GPNode root.  Likewise, <b>printTree</b> calls printRootedTree
+ *
+ * <li><b>printTreeForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints a GPTree in a fashion intended for human consumption only.
+ * <b>printTreeForHumans</b> calls either <b>makeCTree</b> and prints the result,
+ * calls <b>makeLatexTree</b> and prints the result, or calls <b>printRootedTreeForHumans</b> on the root.
+ * Which one is called depends on the kind of tree you have chosen to print for humans, as is discussed next.
+ * </ul>
+
+
+
+ * <p>GPTrees can print themselves for humans in one of <b>four</b> styles:
+ * <ol><li>A GPTree can print the tree as a Koza-style Lisp s-expression, which is the default.  
+ * <li> A GPTree can print itself in pseudo-C format:
+ *     <ol><li>Terminals can be printed either as variables "a" or as zero-argument functions "a()"
+ *     <li>One-argument nonterminals are printed as functions "a(b)"
+ *     <li>Two-argument nonterminals can be printed either as operators "b a c" or as functions "a(b, c)"
+ *     <li>Nonterminals with more arguments are printed as functions "a(b, c, d, ...)"
+ * </ol>
+ * <li>A GPTree can print the tree AT&amp;T's Graphviz format.  You can snip the code out and save 
+ * it as a ".dot" file to render in any Graphviz renderer (for example, use <a href="http://www.pixelglow.com/graphviz/">
+ * this MacOS X front end to the renderer</a>).
+ * <li>A GPTree can print the tree as a LaTeX2e code snippet, which can be inserted
+ * into a LaTeX2e file and will result in a picture of the tree!  Cool, no?
+ * </ol>
+ *
+ * <p>You turn the C-printing feature on with the <b>c</b> parameter, plus certain
+ * optional parameters (<b>c-operators</b>, <b>c-variables</b>) as described below.
+ * You turn the latex-printing <b>latex</b> parameter below.  The C-printing parameter
+ * takes precedence.
+ * <p>
+ * Here's how the latex system works.  To insert the code, you'll need to include the
+ * <tt>epic</tt>,<tt>ecltree</tt>, and probably the <tt>fancybox</tt> packages,
+ * in that order.  You'll also need to define the command <tt>\gpbox</tt>, which
+ * takes one argument (the string name for the GPNode) and draws a box with that
+ * node.  Lastly, you might want to set a few parameters dealing with the 
+ * <tt>ecltree</tt> package.
+ *
+ * <p>Here's an example which looks quite good (pardon the double-backslashes
+ * in front of the usepackage statements -- javadoc is freaking out if I put
+ * a single backslash.  So you'll need to remove the extra backslash in order
+ * to try out this example):
+ 
+ <p><table width=100% border=0 cellpadding=0 cellspacing=0>
+ <tr><td bgcolor="#DDDDDD"><font size=-1><tt>
+ <pre>
+
+ \documentclass[]{article}
+ \\usepackage{epic}     <b>% required by ecltree and fancybox packages</b>
+ \\usepackage{ecltree}  <b>% to draw the GP trees</b>
+ \\usepackage{fancybox} <b>% required by \Ovalbox</b>
+
+ \begin{document}
+
+ <b>% minimum distance between nodes on the same line</b>
+ \setlength{\GapWidth}{1em}    
+
+ <b>% draw with a thick dashed line, very nice looking</b>
+ \thicklines \drawwith{\dottedline{2}}   
+
+ <b>% draw an oval and center it with the rule.  You may want to fool with the
+ % rule values, though these seem to work quite well for me.  If you make the
+ % rule smaller than the text height, then the GP nodes may not line up with
+ % each other horizontally quite right, so watch out.</b>
+ \newcommand{\gpbox}[1]{\Ovalbox{#1\rule[-.7ex]{0ex}{2.7ex}}}
+                
+ <b>% Here's the tree which the GP system spat out</b>
+ \begin{bundle}{\gpbox{progn3}}\chunk{\begin{bundle}{\gpbox{if-food-ahead}}
+ \chunk{\begin{bundle}{\gpbox{progn3}}\chunk{\gpbox{right}}
+ \chunk{\gpbox{left}}\chunk{\gpbox{move}}\end{bundle}}
+ \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\gpbox{move}}
+ \chunk{\gpbox{left}}\end{bundle}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{progn2}}
+ \chunk{\begin{bundle}{\gpbox{progn2}}\chunk{\gpbox{move}}
+ \chunk{\gpbox{move}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{progn2}}
+ \chunk{\gpbox{right}}\chunk{\gpbox{left}}\end{bundle}}\end{bundle}}
+ \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\begin{bundle}{\gpbox{if-food-ahead}}
+ \chunk{\gpbox{move}}\chunk{\gpbox{left}}\end{bundle}}
+ \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\gpbox{left}}\chunk{\gpbox{right}}
+ \end{bundle}}\end{bundle}}\end{bundle}
+
+ \end{document}
+ </pre></tt></font></td></tr></table>
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tc</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(The tree's constraints)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>print-style</tt><br>
+ <font size=-1>String, one of: c, dot, latex, lisp</td>
+ <td valign=top>(specifies the print style of the tree)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>c-operators</tt><br>
+ <font size=-1>bool = <tt>true</tt> (default) or <tt>false</tt></td>
+ <td valign=top>(when printing using c, print two-argument functions operators "b a c"?  The alternative is functions "a(b, c)."</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>c-variables</tt><br>
+ <font size=-1>bool = <tt>true</tt> (default) or <tt>false</tt></td>
+ <td valign=top>(when printing using c, print zero-argument functions as variables "a"?  The alternative is functions "a()".)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.tree
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPTree implements GPNodeParent, Prototype
+    {
+    public static final String P_TREE = "tree";
+    public static final String P_TREECONSTRAINTS = "tc";
+    public static final String P_USEGRAPHVIZ = "graphviz";
+    public static final String P_USELATEX = "latex";
+    public static final String P_USEC = "c";
+    public static final String P_USEOPS = "c-operators";
+    public static final String P_USEVARS = "c-variables";
+    public static final int NO_TREENUM = -1;
+
+    public static final String P_PRINT_STYLE = "print-style";
+    public static final String V_LISP = "lisp";
+    public static final String V_DOT = "dot";
+    public static final String V_LATEX = "latex";
+    public static final String V_C = "c";
+    public static final int PRINT_STYLE_LISP = 0;
+    public static final int PRINT_STYLE_DOT = 1;
+    public static final int PRINT_STYLE_LATEX = 2;
+    public static final int PRINT_STYLE_C = 3;
+
+
+    /** the root GPNode in the GPTree */
+    public GPNode child;
+
+    /** the owner of the GPTree */
+    public GPIndividual owner;
+
+    /** constraints on the GPTree  -- don't access the constraints through
+        this variable -- use the constraints() method instead, which will give
+        the actual constraints object. */
+    public byte constraints;
+
+    /** The print style of the GPTree. */
+    public int printStyle;
+
+    /** When using c to print for humans, do we print terminals as variables? 
+        (as opposed to zero-argument functions)? */
+    public boolean printTerminalsAsVariablesInC;
+
+    /** When using c to print for humans, do we print two-argument nonterminals in operator form "a op b"? 
+        (as opposed to functions "op(a, b)")? */
+    public boolean printTwoArgumentNonterminalsAsOperatorsInC;
+
+    public final GPTreeConstraints constraints( final GPInitializer initializer ) 
+        { return initializer.treeConstraints[constraints]; }
+
+    public Parameter defaultBase()
+        {
+        return GPDefaults.base().push(P_TREE);
+        }
+
+    /** Returns true if I am "genetically" the same as tree,
+        though we may have different owners. */
+    public boolean treeEquals(GPTree tree)
+        {
+        return child.rootedTreeEquals(tree.child);
+        }
+
+    /** Returns a hash code for comparing different GPTrees.  In
+        general, two trees which are treeEquals(...) should have the
+        same hash code. */
+    public int treeHashCode()
+        {
+        return child.rootedTreeHashCode();
+        }
+
+    /** Like clone() but doesn't copy the tree. */
+    public GPTree lightClone()
+        {
+        try 
+            { 
+            return (GPTree)(super.clone());  // note that the root child reference is copied, not cloned
+            }
+        catch (CloneNotSupportedException e) { throw new InternalError(); } // never happens
+        }
+
+    /** Deep-clones the tree.  Note that you should not deep-clone trees attached to the
+        prototypical GPIndividual: they are blank trees with no root, and this method
+        will generate a NullPointerException as a result. */
+    public Object clone()
+        {
+        GPTree newtree = lightClone();
+        newtree.child = (GPNode)(child.clone());  // force a deep copy
+        newtree.child.parent = newtree;
+        newtree.child.argposition = 0;
+        return newtree;
+        }
+    
+    /** An expensive function which determines my tree number -- only
+        use for errors, etc. Returns ec.gp.GPTree.NO_TREENUM if the 
+        tree number could not be
+        determined (might happen if it's not been assigned yet). */
+    public int treeNumber()
+        {
+        if (owner==null) return NO_TREENUM;
+        if (owner.trees==null) return NO_TREENUM;
+        for(int x=0;x<owner.trees.length;x++)
+            if (owner.trees[x]==this) return x;
+        return NO_TREENUM;
+        }
+
+    /** Sets up a prototypical GPTree with those features it shares with
+        other GPTrees in its position in its GPIndividual, and nothhing more.
+
+        This must be called <i>after</i> the GPTypes and GPNodeConstraints 
+        have been set up.  Presently they're set up in GPInitializer,
+        which gets called before this does, so we're safe. */
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        // get rid of deprecated values
+        if (state.parameters.exists(base.push(P_USEGRAPHVIZ), def.push(P_USEGRAPHVIZ)))
+            state.output.error("Parameter no longer used.  See GPTree.java for details.", base.push(P_USEGRAPHVIZ), def.push(P_USEGRAPHVIZ));
+        if (state.parameters.exists(base.push(P_USELATEX), def.push(P_USELATEX)))
+            state.output.error("Parameter no longer used.  See GPTree.java for details.", base.push(P_USELATEX), def.push(P_USELATEX));
+        if (state.parameters.exists(base.push(P_USEC), def.push(P_USEC)))
+            state.output.error("Parameter no longer used.  See GPTree.java for details.", base.push(P_USEC), def.push(P_USEC));
+        state.output.exitIfErrors();
+
+        String style = state.parameters.getString(base.push(P_PRINT_STYLE), def.push(P_PRINT_STYLE));
+        if (style == null)  // assume Lisp
+            printStyle = PRINT_STYLE_LISP;
+        else if (style.equals(V_C))
+            printStyle = PRINT_STYLE_C;
+        else if (style.equals(V_DOT))
+            printStyle = PRINT_STYLE_DOT;
+        else if (style.equals(V_LATEX))
+            printStyle = PRINT_STYLE_LATEX;
+
+        // in C, treat terminals as variables?  By default, yes.
+        printTerminalsAsVariablesInC = state.parameters.getBoolean(base.push(P_USEVARS),def.push(P_USEVARS),true);
+
+        // in C, treat two-child functions as operators?  By default, yes.
+        printTwoArgumentNonterminalsAsOperatorsInC = state.parameters.getBoolean(base.push(P_USEOPS),def.push(P_USEOPS),true);
+
+        // determine my constraints -- at this point, the constraints should have been loaded.
+        String s = state.parameters.getString(base.push(P_TREECONSTRAINTS),
+            def.push(P_TREECONSTRAINTS));
+        if (s==null)
+            state.output.fatal("No tree constraints are defined for the GPTree " + base + ".");
+        else 
+            constraints = GPTreeConstraints.constraintsFor(s,state).constraintNumber;
+        
+        state.output.exitIfErrors();  // because I promised
+        // we're not loading the nodes at this point
+        }
+
+
+    /** Verification of validity of the tree -- strictly for debugging purposes only */
+    public final void verify(EvolutionState state)
+        {
+        if (!(state.initializer instanceof GPInitializer))
+            { state.output.error("Initializer is not a GPInitializer"); return; }
+            
+        GPInitializer initializer = (GPInitializer)(state.initializer);
+
+        if (child == null)
+            { state.output.error("Null root child of GPTree."); return; }
+        if (owner == null)
+            { state.output.error("Null owner of GPTree."); return; }
+        if (owner.trees == null)
+            { state.output.error("Owner has null trees."); return; }
+        if (treeNumber() == NO_TREENUM) 
+            { state.output.error("No Tree Number! I appear to be an orphan GPTree."); return; }
+        if (constraints < 0 || constraints >= initializer.numTreeConstraints)
+            { state.output.error("Preposterous tree constraints (" + constraints + ")"); return; }
+
+        child.verify(state, constraints(initializer).functionset, 0);
+        state.output.exitIfErrors();
+        }
+
+    /** Prints out the tree in single-line fashion suitable for reading
+        in later by computer. O(n). 
+        The default version of this method simply calls child's 
+        printRootedTree(...) method. 
+    */
+
+    public void printTree(final EvolutionState state, final int log)
+        {
+        printTree(state, log, Output.V_VERBOSE);
+        }
+
+    /** Prints out the tree in single-line fashion suitable for reading
+        in later by computer. O(n). 
+        The default version of this method simply calls child's 
+        printRootedTree(...) method. 
+        @deprecated Verbosity no longer has an effect
+    */
+
+    public void printTree(final EvolutionState state, final int log,
+        final int verbosity)
+        {
+        child.printRootedTree(state,log,0);
+        // printRootedTree doesn't print a '\n', so I need to do so here
+        state.output.println("",log);
+        }
+
+    /** Prints out the tree in single-line fashion suitable for reading
+        in later by computer. O(n). 
+        The default version of this method simply calls child's 
+        printRootedTree(...) method. */
+
+    public void printTree(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        child.printRootedTree(state,writer,0);
+        // printRootedTree doesn't print a '\n', so I need to do so here
+        writer.println();
+        }
+
+    /** Reads in the tree from a form printed by printTree. */
+    public void readTree(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        int linenumber = reader.getLineNumber();
+
+        // the next line will be the child
+        String s = reader.readLine();
+        if (s==null)  // uh oh
+            state.output.fatal("Reading Line " + linenumber + ": " +
+                "No Tree found.");
+        else
+            {
+            GPInitializer initializer = ((GPInitializer)state.initializer);
+            child = GPNode.readRootedTree(linenumber,new DecodeReturn(s),
+                constraints(initializer).treetype,
+                constraints(initializer).functionset,this,0,state);
+            }
+        }
+
+    public void writeTree(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        child.writeRootedTree(state,constraints(initializer).treetype, constraints(initializer).functionset, dataOutput);
+        }
+
+    public void readTree(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        child = GPNode.readRootedTree(state,dataInput,constraints(initializer).treetype, constraints(initializer).functionset, this,0);
+        }
+
+
+    /** Prints out the tree in a readable Lisp-like fashion. O(n). 
+        The default version of this method simply calls child's 
+        printRootedTreeForHumans(...) method. */
+    
+    public void printTreeForHumans(final EvolutionState state, final int log)
+        {               
+        printTreeForHumans(state, log, Output.V_VERBOSE);
+        }
+
+
+    /** Prints out the tree in a readable Lisp-like fashion. O(n). 
+        The default version of this method simply calls child's 
+        printRootedTreeForHumans(...) method. 
+        @deprecated Verbosity no longer has an effect.
+    */
+    
+    public void printTreeForHumans(final EvolutionState state, final int log,
+        final int verbosity)
+        {               
+        if (printStyle==PRINT_STYLE_C) state.output.print(child.makeCTree(true, 
+                printTerminalsAsVariablesInC, printTwoArgumentNonterminalsAsOperatorsInC),log);
+        else if (printStyle==PRINT_STYLE_LATEX) state.output.print(child.makeLatexTree(),log);
+        else if (printStyle==PRINT_STYLE_DOT) state.output.print(child.makeGraphvizTree(), log);
+        else child.printRootedTreeForHumans(state,log,0,0);
+        // printRootedTreeForHumans doesn't print a '\n', so I need to do so here
+        state.output.println("",log);
+        }
+
+    /** Builds a new randomly-generated rooted tree and attaches it to the GPTree. */
+
+    public void buildTree(final EvolutionState state, final int thread) 
+        {
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        child = constraints(initializer).init.newRootedTree(state,
+            constraints(initializer).treetype,
+            thread,
+            this,
+            constraints(initializer).functionset,
+            0,
+            GPNodeBuilder.NOSIZEGIVEN);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTreeConstraints.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTreeConstraints.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTreeConstraints.java	(revision 6152)
@@ -0,0 +1,191 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+import java.util.*;
+import java.util.Enumeration;
+
+/* 
+ * GPTreeConstraints.java
+ * 
+ * Created: Thu Oct  7 15:38:45 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A GPTreeConstraints is a Clique which defines constraint information
+ * common to many different GPTree trees, namely the tree type,
+ * builder, and function set.  GPTreeConstraints have unique names
+ * by which they are identified.
+ *
+ * <p>In adding new things to GPTreeConstraints, you should ask yourself
+ * the following questions: first, is this something that takes up too
+ * much memory to store in GPTrees themseves?  second, is this something
+ * that needs to be accessed very rapidly, so cannot be implemented as
+ * a method call in a GPTree?  third, can this be shared among different
+ * GPTrees?
+ *
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of tree constraints)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of tree constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>init</tt><br>
+ <font size=-1>classname, inherits and != ec.gp.GPNodeBuilder</font></td>
+ <td valign=top>(GP node builder for tree constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>returns</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(tree type for tree constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>fset</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(function set for tree constraint <i>n</i>)</td></tr>
+
+ </table>
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPTreeConstraints implements Clique
+    {
+    public static final int SIZE_OF_BYTE = 256;
+    public final static String P_NAME = "name";
+    public final static String P_SIZE = "size";
+    public final static String P_INIT = "init";
+    public static final String P_RETURNS = "returns";
+    public static final String P_FUNCTIONSET = "fset";
+
+    public String name;
+    
+    /** The byte value of the constraints -- we can only have 256 of them */
+    public byte constraintNumber;
+
+    /** The builder for the tree */
+    public GPNodeBuilder init;
+
+    /** The type of the root of the tree */
+    public GPType treetype;
+
+    /** The function set for nodes in the tree */
+    public GPFunctionSet functionset;
+    
+    public String toString() { return name; }
+
+    /** This must be called <i>after</i> the GPTypes and GPFunctionSets 
+        have been set up. */
+    public final void setup(final EvolutionState state, final Parameter base)
+        {
+        // What's my name?
+        name = state.parameters.getString(base.push(P_NAME),null);
+        if (name==null)
+            state.output.fatal("No name was given for this function set.",
+                base.push(P_NAME));
+
+        // Register me
+        GPTreeConstraints old_constraints = 
+            (GPTreeConstraints)(((GPInitializer)state.initializer).treeConstraintRepository.put(name,this));
+        if (old_constraints != null)
+            state.output.fatal("The GP tree constraint \"" + name + "\" has been defined multiple times.", base.push(P_NAME));
+
+        // Load my initializing builder
+        init = (GPNodeBuilder)(state.parameters.getInstanceForParameter(base.push(P_INIT),null,GPNodeBuilder.class));
+        init.setup(state,base.push(P_INIT));
+
+        // Load my return type
+        String s = state.parameters.getString(base.push(P_RETURNS),null);
+        if (s==null)
+            state.output.fatal("No return type given for the GPTreeConstraints " + name, base.push(P_RETURNS));
+        treetype = GPType.typeFor(s,state);
+
+        // Load my function set
+
+        s = state.parameters.getString(base.push(P_FUNCTIONSET),null);
+        if (s==null)
+            state.output.fatal("No function set given for the GPTreeConstraints " + name, base.push(P_RETURNS));
+        functionset = GPFunctionSet.functionSetFor(s,state);
+        state.output.exitIfErrors();  // otherwise checkFunctionSetValidity might crash below
+
+        // Determine the validity of the function set
+        // the way we do that is by gathering all the types that
+        // are transitively used, starting with treetype, as in:
+        Hashtable typ = new Hashtable();
+        checkFunctionSetValidity(state, typ, treetype);
+        // next we make sure that for every one of these types,
+        // there's a terminal with that return type, and *maybe*
+        // a nonterminal
+        Enumeration e = typ.elements();
+        while (e.hasMoreElements())
+            {
+            GPType t = (GPType)(e.nextElement());
+            GPNode[] i = functionset.nodes[t.type];
+            if (i.length==0) // yeesh
+                state.output.error("In function set " + functionset + " for the GPTreeConstraints " + this + ", no nodes at all are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type.  This almost certainly indicates a serious typing error.", base);
+            else
+                {
+                i = functionset.terminals[t.type];
+                if (i.length==0) // uh oh
+                    state.output.warning("In function set " + functionset + " for the GPTreeConstraints " + this + ", no terminals are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type.  Nearly all tree-builders in ECJ require the ability to add a terminal of any type for which there is a nonterminal, and at any time.  Without terminals, your code may not work.  One common indication that a tree-builder has failed due to this problem is if you get the MersenneTwister error 'n must be positive'.", base);
+                i = functionset.nonterminals[t.type];
+                if (i.length==0) // uh oh
+                    state.output.warning("In function set " + functionset + " for the GPTreeConstraints " + this + ", no *nonterminals* are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type.  This may or may not be a problem for you.", base);
+                }
+            }
+        state.output.exitIfErrors();
+        }
+
+    // When completed, done will hold all the types which are needed
+    // in the function set -- you can then check to make sure that
+    // they contain at least one terminal and (hopefully) at least
+    // one nonterminal.
+
+    private void checkFunctionSetValidity(final EvolutionState state,
+        final Hashtable done, 
+        final GPType type)
+        {
+        // put type in the hashtable -- it's being used
+        done.put(type,type);
+        
+        // Grab the array in nodes
+        GPNode[] i = functionset.nodes[type.type];
+
+        // For each argument type in a node in i, if it's not in done,
+        // then add it to done and call me on it
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        for (int x=0; x<i.length;x++)
+            for (int y=0;y<i[x].constraints(initializer).childtypes.length;y++)
+                if (done.get(i[x].constraints(initializer).childtypes[y])==null)
+                    {
+                    checkFunctionSetValidity(
+                        state, done, i[x].constraints(initializer).childtypes[y]);
+                    }
+        }
+
+
+
+    /** You must guarantee that after calling constraintsFor(...) one or
+        several times, you call state.output.exitIfErrors() once. */
+
+    public static GPTreeConstraints constraintsFor(final String constraintsName,
+        final EvolutionState state)
+        {
+        GPTreeConstraints myConstraints = (GPTreeConstraints)(((GPInitializer)state.initializer).treeConstraintRepository.get(constraintsName));
+        if (myConstraints==null)
+            state.output.error("The GP tree constraint \"" + constraintsName + "\" could not be found.");
+        return myConstraints;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPType.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/GPType.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/GPType.java	(revision 6152)
@@ -0,0 +1,173 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GPType.java
+ * 
+ * Created: Fri Aug 27 20:54:23 1999
+ * By: Sean Luke
+ */
+
+/**
+ * GPType is a Clique which represents types in 
+ * Strongly-Typed Genetic Programming (STGP). 
+ * (David Montana, "Strongly-Typed Genetic Programming", 
+ * <i>Evolutionary Computation</i> 3(2), pp. 199-230).
+ *
+ * <p>In STGP, each function node has a <i>return-type</i>, and each of
+ * its arguments also have assigned types.  Furthermore, the tree
+ * itself has a predefined "tree type".  STGP permits crossover
+ * and mutation of trees only with the constraint that each node's
+ * return type "fits" with the corresponding argument type in the
+ * node's parent; further, the root node's return type must "fit" with
+ * the tree type.
+ *
+ * <p>The simplest definition of "fit" is that the types must be the same.
+ * Montana calls this "Basic" STGP (see section 2.1).  This is the form
+ * of STGP that most implementations do, and it's not very powerful.
+ *
+ * <p>Montana further defined generic functions (ones with polymorphic
+ * data types).  Such beasts "fit" only if the trees involved can be
+ * unified to make them fit, an expensive proceedure which ECJ does not
+ * support.  However, ECJ's does support a compromise between simple 
+ * "Basic" STGP and STGP with polymorphic types: providing both 
+ * <i>atomic types</i> (basic STGP) and a more powerful notion of 
+ * <i>set types</i>.
+ *
+ * <p>An atomic type is a basic GP type.  Atomic types "fit" only
+ * if they're the same object (this implementation uses == ).   A problem
+ * domain that only uses atomic types is essentially doing "Basic" STGP.
+ *
+ * <p>Set types are sets of atomic types.  A set type "fits" with an
+ * atomic type only if it contains the atomic type in its set.  A set type
+ * "fits" with another set type only if they share at least one atomic type
+ * in common (that is, the intersection of their sets is nonempty).
+ *
+ * <p>Set types allow for types which can fit in several different generic
+ * places -- an object can now say that it "fits" with types
+ * A or B or C, but not D or E.
+ *
+ * <p>GPTypes are a Clique, and they set themselves up as a group; in general
+ * you should not create any new GPTypes.   You should also not attempt to
+ * clone them, since type equivalence is determined partially by pointer
+ * equivalence.
+ *
+ * <p><b>What Set and Atomic Types Can Do. </b>
+ * Set and Atomic types can be used for most of the existing literature
+ * (major exceptions: Tina Yu's work, and also work on multiplying 
+ * matricies with GP).  For example,  
+ * I am fairly certain that atomic types and set types can be used to
+ * implement any mechanism devisable using type inheritance along the lines
+ * of (Thomas Haynes, Dale Schoenefeld, and Roger Wainwright, 
+ * "Type Inheritance in Strongly Typed Genetic Programming",
+ * <i>Advances in Genetic Progrmming 2</i>, pp. 359-376.  
+ * Let's say that you wanted to define some classes a-la Haynes <i>et al</i>
+ * with multiple inheritance,
+ * say, a Vehicle, a Red-Thing, a Car (which is a Vehicle), a Truck (which
+ * is a Vehicle), and a Fire-Truck (which is a Truck and a Red-Thing).  Now, you
+ * want to guarantee that children nodes fit with parents only if the return
+ * value of the children node is a subclass of the parents' argument slot.
+ * You can do this as follows: first, you create an atomic type for each
+ * of the classes above.  Then you create the set types: Vehicle-S = {Vehicle},
+ * Red-Thing-S = {Red-Thing}, Car-S = {Car,Vehicle}, Truck-S = {Truck,Vehicle},
+ * and Fire-Truck-S = {Fire-Truck,Truck,Red-Thing}.  Then you set up your function
+ * sets so that the return type of each node is an <i>atomic type</i>, and the
+ * argument types of nodes are <i>set types</i>.  For example, if the function
+ * FOO is supposed to take a Fire Truck and a Car and return another Car, then
+ * you set the return type to Car, the first argument type to Fire-Truck-S, and the
+ * second return type to Car-S.  The rest is left up to the reader as an excercise :-)
+ *
+ * <p>I also believe that set types and atomic types can handle most grammar-based
+ * mechanisms I've seen, which in general appear reducable to STGP anyway;
+ * for example, in Eric Jones and William Joines, "Genetic
+ * Design of Electronic Circuits".  <i>Late-Breaking Papers at the 1999 Genetic 
+ * and Evolutionary Computatiokn Conference</i>.  124-133.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>a.size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of atomic types)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>s.size</tt><br>
+ <font size=-1>int &gt;= 0</font></td>
+ <td valign=top>(number of set types)</td></tr>
+
+ <tr><td valign=top><i>base</i><tt>.a.</tt><i>n</i><tt>.name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of atomic type <i>n</i>.  Must be different from other GPType names)</td></tr>
+
+ <tr><td valign=top><i>base</i><tt>.s.</tt><i>n</i><tt>.name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of set type <i>n</i>.  Must be different from other GPType names)</td></tr>
+
+ <tr><td valign=top><i>base</i><tt>.s.</tt><i>n</i><tt>.size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of atomic types in the set type <i>n</i>'s set)</td></tr>
+
+ <tr><td valign=top><i>base</i><tt>.s.</tt><i>n</i><tt>.member.</tt><i>m</i><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of atomic type member <i>m</i> in set type <i>n</i>)</td></tr>
+ </table>
+
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class GPType implements Clique
+    {
+    public final static String P_NAME = "name";
+
+    /** The name of the type */
+    public String name;
+
+    /** The preassigned integer value for the type */
+    public int type;
+
+    /** Am I compatible with ("fit" with) <i>t</i>?  For two atomic
+        types, this is done by direct pointer equality.  For
+        two set types, this is done by determining if the intersection
+        is nonempty.  A set type is compatible with an atomic type
+        if it contains the atomic type in its set. */
+    public abstract boolean compatibleWith(final GPInitializer initializer, final GPType t);
+
+    /** Returns the type's name */
+    public String toString() { return name; }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // What's my name?
+        name = state.parameters.getString(base.push(P_NAME),null);
+        if (name==null)
+            state.output.fatal("No name was given for this GP type.",
+                base.push(P_NAME));
+
+        // Register me
+        GPType old_type = (GPType)(((GPInitializer)state.initializer).typeRepository.put(name,this));
+        if (old_type != null)
+            state.output.fatal("The GP type \"" + name + "\" has been defined multiple times.", base.push(P_NAME));     
+        }
+
+    /** Returns a type for a given name.
+        You must guarantee that after calling typeFor(...) one or
+        several times, you call state.output.exitIfErrors() once. */
+
+    public static GPType typeFor(final String typeName,
+        final EvolutionState state)
+        {
+        GPType myType = (GPType)(((GPInitializer)state.initializer).typeRepository.get(typeName));
+        if (myType==null)
+            state.output.error("The GP type \"" + typeName + "\" could not be found.");
+        return myType;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/README	(revision 6152)
@@ -0,0 +1,162 @@
+This package, and subpackages, comprise the genetic programming facility of
+ECJ.  This is by far ECJ's best-tested facility.
+
+The GP facility is fairly complex and detailed.  You might do well to start
+with the ECJ tutorials, one of which is a GP tutorial.  There are a number of
+GP example applications in the app directory as well (including regression,
+ant, multiplexer, lawnmower, etc.)
+
+The gp.params file contains certain parameters common to gp problems.  But more
+useful to you will be the koza.params file, located in the 'koza' directory,
+which contains an extensive collection of default parameter settings common to
+the GP problems often found in John Koza's works.  Most of the application
+examples rely on the koza.params files for their defaults.  After doing the
+tutorials, it might be helpful to peruse the koza.params file.
+
+
+
+
+GP Individuals
+--------------
+
+ECJ's GP system is tree-based.  GP individuals use the GPIndividual class or
+a subclass, whose species must be GPSpecies or a subclass.  A GPIndividual
+contains an array of GPTrees, each representing a tree in the individual.
+Commonly there's only one such tree, but there's no reason you can't have
+more (and we've used as many as eleven in the past).  Just as individuals
+share common data in Species, GPTrees share common data in GPTreeConstraints
+objects.  That data is primarily the function set used by the GPTree in
+question and the return type of the tree.  Hanging from GPTrees are trees
+whose nodes are all subclasses of GPNode.  GPNodes contain an array of GPNodes
+(the "children" to that GPNode).  If a GPNode has no children, its array may
+be null rather than empty, to save a bit of memory.  Various GPNodes share 
+common data in GPNodeConstraints objects, which largely specify the arity 
+of the GPNode in question (that is, the number of children it has), its 
+return type, and, for each array slot, the type that children in that slot
+must have their return types type-compatible with.
+
+Each GPNode has a parent.  That parent is usually another GPNode (to which it
+is the child).  The root GPNode has the GPTree as its parent.  Thus GPNode
+and GPTree both implement the GPNodeParent interface.
+
+
+GP Function Sets and Node Builders
+----------------------------------
+
+Each GPTreeConstraints contains a GPFunctionSet object, essentially a
+collection of prototypical GPNodes.  GP trees are constructed from copies
+of these nodes.  GPTreeConstraints also contain a GPNodeBuilder of some kind,
+responsible for actually constructing a brand new GP tree.  Some common
+GPNodeBuilders are located in the koza directory (GrowBuilder, HalfBuilder,
+and FullBuilder, all subclasses of KozaBuilder).  Other GPNodeBuilders are 
+located in the build directory.
+
+
+Types
+-----
+
+GPNodes can't just be strung together willy-nilly to form trees.  Not only
+must a tree only contain nodes drawn from that tree's function set, but
+certain constraints are placed on which nodes may serve as children to other
+nodes, or as the root of the tree.  These constraints are called types.  ECJ's
+type facility defines an abstract superclass of types called GPType with two
+concrete subclasses, GPAtomicType and GPSetType.  These types are stored in
+global collections defined within these classes.  Here's how it works.  Each
+GPNode has a return type (either an atomic or set type).  GPNodes which can
+have children also have separate types for each of those child slots.  In order
+for a node to be permitted as a child of another node in a given slot, the 
+types must be compatible.  Atomic types with one another are compatible only 
+if they are exactly the same type.  Set types contain sets of atomic types, and
+two set types are compatible with one another only if their intersection is
+nonempty.  You can mix atomic and set typing as well: a set type is compatible
+with an atomic type if the atomic type is a member of the set type.   GPTrees
+also specify a type for the root node: a GPNode's return type must be
+compatible with this type for the node to be legal as a root.  The most common
+situation is for no typing to be used at all, or more properly described,
+for all nodes to use a single atomic type.  The koza.params file in the
+koza directory defines seven GPNodeConstraints (representing nodes with
+zero through six children), all of which use the same atomic type everywhere.
+For no good reason the name of that type, in that file, is 'nil'.
+
+The various global cliques (GPNodeConstraints, GPTypes, and GPFunctionSets) 
+are all set up initially, and stored for easy access, in GPInitializer, a
+subcass of Initializer which you must use (or a subclas thereof).
+
+
+Problems and Special Kinds of GPNodes
+-------------------------------------
+
+Part of the process of making a GP problem involves the construction of the
+function set used for that problem.  Usually this means directly subclassing
+GPNode several times.  ECJ provides four utility GPNode subclasses which might
+also be useful to you.  The ERC class permits the creation of Ephemeral Random
+Constants (ERCs), essentially GPNodes which describe constant values which
+are created randomly initially but are constant thereafter.  To create them you
+need to subclass ERC and override certain methods.  The ADF class defines
+Automatically Defined Function nodes which cause execution to transfer to
+another GPTree in the individual (an Automatically Defined Function).
+Associated with ADFs are ADFArgument nodes appearing in the corresponding 
+Automatically Defined Function tree.  These nodes provide the return values
+to children of the original ADF node.  Last, ADM nodes (for Automatically
+Defined Macro) are like ADFs, only the return values of their ADFArguments
+are computed on-the-fly and dynamically rather than beforehand.
+
+All GP problems must be subclasses of GPProblem, which contains the machinery
+to make ADFs work (including special classes for execution transfer,
+ADFContext and ADFStack, which you'll never need to deal with).
+
+When a GP tree is executed, the root node is handed a GPData object which may
+contain information for the root node to act on, or (more commonly) slots of
+data for it to fill out before it hands the GPData object back.  The root node
+goes on to reuse this GPData object by handing it to its children (and receiving
+it back) and so on down the line.  As part of building a GPProblem, you'll
+probably need to define a GPData subclass.
+
+
+Breeding
+--------
+
+GP has its own traditional breeding pipeline, which is defined entirely in
+the koza.params file as well.  Breeding pipelines often, but are not required
+to, subclass from GPBreedingPipeline, which checks to make certain that the
+individual's species is a GPSpecies.  Common pipelines are found in the
+koza directory: CrossoverPipeline and MutationPipeline.  Other commonly used
+GP pipelines are in the ec/breed directory: ReproductionPipeline and
+MultiBreedingPipeline.
+
+To breed individuals, it's often necessary to select points within a tree
+(to do crossover on, for example).  This is the job of the subclasses of the
+abstract superclass GPNodeSelector.  A single concrete subclass in the 'koza'
+directory, KozaNodeSelector, can pick random nodes in a tree with certain
+probabilities based on how often you want certain kinds of nodes (the root,
+nonleaf nodes, leaf nodes, or all nodes).
+
+Certain utility functions in GPNode rely on an auxillary class, GPNodeGatherer,
+which is largely private and probably should be folded into GPNode.
+
+
+Fitness and Statistics
+----------------------
+
+Koza-style genetic programming has its own traditional fitness function which
+presents the fitness value in different guises.  The raw fitness is set by the
+application problem.  The standardized fitness converts this into a value where
+0 is optimal and infinity is worse than the worst possible.  In ECJ these two
+fitness values are the same thing.  The adjusted fitness is the raw fitness
+converted so that 1 is optimal and 0 is worse than the worst possible.  This is
+defined as adjustedFitness = (1 / (1 + rawFitness)).  Last, the auxillary hits
+measure, mostly for historical reasons, indicates how many successful tests were
+made for certain kinds of problems.
+
+Because of this fitness complexity, ECJ has its own Fitness subclass different
+from SimpleFitness which is used for GP problems: KozaFitness (in the 'koza'
+directory).  You can use whatever fitness you want for your problem, but
+KozaFitness may be convenient.
+
+Associated with KozaFitness are two revised Statistics subclasses which provide
+a variety of useful data special to GP.  KozaStatistics logs the best trees
+of each run, plus certain fitness information.  KozaShortStatistics logs a
+variety of easily parsed statistical information, one line per generation.
+Both are located in the 'koza' directory.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/GPBreedDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/GPBreedDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/GPBreedDefaults.java	(revision 6152)
@@ -0,0 +1,39 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.gp.GPDefaults;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * GPBreedDefaults.java
+ * 
+ * Created: Tue Oct 12 17:44:47 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A static class that returns the base for "default values" which various
+ * GP breeding
+ * operators use, rather than making the user specify them all on a per-
+ * species basis.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class GPBreedDefaults implements DefaultsForm
+    {
+    public static final String P_BREED = "breed";
+
+    /** Returns the default base, which is built off of the GPDefaults base. */
+    public static final Parameter base()
+        {
+        return GPDefaults.base().push(P_BREED);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/InternalCrossoverPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/InternalCrossoverPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/InternalCrossoverPipeline.java	(revision 6152)
@@ -0,0 +1,361 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * InternalCrossoverPipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * InternalCrossoverPipeline picks two subtrees from somewhere within an individual,
+ * and crosses them over.  Before doing so, it checks to make sure that the
+ * subtrees come from trees with the same tree constraints, that the subtrees
+ * are swap-compatible with each other, that the new individual does not violate
+ * depth constraints, and that one subtree does not contain the other.  It tries
+ * <tt>tries</tt> times to find a valid subtree pair to cross over.  Failing this,
+ * it just copies the individual.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>maxdepth</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(maximum valid depth of the crossed-over individual's trees)</td></tr>
+ 
+ <tr><td valign=top><i>base</i>.<tt>ns.</tt>0<br>
+ <font size=-1>classname, inherits and != GPNodeSelector</font></td>
+ <td valign=top>(GPNodeSelector for subtree 0.  </td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>ns.</tt>1<br>
+ <font size=-1>classname, inherits and != GPNodeSelector,<br>
+ or String <tt>same<tt></font></td>
+ <td valign=top>(GPNodeSelector for subtree 1.  If value is <tt>same</tt>, then <tt>ns.1</tt> a copy of whatever <tt>ns.0</tt> is)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(first tree for the crossover; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.1</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(second tree for the crossover; if parameter doesn't exist, tree is picked at random.  This tree <b>must</b> have the same GPTreeConstraints as <tt>tree.0</tt>, if <tt>tree.0</tt> is defined.)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.internal-xover
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns.</tt><i>n</i><br>
+ <td>nodeselect<i>n</i> (<i>n</i> is 0 or 1)</td></tr>
+ </table>
+
+ </table>
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class InternalCrossoverPipeline extends GPBreedingPipeline
+    {
+    public static final String P_INTERNALCROSSOVER = "internal-xover";
+    public static final String P_NUM_TRIES = "tries";
+    public static final String P_MAXDEPTH = "maxdepth";
+    public static final int NUM_SOURCES = 1;
+
+    
+    /** How the pipeline chooses the first subtree */
+    public GPNodeSelector nodeselect0;
+
+    /** How the pipeline chooses the second subtree */
+    public GPNodeSelector nodeselect1;
+
+    /** How many times the pipeline attempts to pick nodes until it gives up. */
+    public int numTries;
+
+    /** The deepest tree the pipeline is allowed to form.  Single terminal trees are depth 1. */
+    public int maxDepth;
+
+    /** Is the first tree fixed?  If not, this is -1 */
+    public int tree1;
+
+    /** Is the second tree fixed?  If not, this is -1 */
+    public int tree2;
+
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_INTERNALCROSSOVER); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        InternalCrossoverPipeline c = (InternalCrossoverPipeline)(super.clone());
+        
+        // deep-cloned stuff
+        c.nodeselect0 = (GPNodeSelector)(nodeselect0.clone());
+        c.nodeselect1 = (GPNodeSelector)(nodeselect1.clone());
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+        Parameter p = base.push(P_NODESELECTOR).push("0");
+        Parameter d = def.push(P_NODESELECTOR).push("0");
+
+        nodeselect0 = (GPNodeSelector)
+            (state.parameters.getInstanceForParameter(
+                p,d, GPNodeSelector.class));
+        nodeselect0.setup(state,p);
+
+        p = base.push(P_NODESELECTOR).push("1");
+        d = def.push(P_NODESELECTOR).push("1");
+
+        if (state.parameters.exists(p,d) &&
+            state.parameters.getString(p,d).equals(V_SAME))
+            // can't just copy it this time; the selectors
+            // use internal caches.  So we have to clone it no matter what
+            nodeselect1 = (GPNodeSelector)(nodeselect0.clone());
+        else
+            {
+            nodeselect1 = (GPNodeSelector)
+                (state.parameters.getInstanceForParameter(
+                    p,d, GPNodeSelector.class));
+            nodeselect1.setup(state,p);
+            }
+
+        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES),1);
+        if (numTries == 0)
+            state.output.fatal("InternalCrossover Pipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+
+        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),def.push(P_MAXDEPTH),1);
+        if (maxDepth==0)
+            state.output.fatal("InternalCrossover Pipeline has an invalid maximum depth (it must be >= 1).",base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+
+        tree1 = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree1 = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree1==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+
+        tree2 = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+1),
+                def.push(P_TREE).push(""+1)))
+            {
+            tree2 = state.parameters.getInt(base.push(P_TREE).push(""+1),
+                def.push(P_TREE).push(""+1),0);
+            if (tree2==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+
+    /** Returns true if inner1 and inner2 do not contain one another */
+    private boolean noContainment(GPNode inner1, GPNode inner2)
+        {
+        GPNodeParent current = inner1;
+        while(current != null && current instanceof GPNode)
+            {
+            if (current==inner2) return false;  // inner2 contains inner1
+            current = ((GPNode)current).parent;
+            }
+        current = inner2;
+        while(current != null && current instanceof GPNode)
+            {
+            if (current==inner1) return false;  // inner1 contains inner2
+            current = ((GPNode)current).parent;
+            }
+        return true;
+        }
+
+    /** Returns true if inner1 can feasibly be swapped into inner2's position. */
+
+    boolean verifyPoints(GPInitializer initializer, GPNode inner1, GPNode inner2)
+        {
+        // first check to see if inner1 is swap-compatible with inner2
+        // on a type basis
+        if (!inner1.swapCompatibleWith(initializer, inner2)) return false;
+
+        // next check to see if inner1 can fit in inner2's spot
+        if (inner1.depth()+inner2.atDepth() > maxDepth) return false;
+
+        // checks done!
+        return true;
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        for(int q=start;q<n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+                    
+            if (tree1!=TREE_UNFIXED && (tree1<0 || tree1 >= i.trees.length))
+                // uh oh
+                state.output.fatal("Internal Crossover Pipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+                
+            if (tree2!=TREE_UNFIXED && (tree2<0 || tree2 >= i.trees.length))
+                // uh oh
+                state.output.fatal("Internal Crossover Pipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+
+            GPIndividual j;
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                }
+            else // need to copy it
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    j.trees[x] = (GPTree)(i.trees[x].lightClone());  // light clone
+                    j.trees[x].owner = j;
+                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                    j.trees[x].child.parent = j.trees[x];
+                    j.trees[x].child.argposition = 0;
+                    }
+                }
+
+
+            int t1=0; int t2=0;
+            if (tree1==TREE_UNFIXED || tree2==TREE_UNFIXED) 
+                {
+                do
+                    // pick random trees  -- their GPTreeConstraints must be the same
+                    {
+                    if (tree1==TREE_UNFIXED)
+                        if (i.trees.length > 1)
+                            t1 = state.random[thread].nextInt(i.trees.length);
+                        else t1 = 0;
+                    else t1 = tree1;
+                    
+                    if (tree2==TREE_UNFIXED) 
+                        if (i.trees.length > 1)
+                            t2 = state.random[thread].nextInt(i.trees.length);
+                        else t2 = 0;
+                    else t2 = tree2;
+                    } while (i.trees[t1].constraints(initializer) != i.trees[t2].constraints(initializer));
+                }
+            else
+                {
+                t1 = tree1;
+                t2 = tree2;
+                // make sure the constraints are okay
+                if (i.trees[t1].constraints(initializer) 
+                    != i.trees[t2].constraints(initializer)) // uh oh
+                    state.output.fatal("GP Crossover Pipeline's two tree choices are both specified by the user -- but their GPTreeConstraints are not the same");
+                }
+
+            
+            // prepare the nodeselectors
+            nodeselect0.reset();
+            nodeselect1.reset();
+            
+            
+            // pick some nodes
+            
+            GPNode p1=null;
+            GPNode p2=null;
+            boolean res = false;
+
+            for(int x=0;x<numTries;x++)
+                {
+                // pick a node in individual 1
+                p1 = nodeselect0.pickNode(state,subpopulation,thread,j,j.trees[t1]);
+                
+                // pick a node in individual 2
+                p2 = nodeselect1.pickNode(state,subpopulation,thread,j,j.trees[t2]);
+                
+                // make sure they're not the same node
+                res = (p1!=p2 &&
+                    // check for containment
+                    (t1!=t2 || noContainment(p1,p2)) &&
+                    // check for validity
+                    verifyPoints(initializer,p1,p2) &&   // 1 goes into 2
+                    verifyPoints(initializer,p2,p1));    // 2 goes into 1
+                if (res) break; // got one
+                }
+
+            // if res, then it's time to cross over!
+            if (res)
+                {
+                GPNodeParent oldparent = p1.parent;
+                byte oldargposition = p1.argposition;
+                p1.parent = p2.parent;
+                p1.argposition = p2.argposition;
+                p2.parent = oldparent;
+                p2.argposition = oldargposition;
+                
+                if (p1.parent instanceof GPNode)
+                    ((GPNode)(p1.parent)).children[p1.argposition] = p1;
+                else ((GPTree)(p1.parent)).child = p1;
+
+                if (p2.parent instanceof GPNode)
+                    ((GPNode)(p2.parent)).children[p2.argposition] = p2;
+                else ((GPTree)(p2.parent)).child = p2;
+
+                j.evaluated = false;  // we've modified it
+                }
+            
+            // add the individuals to the population
+            inds[q] = j;
+            }
+        return n;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateAllNodesPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateAllNodesPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateAllNodesPipeline.java	(revision 6152)
@@ -0,0 +1,304 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * MutateAllNodesPipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutateAllNodesPipeline implements the AllNodes mutation algorithm described
+ * in Kumar Chellapilla,
+ * "A Preliminary Investigation into Evolving Modular Programs without Subtree
+ * Crossover", GP98.
+ *
+ * <p>MutateAllNodesPipeline chooses a subtree and for each node <i>n</i>
+ * in that subtree, it replaces <i>n</i> with a randomly-picked node of the same
+ * arity and type constraints.  Thus the original topological structure is
+ * the same but the nodes are different.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns</tt>.0<br>
+ <font size=-1>classname, inherits and != GPNodeSelector</font></td>
+ <td valign=top>(GPNodeSelector for tree)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.mutate-all-nodes
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
+ <td>The GPNodeSelector selector</td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutateAllNodesPipeline extends GPBreedingPipeline
+    {
+    public static final String P_MUTATEALLNODES = "mutate-all-nodes";
+    public static final int NUM_SOURCES = 1;
+
+    /** How the pipeline chooses a subtree to mutate */
+    public GPNodeSelector nodeselect;
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    public Parameter defaultBase() 
+        { 
+        return GPBreedDefaults.base().push(P_MUTATEALLNODES); 
+        }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        MutateAllNodesPipeline c = (MutateAllNodesPipeline)(super.clone());
+        
+        // deep-cloned stuff
+        c.nodeselect = (GPNodeSelector)(nodeselect.clone());
+        return c;
+        }
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        Parameter p = base.push(P_NODESELECTOR).push(""+0);
+        nodeselect = (GPNodeSelector)
+            (state.parameters.getInstanceForParameter(
+                p,def.push(P_NODESELECTOR).push(""+0),
+                GPNodeSelector.class));
+        nodeselect.setup(state,p);
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+    /** Returns a node which is swap-compatible with returntype, and whose arguments are swap-compatible with the current children of original.  You need to clone this node. */
+
+    private GPNode pickCompatibleNode(
+        final GPNode original, final GPFunctionSet set, 
+        final EvolutionState state, final GPType returntype, final int thread)
+        {
+        // an expensive procedure: we will linearly search for a valid node
+        int numValidNodes = 0;
+        
+        int type = returntype.type;
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        int len = original.constraints(initializer).childtypes.length;
+        boolean failed;
+
+        if (initializer.numAtomicTypes + 
+            initializer.numSetTypes == 1)  // easy
+            numValidNodes = set.nodesByArity[type][len].length;
+        else for(int x=0;x<set.nodesByArity[type][len].length;x++) // ugh, the hard way -- nodes swap-compatible with type, and of arity len
+                 {
+                 failed = false;
+                 for(int y=0;y<set.nodesByArity[type][len][x].constraints(initializer).childtypes.length;y++)
+                     if (!set.nodesByArity[type][len][x].constraints(initializer).
+                         childtypes[y].compatibleWith(initializer,original.children[y].
+                             constraints(initializer).returntype))
+                         { failed = true; break; }
+                 if (!failed) numValidNodes++;
+                 }
+        
+        // we must have at least success -- the node itself.  Otherwise we're
+        // in deep doo-doo.
+
+        // now pick a random node number
+        int nodenum = state.random[thread].nextInt(numValidNodes);
+
+        // find and return that node
+        int prosnode = 0;
+        
+        if (numValidNodes == set.nodesByArity[type][len].length) // easy
+            return set.nodesByArity[type][len][nodenum];
+        else for(int x=0;x<set.nodesByArity[type][len].length;x++) // ugh, the hard way -- nodes swap-compatible with type, and of arity len
+                 {
+                 failed = false;
+                 for(int y=0;y<set.nodesByArity[type][len][x].constraints(initializer).childtypes.length;y++)
+                     if (!set.nodesByArity[type][len][x].constraints(initializer).
+                         childtypes[y].compatibleWith(initializer,original.children[y].
+                             constraints(initializer).returntype))
+                         { failed = true; break; }
+                 if (!failed) 
+                     {
+                     if (prosnode == nodenum)  // got it!
+                         return set.nodesByArity[type][len][x];
+                     prosnode++;
+                     }
+                 }
+
+        // should never be able to get here
+        throw new InternalError();  // whoops!
+
+        }
+
+
+    /** Returns a brand-new tree which is swap-compatible with returntype, created by making nodes "compatible" with the equivalent nodes in the tree rooted at original.  You need to set the parent and argumentposition of the root yourself.*/
+
+    private GPNode generateCompatibleTree(final GPNode original, final GPFunctionSet set, final EvolutionState state, final GPType returntype, final int thread) 
+        {
+        // pick a new node and clone it
+        GPNode node = (GPNode)(pickCompatibleNode(original,set,state,returntype,thread).lightClone());
+        
+        // reset it
+        node.resetNode(state,thread);
+
+        // fill in its children
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        for (int x=0;x<node.children.length;x++)
+            {
+            node.children[x] = generateCompatibleTree(original.children[x],set,state,original.constraints(initializer).childtypes[x],thread);
+            node.children[x].parent = node;
+            node.children[x].argposition = (byte)x;
+            }
+        return node;
+        }
+
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+            
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("MutateAllNodesPipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+
+            int t;
+            // pick random tree
+            if (tree==TREE_UNFIXED)
+                if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                else t = 0;
+            else t = tree;
+            
+            // prepare the nodeselector
+            nodeselect.reset();
+            
+            // pick a node
+            
+            GPNode p1=null;  // the node we pick
+            GPNode p2=null;
+            
+            // pick a node in individual 1
+            p1 = nodeselect.pickNode(state,subpopulation,thread,i,i.trees[t]);
+            
+            // generate a tree with a new root but the same children,
+            // which we will replace p1 with
+            
+            GPType type;
+            type = p1.parentType(initializer);
+            
+            p2 = generateCompatibleTree(p1,i.trees[t].constraints(initializer).functionset,state,type,thread);
+            // we'll need to set p2.argposition and p2.parent further down
+
+            
+            GPIndividual j;
+
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                p2.parent = p1.parent;
+                p2.argposition = p1.argposition;
+                if (p2.parent instanceof GPNode)
+                    ((GPNode)(p2.parent)).children[p2.argposition] = p2;
+                else ((GPTree)(p2.parent)).child = p2;
+                j.evaluated = false;  // we've modified it
+                }
+            else  // need to copy it in
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    if (x==t)  // we've got a tree with a kicking cross position!
+                        { 
+                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                        j.trees[x].owner = j;
+                        j.trees[x].child = i.trees[x].child.cloneReplacingNoSubclone(p2,p1);
+                        j.trees[x].child.parent = j.trees[x];
+                        j.trees[x].child.argposition = 0;
+                        j.evaluated = false; 
+                        } // it's changed
+                    else 
+                        {
+                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                        j.trees[x].owner = j;
+                        j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                        j.trees[x].child.parent = j.trees[x];
+                        j.trees[x].child.argposition = 0;
+                        }
+                    }
+                }
+
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateDemotePipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateDemotePipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateDemotePipeline.java	(revision 6152)
@@ -0,0 +1,518 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*; 
+
+/* 
+ * MutateDemotePipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutateDemotePipeline works very similarly to the DemoteNode algorithm
+ * described in  Kumar Chellapilla,
+ * "A Preliminary Investigation into Evolving Modular Programs without Subtree
+ * Crossover", GP98, and is also similar to the "insertion" operator found in
+ * Una-May O'Reilly's thesis,
+ * <a href="http://www.ai.mit.edu/people/unamay/thesis.html">
+ * "An Analysis of Genetic Programming"</a>.
+ *
+ * <p>MutateDemotePipeline tries picks a random tree, then picks
+ * randomly from all the demotable nodes in the tree, and demotes one.  
+ * If its chosen tree has no demotable nodes, or demoting
+ * its chosen demotable node would make the tree too deep, it repeats
+ * the choose-tree-then-choose-node process.  If after <i>tries</i> times
+ * it has failed to find a valid tree and demotable node, it gives up and simply
+ * copies the individual.
+ *
+ * <p>"Demotion" means to take a node <i>n</i> and insert a new node <i>m</i>
+ * between <i>n</i> and <i>n</i>'s parent.  <i>n</i> becomes a child of
+ * <i>m</i>; the place where it becomes a child is determined at random
+ * from all the type-compatible slots of <i>m</i>.  The other child slots
+ * of <i>m</i> are filled with randomly-generated terminals.  
+ * Chellapilla's version of the algorithm always
+ * places <i>n</i> in child slot 0 of <i>m</i>.  Because this would be
+ * unneccessarily restrictive on strong typing, MutateDemotePipeline instead
+ * picks the slot at random from all available valid choices.
+ *
+ * <p>A "Demotable" node means a node which is capable of demotion
+ * given the existing function set.  In general to demote a node <i>foo</i>,
+ * there must exist in the function set a nonterminal whose return type
+ * is type-compatible with the child slot <i>foo</i> holds in its parent;
+ * this nonterminal must also have a child slot which is type-compatible
+ * with <i>foo</i>'s return type.
+ *
+ * <p>This method is very expensive in searching nodes for
+ * "demotability".  However, if the number of types is 1 (the
+ * GP run is typeless) then the type-constraint-checking
+ * code is bypassed and the method runs a little faster.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>maxdepth</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(maximum valid depth of a mutated tree)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.mutate-demote
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutateDemotePipeline extends GPBreedingPipeline
+    {
+    public static final String P_MUTATEDEMOTE = "mutate-demote";
+    public static final String P_NUM_TRIES = "tries";
+    public static final String P_MAXDEPTH = "maxdepth";
+    public static final int NUM_SOURCES = 1;
+    
+    /** The number of times the pipeline tries to build a valid mutated
+        tree before it gives up and just passes on the original */
+    int numTries;
+
+    /** The maximum depth of a mutated tree */
+    int maxDepth;
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    /** Temporary Node Gatherer */
+    private GPNodeGatherer gatherer;
+
+    public MutateDemotePipeline() { gatherer = new GPNodeGatherer(); }
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATEDEMOTE); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES),1);
+        if (numTries == 0)
+            state.output.fatal("MutateDemotePipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+    
+        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),
+            def.push(P_MAXDEPTH),1);
+        if (maxDepth==0)
+            state.output.fatal("The MutateDemotePipeline " + base + "has an invalid maximum depth (it must be >= 1).",base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+    public Object clone()
+        { 
+        MutateDemotePipeline obj = (MutateDemotePipeline)(super.clone());
+        obj.gatherer = new GPNodeGatherer();  // make sure they're different
+        return obj;
+        }
+
+
+    private boolean demotable(final GPInitializer initializer,
+        final GPNode node, final GPFunctionSet set)
+        {
+        GPType t;
+
+        if (node.parent instanceof GPNode)  // ugh, expensive
+            t = ((GPNode)(node.parent)).constraints(initializer).childtypes[node.argposition];
+        else 
+            t = ((GPTree)(node.parent)).constraints(initializer).treetype;
+
+        // Now, out of the nonterminals compatible with that return type,
+        // do any also have a child compatible with that return type?  This
+        // will be VERY expensive
+
+        for(int x=0;x<set.nonterminals[t.type].length;x++)
+            for(int y=0;y<set.nonterminals[t.type][x].constraints(initializer).
+                    childtypes.length;y++)
+                if (set.nonterminals[t.type][x].constraints(initializer).childtypes[y].
+                    compatibleWith(initializer,node.constraints(initializer).returntype))
+                    return true;
+        return false;
+        }
+    
+
+    private void demoteSomething(final GPNode node, final EvolutionState state, final int thread, final GPFunctionSet set) 
+        {
+        // if I have just one type, do it the easy way
+        if (((GPInitializer)state.initializer).numAtomicTypes + 
+            ((GPInitializer)state.initializer).numSetTypes == 1)
+            _demoteSomethingTypeless(node,state,thread,set);
+        // otherwise, I gotta do the dirty work
+        else _demoteSomething(node,state,thread,set);
+        }
+
+
+    private void _demoteSomething(final GPNode node, final EvolutionState state, final int thread, final GPFunctionSet set) 
+        {
+        int numDemotable = 0;
+
+        GPType t;
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        
+        if (node.parent instanceof GPNode)  // ugh, expensive
+            t = ((GPNode)(node.parent)).constraints(initializer).childtypes[node.argposition];
+        else 
+            t = ((GPTree)(node.parent)).constraints(initializer).treetype;
+
+        // Now, determine how many nodes we can demote this under --
+        // note this doesn't select based on the total population
+        // of "available child positions", but on the total population
+        // of *nodes* regardless of if they have more than one possible
+        // valid "child position".
+
+        for(int x=0;x<set.nonterminals[t.type].length;x++)
+            for(int y=0;y<set.nonterminals[t.type][x].constraints(initializer).
+                    childtypes.length;y++)
+                if (set.nonterminals[t.type][x].constraints(initializer).childtypes[y].
+                    compatibleWith(initializer,node.constraints(initializer).returntype))
+                    {
+                    numDemotable++; break; // breaks out to enclosing for
+                    }
+
+        // pick a random item to demote -- numDemotable is assumed to be > 0
+        int demoteItem = state.random[thread].nextInt(numDemotable);
+
+        numDemotable=0;
+        // find it
+
+        for(int x=0;x<set.nonterminals[t.type].length;x++)
+            for(int y=0;y<set.nonterminals[t.type][x].constraints(initializer).
+                    childtypes.length;y++)
+                if (set.nonterminals[t.type][x].constraints(initializer).childtypes[y].
+                    compatibleWith(initializer,node.constraints(initializer).returntype))
+                    {
+                    if (numDemotable==demoteItem)
+                        {
+                        // clone the node
+                        GPNode cnode = (GPNode)(set.nonterminals[t.type][x].lightClone());
+
+                        // choose a spot to hang the old parent under
+                        int numSpots=0;
+                        GPType retyp = node.constraints(initializer).returntype;
+                        GPType[] chityp = cnode.constraints(initializer).childtypes;
+
+                        for(int z=0;z<cnode.children.length;z++)
+                            if (chityp[z].compatibleWith(initializer,retyp))
+                                numSpots++;
+                        int choice = state.random[thread].nextInt(numSpots);
+
+                        numSpots=0;
+                        for(int z=0;z<cnode.children.length;z++)
+                            if (chityp[z].compatibleWith(initializer,retyp))
+                                {
+                                if (numSpots==choice)
+                                    {
+                                    // demote the parent, inserting cnode
+                                    cnode.parent = node.parent;
+                                    cnode.argposition = node.argposition;
+                                    cnode.children[z] = node;
+                                    node.parent = cnode;
+                                    node.argposition = (byte)z;
+                                    if (cnode.parent instanceof GPNode)
+                                        ((GPNode)(cnode.parent)).
+                                            children[cnode.argposition] = cnode;
+                                    else ((GPTree)(cnode.parent)).child = cnode;
+
+                                    // this is important to ensure that the
+                                    // demotion only happens once!  Otherwise
+                                    // you'll get really nasty bugs
+                                    numSpots++;  // notice no break
+                                    }
+                                else 
+                                    {
+                                    // hang a randomly-generated terminal off of cnode
+                                    GPNode term = (GPNode)(set.terminals[chityp[z].type][
+                                            state.random[thread].nextInt(
+                                                set.terminals[chityp[z].type].length)].lightClone());
+                                    cnode.children[z] = term;
+                                    term.parent = cnode; // just in case
+                                    term.argposition = (byte)z;  // just in case
+                                    term.resetNode(state,thread);  // let it randomize itself if necessary
+
+                                    // increase numSpots
+                                    numSpots++;  // notice no break
+                                    }
+                                }
+                            else
+                                {
+                                // hang a randomly-generated terminal off of cnode
+                                GPNode term = (GPNode)(set.terminals[chityp[z].type][
+                                        state.random[thread].nextInt(
+                                            set.terminals[chityp[z].type].length)].lightClone());
+                                cnode.children[z] = term;
+                                term.parent = cnode; // just in case
+                                term.argposition = (byte)z;  // just in case
+                                term.resetNode(state,thread);  // let it randomize itself if necessary
+                                }
+                        return;
+                        }
+                    else 
+                        {
+                        numDemotable++; break; // breaks out to enclosing for
+                        }
+                    }
+        // should never reach here
+        throw new InternalError("Bug in demoteSomething -- should never be able to reach the end of the function");
+        }
+
+
+
+    private void _demoteSomethingTypeless(final GPNode node, final EvolutionState state, final int thread, final GPFunctionSet set) 
+        {
+        int numDemotable = 0;
+
+        // since we're typeless, we can demote under any nonterminal
+        numDemotable = set.nonterminals[0].length;
+
+        // pick a random item to demote -- numDemotable is assumed to be > 0
+        int demoteItem = state.random[thread].nextInt(numDemotable);
+
+        numDemotable=0;
+        // find it
+
+        // clone the node
+        GPNode cnode = (GPNode)(set.nonterminals[0][demoteItem].lightClone());
+        
+        GPType[] chityp = cnode.constraints(((GPInitializer)state.initializer)).childtypes;
+
+        // choose a spot to hang the old parent under
+        int choice = state.random[thread].nextInt(cnode.children.length);
+        
+        for(int z=0;z<cnode.children.length;z++)
+            if (z==choice)
+                {
+                // demote the parent, inserting cnode
+                cnode.parent = node.parent;
+                cnode.argposition = node.argposition;
+                cnode.children[z] = node;
+                node.parent = cnode;
+                node.argposition = (byte)z;
+                if (cnode.parent instanceof GPNode)
+                    ((GPNode)(cnode.parent)).
+                        children[cnode.argposition] = cnode;
+                else ((GPTree)(cnode.parent)).child = cnode;
+                }
+            else 
+                {
+                // hang a randomly-generated terminal off of cnode
+                GPNode term = (GPNode)(
+                    set.terminals[chityp[z].type][
+                        state.random[thread].nextInt(
+                            set.terminals[chityp[z].type].length)].lightClone());
+                cnode.children[z] = term;
+                term.parent = cnode; // just in case
+                term.argposition = (byte)z;  // just in case
+                term.resetNode(state,thread);  // let it randomize itself if necessary
+                }
+        }
+
+
+
+
+    private int numDemotableNodes(final GPInitializer initializer,
+        final GPNode root, int soFar, final GPFunctionSet set)
+        {
+        // if I have just one type, skip this and just return
+        // the number of nonterminals in the tree
+        if (initializer.numAtomicTypes + 
+            initializer.numSetTypes == 1)
+            return root.numNodes(GPNode.NODESEARCH_ALL);
+        // otherwise, I gotta do the dirty work
+        else return _numDemotableNodes(initializer,root,soFar,set);
+        }
+
+
+    private int _numDemotableNodes(final GPInitializer initializer,
+        final GPNode root, int soFar, final GPFunctionSet set)
+        {
+        if (demotable(initializer,root, set)) soFar++;
+        for(int x=0;x<root.children.length;x++) 
+            soFar = _numDemotableNodes(initializer,root.children[x],soFar, set);
+        return soFar;
+        }
+
+
+    private GPNode demotableNode;
+
+
+    private int pickDemotableNode(final GPInitializer initializer,
+        final GPNode root, int num, final GPFunctionSet set)
+        {
+        // if I have just one type, skip this and just 
+        // the num-th nonterminal
+        if (initializer.numAtomicTypes + 
+            initializer.numSetTypes == 1)
+            {
+            gatherer.node = null;
+            root.nodeInPosition(num,gatherer,GPNode.NODESEARCH_ALL);
+            if (gatherer.node==null) // uh oh
+                throw new InternalError("Internal error in pickDemotableNode, nodeInPosition didn't find a node!"); // should never happen
+            demotableNode = gatherer.node;
+            return -1; // what _pickDemotableNode() returns...
+            }
+        // otherwise, I gotta do the dirty work
+        else return _pickDemotableNode(initializer,root,num,set);
+        }
+    
+
+    // sticks the node in 
+    private int _pickDemotableNode(final GPInitializer initializer,
+        final GPNode root, int num, final GPFunctionSet set)
+        {
+        if (demotable(initializer,root, set))
+            {
+            num--;
+            if (num==-1)  // found it
+                {
+                demotableNode = root;
+                return num;
+                }
+            }
+        for(int x=0;x<root.children.length;x++)
+            {
+            num = _pickDemotableNode(initializer, root.children[x],num,set);
+            if (num==-1) break;  // someone found it
+            }
+        return num;     
+        }
+    
+
+    /** Returns true if inner1's depth + atdepth +1 is within the depth bounds */
+
+    private boolean verifyPoint(GPNode inner1)
+        {
+        // We know they're swap-compatible since we generated inner1
+        // to be exactly that.  So don't bother.
+
+        // next check to see if inner1 can be demoted
+        if (inner1.depth()+inner1.atDepth()+1 > maxDepth) return false;
+
+        // checks done!
+        return true;
+        }
+
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+            
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("MutateDemotePipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+            
+            GPIndividual j;
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                }
+            else // need to copy it
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                    j.trees[x].owner = j;
+                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                    j.trees[x].child.parent = j.trees[x];
+                    j.trees[x].child.argposition = 0;
+                    }
+                }
+
+            for (int x=0;x<numTries;x++)
+                {
+                int t;
+                // pick random tree
+                if (tree==TREE_UNFIXED)
+                    if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                    else t = 0;
+                else t = tree;
+                
+                // is the tree demotable?
+                int numdemote = numDemotableNodes(initializer, j.trees[t].child,0,j.trees[t].constraints(initializer).functionset);
+                if (numdemote==0) continue; // uh oh, try again
+                
+                // demote the node, or if we're unsuccessful, just leave it alone
+                pickDemotableNode(initializer, j.trees[t].child,state.random[thread].nextInt(numdemote),j.trees[t].constraints(initializer).functionset);
+                
+                // does this node exceed the maximum depth limits?
+                if (!verifyPoint(demotableNode)) continue; // uh oh, try again
+                
+                // demote it
+                demoteSomething(demotableNode,state,thread,j.trees[t].constraints(initializer).functionset);
+                j.evaluated = false;
+                break;
+                }
+
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateERCPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateERCPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateERCPipeline.java	(revision 6152)
@@ -0,0 +1,198 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * MutateERCPipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutateERCPipeline works very similarly to the "Gaussian" algorithm
+ * described in Kumar Chellapilla,
+ * "A Preliminary Investigation into Evolving Modular Programs without Subtree
+ * Crossover", GP98.
+ *
+ * <p>MutateERCPipeline picks a random node from a random tree in the individual,
+ * using its node selector.  It then proceeds to "mutate" every ERC (ephemeral
+ * random constant) located in the subtree rooted at that node.  It does this
+ * by calling each ERC's <tt>mutateERC()</tt> method.  The default form of <tt>mutateERC()</tt>
+ * method is to simply call <tt>resetNode()</tt>, thus randomizing the ERC;
+ * you may want to override this default to provide more useful mutations,
+ * such as adding gaussian noise.
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns</tt>.0<br>
+ <font size=-1>classname, inherits and != GPNodeSelector</font></td>
+ <td valign=top>(GPNodeSelector for tree)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.mutate-erc
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
+ <td>The GPNodeSelector selector</td></tr>
+ </table>
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutateERCPipeline extends GPBreedingPipeline
+    {
+    public static final String P_MUTATEERC = "mutate-erc";
+    public static final int NUM_SOURCES = 1;
+    
+    /** How the pipeline chooses a subtree to mutate */
+    public GPNodeSelector nodeselect;
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATEERC); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        MutateERCPipeline c = (MutateERCPipeline)(super.clone());
+        
+        // deep-cloned stuff
+        c.nodeselect = (GPNodeSelector)(nodeselect.clone());
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter p = base.push(P_NODESELECTOR).push(""+0);
+        Parameter def = defaultBase();
+
+        nodeselect = (GPNodeSelector)
+            (state.parameters.getInstanceForParameter(
+                p,def.push(P_NODESELECTOR).push(""+0),
+                GPNodeSelector.class));
+        nodeselect.setup(state,p);
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+    public final void mutateERCs(final GPNode node, 
+        final EvolutionState state, final int thread)
+        {
+        // is node an erc?
+        if (node instanceof ERC)
+            ((ERC)node).mutateERC(state,thread);
+
+        // mutate children
+        for(int x=0;x<node.children.length;x++)
+            mutateERCs(node.children[x],state,thread);
+        }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+            
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("MutateERCPipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+            
+            int t;
+            // pick random tree
+            if (tree==TREE_UNFIXED)
+                if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                else t = 0;
+            else t = tree;
+            
+            GPIndividual j;
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                }
+            else // need to copy it
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                    j.trees[x].owner = j;
+                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                    j.trees[x].child.parent = j.trees[x];
+                    j.trees[x].child.argposition = 0;
+                    }
+                }
+            j.evaluated = false;
+
+            // prepare the nodeselector
+            nodeselect.reset();
+
+            // Now pick a random node
+            
+            GPNode p = nodeselect.pickNode(state,subpopulation,thread,j,j.trees[t]);
+
+            // mutate all the ERCs in p1's subtree
+
+            mutateERCs(p,state,thread);
+            
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateOneNodePipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateOneNodePipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateOneNodePipeline.java	(revision 6152)
@@ -0,0 +1,274 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * MutateOneNodePipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutateOneNodesPipeline implements the OneNode mutation algorithm described
+ * in Kumar Chellapilla,
+ * "A Preliminary Investigation into Evolving Modular Programs without Subtree
+ * Crossover", GP98.
+ *
+ * <p>MutateOneNodesPipeline chooses a single node in an individual and
+ * replaces it with a randomly-chosen node of the same arity and type 
+ * constraints.  Thus the original topological structure is
+ * the same but that one node is different.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns</tt>.0<br>
+ <font size=-1>classname, inherits and != GPNodeSelector</font></td>
+ <td valign=top>(GPNodeSelector for tree)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.mutate-one-node
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
+ <td>The GPNodeSelector selector</td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutateOneNodePipeline extends GPBreedingPipeline
+    {
+    public static final String P_MUTATEONENODE = "mutate-one-node";
+    public static final int NUM_SOURCES = 1;
+    
+    /** How the pipeline chooses a subtree to mutate */
+    public GPNodeSelector nodeselect;    
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATEONENODE); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        MutateOneNodePipeline c = (MutateOneNodePipeline)(super.clone());
+        
+        // deep-cloned stuff
+        c.nodeselect = (GPNodeSelector)(nodeselect.clone());
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter p = base.push(P_NODESELECTOR).push(""+0);
+        Parameter def = defaultBase();
+
+        nodeselect = (GPNodeSelector)
+            (state.parameters.getInstanceForParameter(
+                p,def.push(P_NODESELECTOR).push(""+0),GPNodeSelector.class));
+        nodeselect.setup(state,p);
+
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+
+
+    /** Returns a node which is swap-compatible with returntype, and whose arguments are swap-compatible with the current children of original.  You need to clone this node. */
+
+
+    private GPNode pickCompatibleNode(final GPNode original, final GPFunctionSet set, final EvolutionState state, final GPType returntype, final int thread)
+        {
+        // an expensive procedure: we will linearly search for a valid node
+        int numValidNodes = 0;
+        
+        int type = returntype.type;
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        int len = original.constraints(initializer).childtypes.length;
+        boolean failed;
+
+        if (initializer.numAtomicTypes + initializer.numSetTypes == 1)  // easy
+            numValidNodes = set.nodesByArity[type][len].length;
+        else for(int x=0;x<set.nodesByArity[type][len].length;x++) // ugh, the hard way -- nodes swap-compatible with type, and of arity len
+                 {
+                 failed = false;
+                 for(int y=0;y<set.nodesByArity[type][len][x].constraints(initializer).childtypes.length;y++)
+                     if (!set.nodesByArity[type][len][x].constraints(initializer).
+                         childtypes[y].compatibleWith(initializer,original.children[y].
+                             constraints(initializer).returntype))
+                         { failed = true; break; }
+                 if (!failed) numValidNodes++;
+                 }
+        
+        // we must have at least success -- the node itself.  Otherwise we're
+        // in deep doo-doo.
+
+        // now pick a random node number
+        int nodenum = state.random[thread].nextInt(numValidNodes);
+
+        // find and return that node
+        int prosnode = 0;
+        
+        if (numValidNodes == set.nodesByArity[type][len].length) // easy
+            return set.nodesByArity[type][len][nodenum];
+        else for(int x=0;x<set.nodesByArity[type][len].length;x++) // ugh, the hard way -- nodes swap-compatible with type, and of arity len
+                 {
+                 failed = false;
+                 for(int y=0;y<set.nodesByArity[type][len][x].constraints(initializer).childtypes.length;y++)
+                     if (!set.nodesByArity[type][len][x].constraints(initializer).
+                         childtypes[y].compatibleWith(initializer,original.children[y].
+                             constraints(initializer).returntype))
+                         { failed = true; break; }
+                 if (!failed) 
+                     {
+                     if (prosnode == nodenum)  // got it!
+                         return set.nodesByArity[type][len][x];
+                     prosnode++;
+                     }
+                 }
+
+        // should never be able to get here
+        throw new InternalError();  // whoops!
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+            
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("MutateOneNodePipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+
+            int t;
+            // pick random tree
+            if (tree==TREE_UNFIXED)
+                if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                else t = 0;
+            else t = tree;
+                    
+            // prepare the nodeselector
+            nodeselect.reset();
+            
+            // pick a node
+            
+            GPNode p1=null;  // the node we pick
+            GPNode p2=null;
+            
+            // pick a node in individual 1
+            p1 = nodeselect.pickNode(state,subpopulation,thread,i,i.trees[t]);
+            
+            // generate a tree with a new root but the same children,
+            // which we will replace p1 with
+            
+            GPType type;
+            type = p1.parentType(initializer);
+            
+            p2 = (GPNode)(pickCompatibleNode(p1,i.trees[t].constraints(initializer).functionset,state,type,thread)).lightClone();
+
+            // if it's an ERC, let it set itself up
+            p2.resetNode(state,thread);
+            
+            // p2's parent and argposition will be set automatically below
+
+            GPIndividual j;
+
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                p1.replaceWith(p2);
+                j.evaluated = false;
+                }
+            else
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    if (x==t)  // we've got a tree with a kicking cross position!
+                        { 
+                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                        j.trees[x].owner = j;
+                        j.trees[x].child = i.trees[x].child.cloneReplacingAtomic(p2,p1);
+                        j.trees[x].child.parent = j.trees[x];
+                        j.trees[x].child.argposition = 0;
+                        j.evaluated = false; 
+                        } // it's changed
+                    else 
+                        {
+                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                        j.trees[x].owner = j;
+                        j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                        j.trees[x].child.parent = j.trees[x];
+                        j.trees[x].child.argposition = 0;
+                        }
+                    }
+                }
+
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutatePromotePipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutatePromotePipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutatePromotePipeline.java	(revision 6152)
@@ -0,0 +1,260 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*; 
+
+/* 
+ * MutatePromotePipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutatePromotePipeline works very similarly to the PromoteNode algorithm
+ * described in  Kumar Chellapilla,
+ * "A Preliminary Investigation into Evolving Modular Programs without Subtree
+ * Crossover", GP98, and is also similar to the "deletion" operator found in
+ * Una-May O'Reilly's thesis,
+ * <a href="http://www.ai.mit.edu/people/unamay/thesis.html">
+ * "An Analysis of Genetic Programming"</a>.
+ *
+ * <p>MutatePromotePipeline tries <i>tries</i> times to find a tree
+ * that has at least one promotable node.  It then picks randomly from
+ * all the promotable nodes in the tree, and promotes one.  If it cannot
+ * find a valid tree in <i>tries</i> times, it gives up and simply
+ * copies the individual.
+ *
+ * <p>"Promotion" means to take a node <i>n</i> whose parent is <i>m</i>,
+ * and replacing the subtree rooted at <i>m</i> with the subtree rooted at <i>n</i>.
+ *
+ * <p>A "Promotable" node means a node which is capable of promotion
+ * given the existing type constraints.  In general to promote a node <i>foo</i>,
+ * <i>foo</i> must have a parent node, and must be type-compatible with the
+ * child slot that its parent fills.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.mutate-promote
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutatePromotePipeline extends GPBreedingPipeline
+    {
+    public static final String P_MUTATEPROMOTE = "mutate-promote";
+    public static final String P_NUM_TRIES = "tries";
+    public static final int NUM_SOURCES = 1;
+    
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    /** The number of times the pipeline tries to build a valid mutated
+        tree before it gives up and just passes on the original */
+    int numTries;
+
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATEPROMOTE); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES),1);
+        if (numTries == 0)
+            state.output.fatal("MutatePromotePipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+    private boolean promotable(final GPInitializer initializer,
+        final GPNode node)
+        {
+        // A node is promotable if:
+        // 1: its parent is a GPNode
+        if (!(node.parent instanceof GPNode))
+            return false;
+        GPNode parent = (GPNode)(node.parent);
+
+        GPType t;
+        if (parent.parent instanceof GPNode)  // ugh, expensive
+            t = ((GPNode)(parent.parent)).constraints(initializer).childtypes[parent.argposition];
+        else 
+            t = ((GPTree)(parent.parent)).constraints(initializer).treetype;
+
+        // 2: the node's returntype is type-compatible with its GRANDparent's return slot
+        return (node.constraints(initializer).returntype.compatibleWith(initializer,t));
+        }
+    
+    
+    private void promoteSomething(final GPNode node)
+        {
+        // the node's parent MUST be a GPNode -- we've checked that already
+        GPNode parent = (GPNode)(node.parent);
+
+        node.parent = parent.parent;
+        node.argposition = parent.argposition;
+        
+        if (parent.parent instanceof GPNode)
+            ((GPNode)(parent.parent)).children[parent.argposition] = node;
+        else ((GPTree)(parent.parent)).child = node;
+        return;
+        }
+
+    private int numPromotableNodes(final GPInitializer initializer,
+        final GPNode root, int soFar)
+        {
+        if (promotable(initializer,root)) soFar++;
+        for(int x=0;x<root.children.length;x++) 
+            soFar = numPromotableNodes(initializer,root.children[x],soFar);
+        return soFar;
+        }
+
+
+    private GPNode promotableNode;
+
+    // sticks the node in 
+    private int pickPromotableNode(final GPInitializer initializer,
+        final GPNode root, int num)
+        {
+        if (promotable(initializer,root))
+            {
+            num--;
+            if (num==-1)  // found it
+                {
+                promotableNode = root;
+                return num;
+                }
+            }
+        for(int x=0;x<root.children.length;x++)
+            {
+            num = pickPromotableNode(initializer,root.children[x],num);
+            if (num==-1) break;  // someone found it
+            }
+        return num;     
+        }
+    
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+                    
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("MutatePromotePipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+
+            GPIndividual j;
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                }
+            else // need to copy it
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                    j.trees[x].owner = j;
+                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                    j.trees[x].child.parent = j.trees[x];
+                    j.trees[x].child.argposition = 0;
+                    }
+                }
+
+            for (int x=0;x<numTries;x++)
+                {
+                int t;
+                // pick random tree
+                if (tree==TREE_UNFIXED)
+                    if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                    else t = 0;
+                else t = tree;
+                
+                // is the tree promotable?
+                int numpromote = numPromotableNodes(initializer, j.trees[t].child,0);
+                if (numpromote==0) continue; // uh oh, try again
+                
+                // promote the node, or if we're unsuccessful, just leave it alone
+                pickPromotableNode(initializer, j.trees[t].child,state.random[thread].
+                    nextInt(numpromote));
+                
+                // promote it
+                promoteSomething(promotableNode );
+                j.evaluated = false;
+                break;
+                }
+
+            
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateSwapPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateSwapPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateSwapPipeline.java	(revision 6152)
@@ -0,0 +1,325 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*; 
+
+/* 
+ * MutateSwapPipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutateSwapPipeline works very similarly to the Swap algorithm
+ * described in  Kumar Chellapilla,
+ * "A Preliminary Investigation into Evolving Modular Programs without Subtree
+ * Crossover", GP98.
+ *
+ * <p>MutateSwapPipeline picks a random tree, then picks
+ * randomly from all the swappable nodes in the tree, and swaps two of its subtrees.  
+ * If its chosen tree has no swappable nodes, it repeats
+ * the choose-tree process.  If after <i>tries</i> times
+ * it has failed to find a tree with swappable nodes, it gives up and simply
+ * copies the individual.
+ *
+ * <p>"Swapping" means to take a node <i>n</i>, and choose two children
+ * nodes of <i>n</i>, <i>x</i> and <i>y</i>, such that <i>x</i>'s return
+ * type is swap-compatible with <i>y</i>'s slot, and <i>y</i>'s return
+ * type is swap-compatible with <i>x</i>'s slot.  The subtrees rooted at
+ * <i>x</i> and <i>y</i> are swapped.
+ *
+ * <p>A "Swappable" node means a node which is capable of swapping
+ * given the existing function set.  In general to swap a node <i>foo</i>,
+ * it must have at least two children whose return types are type-compatible
+ * with each other's slots in <i>foo</i>.
+ *
+ * <p>This method is very expensive in searching nodes for
+ * "swappability".  However, if the number of types is 1 (the
+ * GP run is typeless) then the type-constraint-checking
+ * code is bypassed and the method runs a little faster.
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.mutate-swap
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutateSwapPipeline extends GPBreedingPipeline
+    {
+    public static final String P_MUTATESWAP = "mutate-swap";
+    public static final String P_NUM_TRIES = "tries";
+    public static final int NUM_SOURCES = 1;
+   
+    /** The number of times the pipeline tries to build a valid mutated
+        tree before it gives up and just passes on the original */
+    int numTries;
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATESWAP); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES),1);
+        if (numTries == 0)
+            state.output.fatal("MutateSwapPipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+    /** This very expensive method (for types) 
+        might be improved in various ways I guess. */
+
+    private boolean swappable(final GPInitializer initializer,
+        final GPNode node)
+        {
+        if (node.children.length < 2)
+            return false;  // fast check
+
+        if (initializer.numAtomicTypes + initializer.numSetTypes == 1)
+            return true;  // next fast check
+
+        // we're typed, so now we have to check our type compatibility
+        for(int x=0;x<node.constraints(initializer).childtypes.length-1;x++)
+            for(int y=x+1;y<node.constraints(initializer).childtypes.length;y++)
+                if (node.children[x].constraints(initializer).returntype.compatibleWith(initializer,
+                        node.constraints(initializer).childtypes[y]) &&
+                    node.children[y].constraints(initializer).returntype.compatibleWith(initializer,
+                        node.constraints(initializer).childtypes[x]))
+                    // whew!
+                    return true;
+        return false;
+        }
+    
+    
+    private void swapSomething(final GPNode node, final EvolutionState state, final int thread)
+        {
+        if (((GPInitializer)state.initializer).numAtomicTypes + ((GPInitializer)state.initializer).numSetTypes == 1) // typeless
+            _swapSomethingTypeless(node,state,thread);
+        else _swapSomething(node,state,thread);
+        }
+
+    private void _swapSomethingTypeless(final GPNode node, final EvolutionState state, final int thread)
+        {
+        // assumes that number of child nodes >= 2
+
+        // pick a random first node
+        int x = state.random[thread].nextInt(node.children.length);
+        // pick a random second node
+        int y = state.random[thread].nextInt(node.children.length-1);
+        if (y >= x) y++; // adjust for first node
+
+        // swap the nodes
+
+        GPNode tmp = node.children[x];
+        node.children[x] = node.children[y];
+        node.children[y] = tmp;
+        node.children[x].argposition = (byte)x;
+        node.children[y].argposition = (byte)y;
+        // no need to set parent -- it's the same parent of course
+        }
+
+    
+    private void _swapSomething(final GPNode node, final EvolutionState state, final int thread)
+        {
+        int numSwappable = 0;
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        for(int x=0;x<node.constraints(initializer).childtypes.length-1;x++)
+            for(int y=x+1;y<node.constraints(initializer).childtypes.length;y++)
+                if (node.children[x].constraints(initializer).returntype.compatibleWith(initializer,
+                        node.constraints(initializer).childtypes[y]) &&
+                    node.children[y].constraints(initializer).returntype.compatibleWith(initializer,
+                        node.constraints(initializer).childtypes[x]))
+                    // whew!
+                    numSwappable++;
+
+        // pick a random item to swap -- numSwappable is assumed to be > 0
+        int swapItem = state.random[thread].nextInt(numSwappable);
+
+        numSwappable=0;
+        // find it
+
+        for(int x=0;x<node.constraints(initializer).childtypes.length-1;x++)
+            for(int y=x+1;y<node.constraints(initializer).childtypes.length;y++)
+                if (node.children[x].constraints(initializer).returntype.compatibleWith(initializer,
+                        node.constraints(initializer).childtypes[y]) &&
+                    node.children[y].constraints(initializer).returntype.compatibleWith(initializer,
+                        node.constraints(initializer).childtypes[x]))
+                    {
+                    if (numSwappable==swapItem) // found it
+                        {
+                        // swap the children
+                        GPNode tmp = node.children[x];
+                        node.children[x] = node.children[y];
+                        node.children[y] = tmp;
+                        node.children[x].argposition = (byte)x;
+                        node.children[y].argposition = (byte)y;
+                        // no need to set parent -- it's the same parent of course
+                        return;
+                        }
+                    else numSwappable++;
+                    }
+        }
+
+
+    private int numSwappableNodes(final GPInitializer initializer,
+        final GPNode root, int soFar)
+        {
+        if (swappable(initializer, root)) soFar++;
+        for(int x=0;x<root.children.length;x++) 
+            soFar = numSwappableNodes(initializer, root.children[x],soFar);
+        return soFar;
+        }
+
+
+    private GPNode swappableNode;
+
+    // sticks the node in 
+    private int pickSwappableNode(final GPInitializer initializer,
+        final GPNode root, int num)
+        {
+        if (swappable(initializer, root))
+            {
+            num--;
+            if (num==-1)  // found it
+                {
+                swappableNode = root;
+                return num;
+                }
+            }
+        for(int x=0;x<root.children.length;x++)
+            {
+            num = pickSwappableNode(initializer, root.children[x],num);
+            if (num==-1) break;  // someone found it
+            }
+        return num;     
+        }
+    
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+            
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("MutateSwapPipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+            
+            
+            GPIndividual j;
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                }
+            else // need to copy it
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                    j.trees[x].owner = j;
+                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                    j.trees[x].child.parent = j.trees[x];
+                    j.trees[x].child.argposition = 0;
+                    }
+                }
+            
+            
+            for (int x=0;x<numTries;x++)
+                {
+                int t;
+                // pick random tree
+                if (tree==TREE_UNFIXED)
+                    if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                    else t = 0;
+                else t = tree;
+                
+                // is the tree swappable?      
+                GPInitializer initializer = ((GPInitializer)state.initializer);
+                int numswap = numSwappableNodes(initializer, j.trees[t].child,0);
+                if (numswap==0) continue; // uh oh, try again
+                
+                // swap the node, or if we're unsuccessful, just leave it alone
+                pickSwappableNode(initializer, j.trees[t].child,state.random[thread].nextInt(numswap));
+                
+                // node is now in swappableNode, swap it
+                swapSomething(swappableNode,state,thread);
+
+                j.evaluated = false;
+                break;
+                }
+
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/README	(revision 6152)
@@ -0,0 +1,54 @@
+This directory contains various breeding pipelines made for GP trees.  The
+more common ones are historically elsewhere:  CrossoverPipeline and
+MutationPipeline are in the 'koza' directory, and the more general 
+ReproductionPipeline and MultiBreedingPipelien are in the 'ec/breed' directory.
+
+Special-purpose pipelines in this directory:
+
+
+
+ec.gp.breed.InternalCrossoverPipeline
+
+Two points are selected within the same individual, such that neither is a
+subtree of the other.  The points are then crossed over.
+
+
+ec.gp.breed.MutateDemotePipeline
+
+A random non-leaf GPNode is created. A tree is removed from the individual and 
+replaced with the GPNode.  The tree then is reattached as a child to that
+GPNode.  The remaining child slots of the GPNode, if any, are filled with
+randomly generated trees (using a GPNodeBuilder).
+
+
+ec.gp.breed.MutatePromotePipeline
+
+A tree is replaced with one of its children subtrees.
+
+
+ec.gp.breed.MutateSwapPipeline
+
+Two children subtrees of a random GPNode are swapped.
+
+
+ec.gp.breed.MutateOneNodePipeline
+
+A single ERC node in the tree is mutated.
+
+
+ec.gp.breed.MutateAllNodesPipeline
+
+All ERCs in the tree are mutated.
+
+
+ec.gp.breed.RehangPipeline
+
+A nonleaf GPNode in the tree is chosen as the new root.  Call it N.  We begin 
+by removing a random child subtree from that node (call it T).  The node is 
+then placed at he root.  The node's former parent is placed in the position 
+formerly occupied by T.  The parent's parent is placed in the position 
+formerly occupied by N.  The parent's parent's parent is placed in the
+position formerly occupied by N's parent.  And so on, until all parents are
+exhausted.  The remaining open slot is then filled with T.  This technique
+is highly randomizing and really only useful for odd tests here or there.
+It also cannot be used with a typed GP problem.
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/RehangPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/RehangPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/RehangPipeline.java	(revision 6152)
@@ -0,0 +1,304 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.breed;
+import ec.*;
+import ec.util.*;
+import ec.gp.*; 
+
+/* 
+ * RehangPipeline.java
+ * 
+ * Created: Wed Dec 15 21:41:30 1999
+ * By: Sean Luke
+ */
+
+/**
+ * RehangPipeline picks a nonterminal node other than the root
+ * and "rehangs" it as
+ * a new root. Imagine if the tree were nodes connected with string.
+ * Grab the new node and pick it up, letting the other nodes hang
+ * underneath it as a new "root".  That's in effect what you're doing.
+ *
+ * <p><b>Important Note</b>: Because it must be free of any constraints
+ * by nature, RehangPipeline does not work with strong typing.  You must
+ * not have more than one type defined in order to use RehangPipeline.  
+ *
+ * <p>RehangPipeline picks a random tree, then picks randomly from
+ * all the nonterminals in the tree other than the root, and rehangs the
+ * chosen nonterminal 
+ * as the new root. If its chosen tree has no nonterminals, it repeats
+ * the choose-tree process.  If after <i>tries</i> times
+ * it has failed to find a tree with nonterminals (other than the root),
+ * it gives up and simply
+ * copies the individual.  As you might guess, determining if a tree has
+ * nonterminals is very fast, so <i>tries</i> can be pretty large with
+ * little to no detriment to evolution speed.
+ *
+ * <p>"Rehanging" is complicated to describe.  First, you pick a random
+ * child of your chosen nonterminal <i>n</i>, 
+ * and remove this subtree from the tree.
+ * Call this subtree <i>T</i>.  Next, you set the nonterminal as a new root; its
+ * former parent <i>p</i> now fills the slot left behind by the missing subtree.
+ * The <i>p</i>'s former parent <i>q</i> now fills the slot left behind by 
+ * <i>n</i>.  <i>q</i>'s former parent <i>r</i> now fills the slot left behind
+ * by <i>p</i>, and so on.  This proceeds all the way up to the old root, which
+ * will be left with one empty slot (where its former child was that is now its new
+ * parent).  This slot is then filled with <i>T</i>
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the source produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.rehang
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class RehangPipeline extends GPBreedingPipeline
+    {
+    public static final String P_REHANG = "rehang";
+    public static final String P_NUM_TRIES = "tries";
+    public static final int NUM_SOURCES = 1;
+   
+    /** The number of times the pipeline tries to find a tree with a
+        nonterminal before giving up and just copying the individual. */
+    int numTries;
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_REHANG); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES),1);
+        if (numTries == 0)
+            state.output.fatal("RehangPipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+
+        if (((GPInitializer)state.initializer).numAtomicTypes + ((GPInitializer)state.initializer).numSetTypes > 1)
+            state.output.fatal("RehangPipeline only works when there is only one type (the system is typeless", base,def);
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+
+    private int numRehangableNodes(final GPNode root, int soFar)
+        {
+        // we don't include the tree root
+        for(int x=0;x<root.children.length;x++) 
+            soFar = _numRehangableNodes(root.children[x],soFar);
+        return soFar;   
+        }
+
+    private int _numRehangableNodes(final GPNode root, int soFar)
+        {
+        if (root.children.length>0) soFar++;  // rehangable
+        for(int x=0;x<root.children.length;x++) 
+            soFar = _numRehangableNodes(root.children[x],soFar);
+        return soFar;
+        }
+
+
+    private GPNode rehangableNode;
+
+    private int pickRehangableNode(final GPNode root, int num)
+        {
+        // we don't include the tree root
+        for(int x=0;x<root.children.length;x++)
+            {
+            num = _pickRehangableNode(root.children[x],num);
+            if (num==-1) break;  // someone found it
+            }   
+        return num;     
+        }
+
+    // sticks the node in 
+    private int _pickRehangableNode(final GPNode root, int num)
+        {
+        if (root.children.length>0)  // rehangable
+            {
+            num--;
+            if (num==-1)  // found it
+                {
+                rehangableNode = root;
+                return num;
+                }
+            }
+        for(int x=0;x<root.children.length;x++)
+            {
+            num = _pickRehangableNode(root.children[x],num);
+            if (num==-1) break;  // someone found it
+            }
+        return num;     
+        }
+    
+
+    private void rehang(final EvolutionState state, final int thread,
+        GPNode pivot, final GPNode root)
+        {
+        // pivot must not be root
+        if (pivot==root) // uh oh
+            throw new InternalError("Oops, pivot==root in ec.gp.breed.Rehang.rehang(...)");
+
+        // snip off a random child from the pivot
+        byte spot = (byte)(state.random[thread].nextInt(pivot.children.length));
+        byte newSpot; byte tmpSpot;
+        GPNode cut = pivot.children[spot];
+
+        // rehang pivot as new root and set it up
+        GPNode newPivot = (GPNode)(pivot.parent);       
+        ((GPTree)root.parent).child = pivot;
+        pivot.parent = root.parent;
+        newSpot = pivot.argposition;
+        pivot.argposition = 0;
+        GPNode oldPivot = pivot;
+        pivot = newPivot;
+
+        // rehang the intermediate nodes
+        while(pivot!=root)
+            {
+            newPivot = (GPNode)(pivot.parent);
+            
+            pivot.parent = oldPivot;
+            oldPivot.children[spot] = pivot;        
+            tmpSpot = pivot.argposition;
+            pivot.argposition = spot;
+            spot = newSpot;
+            newSpot = tmpSpot;
+            
+            oldPivot = pivot;
+            pivot = newPivot;
+            }
+
+        // rehang the root and set the cut
+        pivot.parent = oldPivot;
+        oldPivot.children[spot] = pivot;
+        pivot.argposition = spot;
+        cut.parent = pivot;
+        cut.argposition = newSpot;
+        pivot.children[newSpot] = cut;
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n= sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+
+        // now let's rehang 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+            
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("RehangPipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+
+            GPIndividual j;
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                }
+            else // need to copy it
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                    j.trees[x].owner = j;
+                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                    j.trees[x].child.parent = j.trees[x];
+                    j.trees[x].child.argposition = 0;
+                    }
+                }
+            
+            
+            for (int x=0;x<numTries;x++)
+                {
+                int t;
+                // pick random tree
+                if (tree==TREE_UNFIXED)
+                    if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                    else t = 0;
+                else t = tree;
+                
+                // is the tree rehangable?              
+                if (j.trees[t].child.children.length==0) continue; // uh oh, try again
+                boolean rehangable = false;
+                for(int y=0;y<j.trees[t].child.children.length;y++)
+                    if (j.trees[t].child.children[y].children.length>0) // nonterminal
+                        { rehangable = true; break; }
+                if (!rehangable) continue;  // the root's children are all terminals
+
+                int numrehang = numRehangableNodes(j.trees[t].child,0);
+                pickRehangableNode(j.trees[t].child,
+                    state.random[thread].nextInt(numrehang));
+                
+                rehang(state,thread,rehangableNode,j.trees[t].child);
+
+                j.evaluated = false;
+                }
+
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/breed.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/breed.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/breed.params	(revision 6152)
@@ -0,0 +1,29 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+
+#
+# Some basic default values for various breeding stuff
+#
+
+
+gp.breed.internal-xover.tries = 5
+gp.breed.internal-xover.maxdepth = 17
+gp.breed.internal-xover.ns.0 = ec.gp.koza.KozaNodeSelector
+gp.breed.internal-xover.ns.1 = same
+
+gp.breed.rehang.tries = 1
+
+gp.breed.mutate-swap.tries = 1
+
+gp.breed.mutate-all-nodes.ns.0 = ec.gp.koza.KozaNodeSelector
+
+gp.breed.mutate-one-node.ns.0 = ec.gp.koza.KozaNodeSelector
+
+gp.breed.mutate-demote.tries = 1
+gp.breed.mutate-demote.maxdepth = 17
+
+gp.breed.mutate-promote.tries = 1
+
+gp.breed.mutate-erc.ns.0 = ec.gp.koza.KozaNodeSelector
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/GPBuildDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/GPBuildDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/GPBuildDefaults.java	(revision 6152)
@@ -0,0 +1,34 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+import ec.util.Parameter;
+import ec.gp.*;
+import ec.*;
+
+/* 
+ * GPBuildDefaults.java
+ * 
+ * Created: Thu Jan 20 17:22:22 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GPBuildDefaults implements DefaultsForm
+    {
+    public static final String P_BUILD = "build";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return GPDefaults.base().push(P_BUILD);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC1.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC1.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC1.java	(revision 6152)
@@ -0,0 +1,193 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * PTC1.java
+ * 
+ * Created: Tue Jan 25 21:36:02 2000
+ * By: Sean Luke
+ */
+
+/**
+ * PTC1 implements the "Strongly-typed Probabilistic Tree Creation 1 (PTC1)" algorithm described in 
+ *
+ * <p>Luke, Sean. 2000. <i>Issues in Scaling Genetic Programming: Breeding Strategies, Tree Generation, and Code Bloat.</i> Ph.D. Dissertation, Department of Computer Science, University of Maryland, College Park, Maryland. 
+ *
+ * <p> ...and also in
+ *
+ * <p>Luke, Sean. 2000. Two fast tree-creation algorithms for genetic programming. In <i>IEEE Transactions on Evolutionary Computation</i> 4:3 (September 2000), 274-283. IEEE. 
+ *
+ * <p> Both can be found at <a href="http://www.cs.gmu.edu/~sean/papers/">http://www.cs.gmu.edu/~sean/papers/</a>
+ * 
+ * <p> PTC1 requires that your function set to implement PTCFunctionSetForm.  The
+ * provided function set, PTCFunctionSet, does exactly this.
+ *
+ * <p>The Strongly-typed PTC1 algorithm is a derivative of the GROW algorithm
+ * used in ec.gp.koza.GrowBuilder.  The primary differences are:
+ * 
+ <ul>
+ <li> PTC1 guarantees that trees generated will have an <i>expected</i> (mean) tree size, provided by the user.  There is no guarantee on variance.  This is different from GROW, which doesn't give any user control at all.
+ <li> PTC1 does not have a min-depth value.  In essence, PTC1's min-depth value is always set to 1.
+ <li> PTC1's max-depth value should really only be used to enforce a large memory restriction.  Unlike GROW, where it's used to keep GROW from going nuts.
+ <li> PTC1 has provisions for picking nonterminals with various probabilities over other nonterminals (and likewise for terminals).  To use this, tweak the PTCFunctionSetForm object.
+ </ul>
+ *
+ * PTC1 assumes that the requested size passed to newRootedTree(...) is the <i>expected</i> size.   If the value is NOSIZEGIVEN, then PTC1 will use the expected size defined by the <tt>expected-size</tt> parameter.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>expected-size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>default expected tree size</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>maximum allowable tree depth (usually a big value)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.build.ptc1
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class PTC1 extends GPNodeBuilder 
+    {
+    public static final String P_PTC1 = "ptc1";
+    public static final String P_EXPECTED = "expected-size";
+    public static final String P_MAXDEPTH = "max-depth";
+
+    /** The largest maximum tree depth PTC1 can specify -- should be big. */
+    public int maxDepth;
+
+    /** The default expected tree size for PTC1 */
+    public int expectedSize;
+
+    public Parameter defaultBase()
+        {
+        return GPBuildDefaults.base().push(P_PTC1);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        expectedSize = state.parameters.getInt(base.push(P_EXPECTED),
+            def.push(P_EXPECTED),1);
+        if (expectedSize < 1)
+            state.output.fatal("Default expected size must be >= 1",
+                base.push(P_EXPECTED),
+                def.push(P_EXPECTED));
+
+        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),
+            def.push(P_MAXDEPTH),1);
+        if (maxDepth < 1)
+            state.output.fatal("Maximum depth must be >= 1",
+                base.push(P_MAXDEPTH),
+                def.push(P_MAXDEPTH));
+        
+        }
+
+
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        if (!(set instanceof PTCFunctionSetForm))
+            state.output.fatal("Set " + set.name + " is not of the form ec.gp.build.PTCFunctionSetForm, and so cannot be used with PTC Nodebuilders.");
+
+        // build the tree
+        if (requestedSize == NOSIZEGIVEN)  // use the default
+            {
+            return ptc1(state,0,type,thread,parent,argposition,
+                set,(PTCFunctionSetForm)set,
+                ((PTCFunctionSetForm)set).nonterminalSelectionProbabilities(expectedSize));
+            }
+        if (requestedSize < 1)
+            state.output.fatal("etc.gp.build.PTC1 was requested to build a tree, but a requested size was given that is < 1.");
+        return ptc1(state,0,type,thread,parent,argposition,
+            set,(PTCFunctionSetForm)set,
+            ((PTCFunctionSetForm)set).nonterminalSelectionProbabilities(requestedSize));
+        }
+
+    
+
+    /** A private function which recursively returns a GROW tree to newRootedTree(...) */
+    private GPNode ptc1(final EvolutionState state,
+        final int current,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final int argposition,
+        final GPFunctionSet set,
+        final PTCFunctionSetForm pset, // same as set
+        final float[] nonterminalSelectionProbabilities) 
+        
+        {
+        // ptc1 can mess up if there are no available terminals for a given type.  If this occurs,
+        // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
+        // and pick a nonterminal, violating the PTC1 size and depth contracts.  This can lead to pathological situations
+        // where the system will continue to go on and on unable to stop because it can't pick a terminal,
+        // resulting in running out of memory or some such.  But there are cases where we'd want to let
+        // this work itself out.
+        boolean triedTerminals = false;
+                
+        int t = type.type;
+        GPNode[] terminals = set.terminals[t];
+        GPNode[] nonterminals = set.nonterminals[t];
+        GPNode[] nodes = set.nodes[t];          
+
+        if (nodes.length == 0)
+            errorAboutNoNodeWithType(type, state);   // total failure
+
+        if ((  (current+1 >= maxDepth) ||                                                    // Now pick if we're at max depth
+                !(state.random[thread].nextBoolean(nonterminalSelectionProbabilities[t])) ||  // OR if we're below p_y
+                warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&         // OR if there are NO nonterminals!
+            (triedTerminals = true) &&                                                       // [first set triedTerminals]
+            terminals.length != 0)                                                           // AND if there are available terminals
+            {
+            GPNode n = (GPNode)
+                terminals[RandomChoice.pickFromDistribution(
+                    pset.terminalProbabilities(t),
+                    state.random[thread].nextFloat())].lightClone();
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+            return n;
+            }
+        else  // above p_y, pick a nonterminal by q_ny probabilities
+            {
+            if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);        // we tried terminals and we're here because there were none!
+
+            GPNode n = (GPNode)
+                nonterminals[RandomChoice.pickFromDistribution(
+                    pset.nonterminalProbabilities(t),
+                    state.random[thread].nextFloat())].lightClone();
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+
+            // Populate the node...
+            GPType[] childtypes = n.constraints(((GPInitializer)state.initializer)).childtypes;
+            for(int x=0;x<childtypes.length;x++)
+                n.children[x] = ptc1(state,current+1,childtypes[x],thread,n,x,set,pset,nonterminalSelectionProbabilities);
+            return n;       
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC2.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC2.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC2.java	(revision 6152)
@@ -0,0 +1,293 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * PTC2.java
+ * 
+ * Created: Tue Jan 25 21:36:02 2000
+ * By: Sean Luke
+ */
+
+/**
+ * PTC2 implements the "Strongly-typed Probabilistic Tree Creation 2 (PTC2)" algorithm described in 
+ *
+ * <p>Luke, Sean. 2000. <i>Issues in Scaling Genetic Programming: Breeding Strategies, Tree Generation, and Code Bloat.</i> Ph.D. Dissertation, Department of Computer Science, University of Maryland, College Park, Maryland. 
+ *
+ * <p> ...and also in
+ *
+ * <p>Luke, Sean. 2000. Two fast tree-creation algorithms for genetic programming. In <i>IEEE Transactions on Evolutionary Computation</i> 4:3 (September 2000), 274-283. IEEE. 
+ *
+ * <p> Both can be found at <a href="http://www.cs.gmu.edu/~sean/papers/">http://www.cs.gmu.edu/~sean/papers/</a>
+ * 
+ * <p> PTC2 requires that your function set to implement PTCFunctionSetForm.  The
+ * provided function set, PTCFunctionSet, does exactly this.
+ *
+ * <p>The Strongly-typed PTC2 algorithm roughly works as follows: 
+ * the user provides a requested tree size, and PTC2 attempts to build
+ * a tree of that size or that size plus the maximum arity of a nonterminal
+ * in the function set.  PTC2 works roughly like this:
+ *
+ <ol><li>If the tree size requested is 1, pick a random terminal and return it.
+ <li> Else pick a random nonterminal as the root and put each of its unfilled child positions into the queue <i>Q</i>.
+ <li> Loop until the size of <i>Q</i>, plus the size of the nodes in the tree so far, equals or exceeds the requested tree size:
+ <ol><li>Remove a random position from <i>Q</i>.
+ <li>Fill the position with a random nonterminal <i>n</i>.
+ <li>Put each of </i>n's</i> unfilled child positions into <i>Q</i>.
+ </ol>
+ <li>For each position in <i>Q</i>, fill the position with a randomly-chosen terminal.
+ </ol>
+ *
+ * <p> Generally speaking, PTC2 picks a random position in the horizon of the tree (unfiled child node positions), fills it with a nonterminal, thus extending the horizon, and repeats this until the number of nodes (nonterminals) in the tree, plus the number of unfilled node positions, is >= the requested tree size.  Then the remaining horizon is filled with terminals.
+ *
+ * <p> The user-provided requested tree size is either provided directly to the PTC2 algorithm, or if the size is NOSIZEGIVEN, then PTC2 will pick one at random from the GPNodeBuilder probability distribution system (using either max-depth and min-depth, or using num-sizes).
+ *
+ * <p> PTC2 also has provisions for picking nonterminals with a certain probability over other nonterminals of the same return type (and terminals over other terminals likewise), hence its name.  To change the probability of picking various terminals or nonterminals, you modify your PTCFunctionSetForm function set.
+ *
+ * <p>PTC2 further has a maximum depth, which you should set to some fairly big value.  If your maximum depth is small enough that PTC2 often creates trees which bump up against it, then PTC2 will only generate terminals at that depth position.  If the depth is *really* small, it's possible that this means PTC2 will generate trees smaller than you had requested.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>maximum allowable tree depth (usually a big value)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.breed.ptc2
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class PTC2 extends GPNodeBuilder 
+    {
+    public static final String P_PTC2 = "ptc2";
+    public static final String P_MAXDEPTH = "max-depth";
+
+    /** The largest maximum tree depth GROW can specify -- should be big. */
+    public int maxDepth;
+    
+    public Parameter defaultBase()
+        {
+        return GPBuildDefaults.base().push(P_PTC2);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        // we use size distributions -- did the user specify any?
+        if (!canPick())
+            state.output.fatal("PTC2 needs a distribution of tree sizes to pick from.  You can do this by either setting a distribution (with " + P_NUMSIZES + ") or with "
+                + P_MINSIZE + " and " + P_MAXSIZE + ".", base, def);
+
+        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),
+            def.push(P_MAXDEPTH),1);
+        if (maxDepth < 1)
+            state.output.fatal("Maximum depth must be >= 1",
+                base.push(P_MAXDEPTH),
+                def.push(P_MAXDEPTH));
+        }
+
+    public final static int MIN_QUEUE_SIZE = 32;
+    
+    // these are all initialized in enqueue
+    GPNode[] s_node;
+    int[] s_argpos;
+    int[] s_depth;
+    int s_size;
+
+    private void enqueue(final GPNode n, final int argpos, final int depth)
+        {
+        if (s_node==null) 
+            {
+            s_node = new GPNode[MIN_QUEUE_SIZE];
+            s_argpos = new int[MIN_QUEUE_SIZE];
+            s_depth = new int[MIN_QUEUE_SIZE];
+            s_size = 0;
+            }
+        else if (s_size==s_node.length) // need to double them
+            {
+            GPNode[] new_s_node = new GPNode[s_size*2];
+            System.arraycopy(s_node,0,new_s_node,0,s_size);
+            s_node = new_s_node;
+            int[] new_s_argpos = new int[s_size*2];
+            System.arraycopy(s_argpos,0,new_s_argpos,0,s_size);
+            s_argpos = new_s_argpos;
+            int[] new_s_depth = new int[s_size*2];
+            System.arraycopy(s_depth,0,new_s_depth,0,s_size);
+            s_depth = new_s_depth;
+            }
+        
+        // okay, let's boogie!
+        s_node[s_size] = n;
+        s_argpos[s_size] = argpos;
+        s_depth[s_size] = depth;
+        s_size++;
+        }
+
+    GPNode dequeue_node;
+    int dequeue_argpos;
+    int dequeue_depth;
+
+    // stashes in dequeue_*
+    private void randomDequeue(final EvolutionState state, final int thread)
+        {
+        int r = state.random[thread].nextInt(s_size);
+        s_size -= 1;
+        // put items r into spot dequeue_*
+        dequeue_node = s_node[r];
+        dequeue_argpos = s_argpos[r];
+        dequeue_depth = s_depth[r];
+        // put items s_size into spot r
+        s_node[r] = s_node[s_size];
+        s_argpos[r] = s_argpos[s_size];
+        s_depth[r] = s_depth[s_size];
+        }
+
+
+    public GPNode newRootedTree(final EvolutionState state,
+        GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        int requestedSize)
+        {
+        // ptc2 can mess up if there are no available terminals for a given type.  If this occurs,
+        // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
+        // and pick a nonterminal, violating the ptc2 size and depth contracts.  This can lead to pathological situations
+        // where the system will continue to go on and on unable to stop because it can't pick a terminal,
+        // resulting in running out of memory or some such.  But there are cases where we'd want to let
+        // this work itself out.
+        boolean triedTerminals = false;
+
+        if (!(set instanceof PTCFunctionSetForm))
+            state.output.fatal("Set " + set.name + " is not of the class ec.gp.build.PTCFunctionSetForm, and so cannot be used with PTC Nodebuilders.");
+
+        PTCFunctionSetForm pset = (PTCFunctionSetForm)set;
+
+        // pick a size from the distribution
+        if (requestedSize==NOSIZEGIVEN)
+            requestedSize = 
+                pickSize(state,thread);
+
+        GPNode root;
+
+        int t = type.type;
+        GPNode[] terminals = set.terminals[t];
+        GPNode[] nonterminals = set.nonterminals[t];
+        GPNode[] nodes = set.nodes[t];          
+
+        if (nodes.length == 0)
+            errorAboutNoNodeWithType(type, state);   // total failure
+
+
+
+        // return a terminal
+        if ((   requestedSize==1 ||                                                          // Now pick a terminal if our size is 1
+                warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&         // OR if there are NO nonterminals!
+            (triedTerminals = true) &&                                                       // [first set triedTerminals]
+            terminals.length != 0)                                                           // AND if there are available terminals
+            {
+            root = (GPNode)
+                terminals[RandomChoice.pickFromDistribution(
+                    pset.terminalProbabilities(t),
+                    state.random[thread].nextFloat())].lightClone();
+            root.resetNode(state,thread);  // give ERCs a chance to randomize
+            root.argposition = (byte)argposition;
+            root.parent = parent;
+            }
+        else   // return a nonterminal-rooted tree
+            {
+            if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);        // we tried terminals and we're here because there were none!
+
+            // pick a nonterminal
+            root = (GPNode)
+                nonterminals[RandomChoice.pickFromDistribution(
+                    pset.nonterminalProbabilities(t),
+                    state.random[thread].nextFloat())].lightClone();
+            root.resetNode(state,thread);  // give ERCs a chance to randomize
+            root.argposition = (byte)argposition;
+            root.parent = parent;
+
+            // set the depth, size, and enqueuing, and reset the random dequeue
+            
+            s_size=0;  // pretty critical!
+            int s = 1;
+            GPInitializer initializer = ((GPInitializer)state.initializer);
+            GPType[] childtypes = root.constraints(initializer).childtypes;
+            for(int x=0;x<childtypes.length;x++)
+                enqueue(root,x,1);  /* depth 1 */
+            
+                        
+                        
+                        
+            while(s_size>0)
+                {
+                triedTerminals = false;
+                randomDequeue(state,thread);
+                type = dequeue_node.constraints(initializer).childtypes[dequeue_argpos];
+                
+                int y = type.type;
+                terminals = set.terminals[y];
+                nonterminals = set.nonterminals[y];
+                nodes = set.nodes[y];           
+
+                if (nodes.length == 0)
+                    errorAboutNoNodeWithType(type, state);   // total failure
+
+                // pick a terminal 
+                if ((   s_size + s >= requestedSize ||                                        // if we need no more nonterminal nodes
+                        dequeue_depth==maxDepth ||                                            // OR if we're at max depth and must pick a terminal
+                        warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&  // OR if there are NO nonterminals!
+                    (triedTerminals = true) &&                                                // [first set triedTerminals]
+                    terminals.length != 0)                                                    // AND if there are available terminals
+                    {
+                    GPNode n = (GPNode)
+                        terminals[RandomChoice.pickFromDistribution(
+                            pset.terminalProbabilities(y),
+                            state.random[thread].nextFloat())].lightClone();
+                    dequeue_node.children[dequeue_argpos] = n;
+                    n.resetNode(state,thread);  // give ERCs a chance to randomize
+                    n.argposition = (byte)dequeue_argpos;
+                    n.parent = dequeue_node;
+                    }
+                
+                // pick a nonterminal and enqueue its children
+                else
+                    {
+                    if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);       // we tried terminals and we're here because there were none!
+                                                                                        
+                    GPNode n = (GPNode)
+                        nonterminals[RandomChoice.pickFromDistribution(
+                            pset.nonterminalProbabilities(y),
+                            state.random[thread].nextFloat())].lightClone();
+                    dequeue_node.children[dequeue_argpos] = n;
+                    n.resetNode(state,thread);  // give ERCs a chance to randomize
+                    n.argposition = (byte)dequeue_argpos;
+                    n.parent = dequeue_node;
+                    
+                    childtypes = n.constraints(initializer).childtypes;
+                    for(int x=0;x<childtypes.length;x++)
+                        enqueue(n,x,dequeue_depth + 1);
+                    }
+                s++;
+                }
+            }
+
+        return root;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTCFunctionSet.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTCFunctionSet.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTCFunctionSet.java	(revision 6152)
@@ -0,0 +1,148 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * PTCFunctionSet.java
+ * 
+ * Created: Wed Jan 26 21:10:59 2000
+ * By: Sean Luke
+ */
+
+/**
+ * PTCFunctionSet is a GPFunctionSet which adheres to PTCFunctionSetForm, and thus
+ * can be used with the PTC1 and PTC2 methods.  Terminal and nonterminal probabilities
+ * for nodes used in this function set are determined by the <tt>prob</tt> parameter
+ * for the nodes' GPNodeConstraints object.  That's not the greatest solution,
+ * because it could require making a lot of different GPNodeConstraints, customized for each
+ * node, but it's the best I can do for now.
+ *
+ * The nonterminalSelectionProbabilities() method computes nonterminal selection
+ * probability using the probabilities above, per type, for the size requested.
+ * If the size is small enough (smaller than CACHE_SIZE), then the result is
+ * memoized so it doesn't need to be computed again next time.
+ * 
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class PTCFunctionSet extends GPFunctionSet implements PTCFunctionSetForm
+    {
+    /** terminal probabilities[type][thenodes], in organized form */
+    public float q_ty[][];
+    /** nonterminal probabilities[type][thenodes], in organized form */
+    public float q_ny[][];
+
+    public static final int CACHE_SIZE = 1024;
+    /** cache of nonterminal selection probabilities -- dense array 
+        [size-1][type].  If any items are null, they're not in the dense cache. */
+    public float p_y[][];
+
+    public float[] terminalProbabilities(final int type)
+        { return q_ty[type]; }
+
+    public float[] nonterminalProbabilities(final int type)
+        { return q_ny[type]; }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        // load our probabilities here.
+        
+        q_ny = new float[nonterminals.length][];
+        q_ty = new float[terminals.length][];
+        
+        boolean allOnes = true;
+        boolean noOnes = true;
+        boolean allZeros = true;
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        for(int type=0;type<nonterminals.length;type++)
+            {
+            q_ny[type] = new float[nonterminals[type].length];
+            for(int x=0;x<nonterminals[type].length;x++)
+                {
+                q_ny[type][x] = nonterminals[type][x].constraints(initializer).probabilityOfSelection;
+                if (q_ny[type][x] != 0.0f) allZeros = false;
+                if (q_ny[type][x] == 1.0f) noOnes = false;
+                else allOnes = false;
+                }
+            }
+            
+        if (allZeros)
+            state.output.warning("In this function set, the probabilities of all nonterminal functions have a 0.0 selection probability -- this will cause them all to be selected uniformly.  That could be an error.", base);
+        allZeros = false;
+
+        for(int type=0;type<terminals.length;type++)
+            {
+            q_ty[type] = new float[terminals[type].length];
+            for(int x=0;x<terminals[type].length;x++)
+                {
+                q_ty[type][x] = terminals[type][x].constraints(initializer).probabilityOfSelection;
+                if (q_ty[type][x] != 0.0f) allZeros = false;
+                if (q_ty[type][x] == 1.0f) noOnes = false;
+                else allOnes = false;
+                }
+            }
+
+        if (allZeros)
+            state.output.warning("In this function set, the probabilities of all terminal functions have a 0.0 selection probability -- this will cause them all to be selected uniformly.  That could be an error.", base);
+
+        if (!allOnes && !noOnes)
+            state.output.warning("In this function set, there are some functions with a selection probability of 1.0, but not all of them.  That could be an error.",base);
+        
+        // set up our node probabilities.  Allow all zeros.
+        for(int x=0;x<q_ty.length;x++)
+            {
+            if (q_ty[x].length == 0) state.output.warning("Function Set " + name + " has no terminals for type number " + x + ".  This may cause problems for you.");
+            else RandomChoice.organizeDistribution(q_ty[x], true);
+            if (q_ny[x].length == 0) state.output.warning("Function Set " + name + " has no nonterminals for type number " + x + ".  This may cause problems for you.");
+            else RandomChoice.organizeDistribution(q_ny[x], true);
+            }
+
+        // set up cache
+        p_y = new float[CACHE_SIZE][];
+        }
+    
+    public float[] nonterminalSelectionProbabilities(final int expectedTreeSize)
+        {
+        // check cache first
+        if (expectedTreeSize<CACHE_SIZE)
+            {
+            if (p_y[expectedTreeSize-1]!=null) return p_y[expectedTreeSize-1];
+            else return p_y[expectedTreeSize-1] = 
+                     computeNonterminalSelectionProbabilities(expectedTreeSize);
+            }
+        else
+            // we'll have to compute it
+            return computeNonterminalSelectionProbabilities(expectedTreeSize);
+        }
+
+    
+    public float[] computeNonterminalSelectionProbabilities(final int expectedTreeSize)
+        {
+        float[] p = new float[q_ny.length];
+
+        // for each type...
+        for(int x=0;x<q_ny.length;x++)
+            {
+            double count=0;
+            // gather branching factor * prob for each nonterminal
+            for(int y=0;y<q_ny[x].length;y++)
+                count += (y==0 ? q_ny[x][y] : q_ny[x][y]-q_ny[x][y-1]) // it's organized
+                    * nonterminals[x][y].children.length;
+
+            p[x] = (float)((1.0-(1.0/expectedTreeSize))/count);
+            }
+        return p;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTCFunctionSetForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTCFunctionSetForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTCFunctionSetForm.java	(revision 6152)
@@ -0,0 +1,46 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+
+/* 
+ * PTCFunctionSetForm.java
+ * 
+ * Created: Mon Oct 16 17:21:44 2000
+ * By: Sean Luke
+ */
+
+/**
+ * PTCFunctionSetForm defines the methods that the PTC1 and PTC2 tree-creation
+ * algorithms require of function sets.  Your GPFunctionSet must adhere to
+ * this form in order to be used by these algorithms; the PTCFunctionSet
+ * class is provided to simplify matters for you (it's a direct subclass of
+ * GPFunctionSet which adheres to this form).
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface PTCFunctionSetForm  
+    {
+    /** Returns an organized distribution (see ec.util.RandomChoice) of likelihoods
+        that various terminals in the function set will be chosen over other terminals
+        with the same return type.  The ordering of the array is the same as
+        the terminals[type][...] array in GPFunctionSet.  */
+    public float[] terminalProbabilities(final int type);
+
+    /** Returns an organized distribution (see ec.util.RandomChoice) of likelihoods
+        that various nonterminals in the function set will be chosen over other nonterminals
+        with the same return type. The ordering of the array is the same as
+        the nonterminals[type][...] array in GPFunctionSet. */
+    public float[] nonterminalProbabilities(final int type);
+    
+    /** Returns an array (by return type) of the probability that PTC1 must pick a
+        nonterminal over a terminal in order to guarantee the expectedTreeSize.
+        Only used by PTC1, not by PTC2. */
+    public float[] nonterminalSelectionProbabilities(final int expectedTreeSize);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/README	(revision 6152)
@@ -0,0 +1,47 @@
+This directory contains GPNodeBuilder subclasses other than the most common
+ones (GPHalfBuilder, GPGrowBuilder, GPFullBuilder) found in the 'koza'
+directory.  A good description of most of these algorithms may be found in
+"A Survey and Comparison of Tree Generation Algorithms" by Sean Luke and
+Liviu Panait, GECCO 2001.  Google for it.
+
+
+
+ec.gp.build.PTC1
+
+Implements the PTC1 algorithm, a variation of the GROW algorithm which
+guarantees that generated trees will have a certain mean size.
+
+
+ec.gp.build.PTC2
+
+Implements the PTC2 algorithm, which guarantees that generated trees will
+be "more or less" a certain desired size.
+
+
+ec.gp.build.PTCFunctionSet
+
+A subclass of GPFunctionSet with additional probabilistic arguments required
+by the PTC1 and PTC2 algorithms.
+
+
+ec.gp.RandomBranch
+
+Implements the RANDOMBRANCH algorithm (Chellapilla), which creates roughly
+evenly distributed algorithms 
+
+
+ec.gp.RandTree
+
+Implements the RandTree algorithm (Iba), which picks trees uniformly according
+to structure, then labels the tree with appropriate nodes.  Note that we
+believe this code may be flakey and do not recommend it.
+
+
+ec.gp.Uniform
+
+Implements an algorithm from (Bohm and Geyer-Schulz) which draws trees 
+entirely uniformly.  The version in ECJ aso considers set and atomic types.
+
+
+If you're struggling to pick a more versatile tree generator than the Koza
+standard ones, we strongly suggest PTC2.
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/RandTree.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/RandTree.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/RandTree.java	(revision 6152)
@@ -0,0 +1,424 @@
+/*
+  Copyright 2006 by Alexander Chircop
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ *  RandTree as described by Hitoshi Iba
+ *  Author: Alexander Chircop
+ *  Date:   28th Nov 2000
+ */
+ 
+package ec.gp.build;
+import ec.gp.*;
+import ec.*;
+import ec.util.*;
+import java.util.*;
+
+public class RandTree extends GPNodeBuilder
+    {
+    public static final String P_RANDOMBRANCH = "randtree";
+    int[] arities;
+    boolean aritySetupDone=false;
+
+    LinkedList permutations;
+
+    private class ArityObject extends Object
+        {
+        public int arity;
+        public ArityObject(int a) { arity=a; }
+        }
+
+    public Parameter defaultBase()
+        {
+        return GPBuildDefaults.base().push(P_RANDOMBRANCH);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        // we use size distributions -- did the user specify any?
+        if (!canPick())
+            state.output.fatal("RandTree requires some kind of size distribution set, either with " + P_MINSIZE + "/" + P_MAXSIZE + ", or with " + P_NUMSIZES + ".",
+                base, defaultBase());
+        }
+
+    // Added method to enhance linked list functionality with ArityObject
+    private boolean contains(LinkedList initArities,int a)
+        {
+        boolean truth=false;
+        int counter=0;
+        ArityObject b;
+
+        if (initArities.size()!=0)
+            while ((counter<initArities.size()) && (!truth))
+                {
+                b=(ArityObject)initArities.get(counter);
+                if (b.arity==a) {truth=true;}
+                counter++;
+                }
+        return truth;
+        }
+
+    private void remove(LinkedList initArities,int a)
+        {
+        int counter=0;
+        boolean removed=false;
+        while((counter<initArities.size()) && (!removed))
+            {
+            ArityObject b=(ArityObject)initArities.get(counter);
+            if (b.arity==a)
+                {
+                initArities.remove(counter);
+                removed=true;
+                }
+            counter++;
+            }
+        }
+
+    public void setupArities(final EvolutionState state,final GPFunctionSet set)
+        {
+        int noOfArities=0,current=0,marker=0,counter=0,a;
+        LinkedList initArities=new LinkedList();
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        // count available arities and place on linked list
+        while(current<set.nodes[0].length)
+            {
+                {
+                a=set.nodes[0][current].constraints(initializer).childtypes.length;
+                if((!contains(initArities,a)) && (a!=0))
+                    {
+                    initArities.add(new ArityObject(a));
+                    noOfArities++;
+                    }
+                }
+            current++;
+            }
+
+        if (initArities.size()==0) {state.output.fatal("Arity count failed... counted 0.");}
+
+        // identify different available arities and place on array
+        arities=new int[noOfArities];
+        current=0;
+
+        while(current<noOfArities)
+            {
+            // finds maximum arity on the list
+            marker=0;
+            for (counter=0;counter<initArities.size();counter++)
+                {
+                ArityObject max=(ArityObject) initArities.get(counter);
+                if (max.arity > marker)
+                    {
+                    marker=max.arity;
+                    }
+                }
+
+            // Place maximum found on the array
+            arities[current]=marker;
+            remove(initArities,marker);
+            current++;
+            }
+
+        aritySetupDone=true;
+        }
+
+    private long fact(long num)
+        {
+        if (num==0) { return 1; }
+        else { return num*fact(num-1); }
+        }
+
+    private int[] select(LinkedList permutations,int size)
+        {
+        int counter1,counter2,total=0;
+        long residue,denominator=1;
+        int selection;
+        int[] current;
+        int[] quantity=new int[permutations.size()];
+
+        for (counter1=0;counter1<permutations.size();counter1++)
+            {
+            current=(int[])permutations.get(counter1);
+            residue=size;
+            // Quick internal calculations
+            for (counter2=0;counter2<current.length;counter2++)
+                {
+                residue -= current[counter2];
+                denominator *= fact(current[counter2]);
+                }
+            quantity[counter1] = (int) (fact(size-1)/(denominator * fact(residue)));
+            total += quantity[counter1];
+            }
+
+        double[] prob=new double[quantity.length];
+        // quantities found... now build array for probabilities
+        for (counter1=0;counter1<quantity.length;counter1++)
+            {
+            prob[counter1] = (double)quantity[counter1]/(double)total;
+            // I don't think we need to check for negative values here -- Sean
+            }
+        RandomChoice.organizeDistribution(prob);
+        double s=0.0;
+        selection = RandomChoice.pickFromDistribution(prob,s);
+
+        return (int[])permutations.get(selection);
+        }
+
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        int treeSize;
+        boolean valid=false;
+        String word=new String();
+
+        treeSize=pickSize(state,thread);
+
+        if (!aritySetupDone) { setupArities(state,set); }
+
+        int[] temp=new int[arities.length];
+        permutations=new LinkedList();
+        Permute(0,temp,treeSize-1);
+        if (permutations.size()==0) { state.output.fatal("Not able to build combination of nodes."); }
+        int[] scheme=select(permutations,treeSize);
+        word=buildDyckWord(treeSize,arities,scheme,state,thread);
+        int cycle=0;
+        while(!valid)
+            {
+            valid=checkDyckWord(word);
+            if (!valid)
+                {
+                word=word.substring(word.length()-1,word.length()).concat(word.substring(0,word.length()-1));
+                cycle++;
+                if (cycle>=(treeSize*2)-1) {state.output.fatal("Not able to find valid permutation for generated Dyck word: "+word);}
+                }
+            }
+        return buildTree(state,thread,parent,argposition,set,word);
+        }
+
+    // recursive function to work out all combinations and push them onto ArrayList
+    private void Permute(int current,int[] sol,int size)
+        {
+        int counter=0,result=0;
+        // base case
+        if (current==arities.length-1) /* set last one to maximum allowable */
+            {
+            while(result<=size)
+                {
+                counter++;
+                result=result+arities[current];
+                }
+            result=result-arities[current];
+            counter--;
+            if (result<0)
+                {
+                result=0;
+                counter=0;
+                }
+            sol[current]=counter;
+
+            //Adding this solution to the list.
+            permutations.add(sol);
+            }
+        // end of base case
+        else
+            {
+            while(result<=size)
+                {
+                if (result<=size)
+                    {
+                    sol[current]=counter;
+                    Permute(current+1,sol,size-result);
+                    }
+                result=result+arities[current];
+                counter++;
+                }
+            }
+        }
+
+    public String buildDyckWord(int requestedSize,int[] arities,int[] s,EvolutionState state,int thread)
+        {
+        int counter,choices,choice,pos,arity=0,checksum=0,size=0;
+        int[] scheme=new int[s.length];
+
+        String dyck=new String("");
+        String addStr=new String();
+
+        scheme=s;
+        for(counter=0;counter<scheme.length;counter++)
+            {
+            checksum += scheme[counter]*arities[counter];
+            }
+
+        size=checksum+1;
+        if (size!=requestedSize) { state.output.message("A tree of the requested size could not be built.  Using smaller size.");}
+        choices=size;
+
+        for(counter=0;counter<size;counter++)
+            {
+            dyck=dyck.concat("x*");
+            }
+
+        // Find a non-0 arity to insert
+        counter=0;
+        while((arity==0) && (counter<scheme.length))
+            {
+            if (scheme[counter]>0)
+                {
+                arity=arities[counter];
+                scheme[counter]--;
+                }
+            counter++;
+            }
+
+        while(arity!=0)
+            {
+            choice=state.random[thread].nextInt(choices--)+1;
+            pos=-1;
+            counter=0;
+            // find insertion position within the string
+            while(counter!=choice)
+                {
+                pos++;
+                if (dyck.charAt(pos)=='*') { counter++; }
+                }
+            // building no of y's in string
+            addStr="";
+            while (addStr.length()<arity) { addStr=addStr.concat("y"); }
+
+            // finally put the string together again
+            dyck=dyck.substring(0,pos).concat(addStr).concat(dyck.substring(pos+1,dyck.length()));
+
+            // Find another non-0 arity to insert
+            counter=0;
+            arity=0;
+            while((arity==0) && (counter<scheme.length))
+                {
+                if (scheme[counter]>0)
+                    {
+                    arity=arities[counter];
+                    scheme[counter]--;
+                    }
+                counter++;
+                }
+            }
+        //Clean up leftover *'s
+        for (counter=0;counter<dyck.length();counter++)
+            {
+            if(dyck.charAt(counter)=='*')
+                {
+                dyck=dyck.substring(0,counter).concat(dyck.substring(counter+1,dyck.length()));
+                }
+            }
+        return dyck;
+        }
+
+    // function to check validity of Dyck word
+    public boolean checkDyckWord(String dyck)
+        {
+        int counter=0;
+        boolean underflow=false;
+        String stack=new String();
+        while ((counter<dyck.length()) && (!underflow))
+            {
+            switch (dyck.charAt(counter))
+                {
+                case 'x':
+                {
+                stack=stack.concat("x");
+                break;
+                }
+                case 'y':
+                {
+                if (stack.length()<=1)
+                    {
+                    underflow=true;
+                    stack="";
+                    }
+                else
+                    {
+                    stack=stack.substring(0,stack.length()-1);
+                    }
+                break;
+                }
+                }
+            counter++;
+            }
+        if (stack.length()!=1)
+            {
+            return false;
+            }
+        else
+            {
+            return true;
+            }
+        }
+
+    // This function parses the dyck word and puts random nodes into their slots.
+    private GPNode buildTree(final EvolutionState state,
+        final int thread,
+        final GPNodeParent parent,
+        final int argposition,
+        final GPFunctionSet set,
+        final String dyckWord) 
+        {
+        int counter=0;
+        Stack s=new Stack();
+        char nextChar;
+
+        // Parsing dyck word from left to right and building tree
+        for (counter=0;counter<dyckWord.length();counter++)
+            {
+            if (counter<dyckWord.length()-1) { nextChar=dyckWord.charAt(counter+1);} else { nextChar='*'; }
+            if ((nextChar=='x') || (nextChar=='*')) /* terminal node */
+                {
+                GPNode[] nn = set.terminals[0];
+                GPNode n = (GPNode)(nn[state.random[thread].nextInt(nn.length)].lightClone());
+                n.resetNode(state,thread);  // give ERCs a chance to randomize
+                s.push(n);
+                }
+            else if (nextChar=='y') /* non-terminal */
+                {
+                // finding arity of connection
+                int Ycount=0; /* arity */
+                boolean nextCharY;
+                nextCharY=(nextChar=='y');
+                counter++;
+                while ((counter<dyckWord.length()) && (nextCharY))
+                    {
+                    if (dyckWord.charAt(counter)=='y') { Ycount++; }
+                    if (counter<dyckWord.length()-1) { nextCharY=(dyckWord.charAt(counter+1)=='y'); }
+                    counter++;
+                    }
+
+                //Arity found.  Now just choose non terminal at random.
+                GPNode[] nonTerms=set.nodesByArity[0][Ycount];
+                GPNode nT=(GPNode) (nonTerms[state.random[thread].nextInt(nonTerms.length)].lightClone());
+                // Non terminal chosen, now attaching children
+                int childcount=Ycount;
+                while (childcount>0)
+                    {
+                    childcount--;
+                    if (s.size()==0) { state.output.fatal("Stack underflow when building tree."); }
+                    GPNode child=(GPNode) s.pop();
+                    child.parent=nT;
+                    child.argposition=(byte)childcount;
+                    nT.children[childcount]=child;
+                    }
+                nT.argposition=0;
+                nT.parent=null;
+                s.push(nT);
+                if (counter!=dyckWord.length()) counter--;
+                }
+            }
+        return (GPNode) s.pop();
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/RandomBranch.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/RandomBranch.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/RandomBranch.java	(revision 6152)
@@ -0,0 +1,149 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+import ec.gp.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * RandomBranch.java
+ * 
+ * Created: Mon Dec 13 14:26:02 1999
+ * By: Sean Luke
+ */
+
+/**
+ * RandomBranch implements the <tt>Random_Branch</tt> tree generation
+ * method described in 
+ *
+ * <p> Chellapilla, K. 1998.  Evolving Modular Programs without Crossover.
+ * in <i>Proceedings of the Third Annual Genetic Programming Conference</i>
+ * (GP98), J.R. Koza <i>et al</i>, editors.  San Fransisco: Morgan Kaufmann.
+ * 23--31.
+ *
+ * <p> This algorithm attempts to create a tree of size <tt>requestedSize</tt>,
+ * or "slightly less".
+ *
+ * If the pipeline does not specify a size it wants (it uses <tt>NOSIZEGIVEN</tt>),
+ * the algorithm picks a size at random from either [minSize...maxSize] or from
+ * sizeDistribution (one of the two <b>must</b> be defined), and attempts to create
+ * a tree of that size or "slightly less".
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class RandomBranch extends GPNodeBuilder 
+    {
+    public static final String P_RANDOMBRANCH = "random-branch";
+
+    public Parameter defaultBase()
+        {
+        return GPBuildDefaults.base().push(P_RANDOMBRANCH);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        // we use size distributions -- did the user specify any?
+        if (!canPick())
+            state.output.fatal("RandomBranch requires some kind of size distribution set, either with " + P_MINSIZE + "/" + P_MAXSIZE + ", or with " + P_NUMSIZES + ".",
+                base, defaultBase());
+        }
+
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        if (requestedSize == NOSIZEGIVEN)  // pick from the distribution
+            return randomBranch(state,type,pickSize(state,thread),thread,parent,argposition,set);
+        if (requestedSize < 1)
+            state.output.fatal("ec.gp.build.RandomBranch requested to build a tree, but a requested size was given that is < 1.");
+        return randomBranch(state,type,requestedSize,thread,parent,argposition,set);
+        }
+
+    private GPNode randomBranch(final EvolutionState state,
+        final GPType type,
+        final int maxLength, 
+        final int thread,
+        final GPNodeParent parent,
+        final int argposition,
+        final GPFunctionSet set) 
+        {
+        // randomBranch can mess up if there are no available terminals for a given type.  If this occurs,
+        // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
+        // and pick a nonterminal, violating the maximum-size contract.  This can lead to pathological situations
+        // where the system will continue to go on and on unable to stop because it can't pick a terminal,
+        // resulting in running out of memory or some such.  But there are cases where we'd want to let
+        // this work itself out.
+        boolean triedTerminals = false;
+
+        int t = type.type;
+        GPNode[] terminals = set.terminals[t];
+        GPNode[] nonterminals = set.nonterminals[t];
+        GPNode[] nodes = set.nodes[t];          
+
+        if (nodes.length == 0)
+            errorAboutNoNodeWithType(type, state);   // total failure
+
+        if ((   maxLength == 1 ||                                                       // if the desired length is 1
+                warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&    // OR if there are NO nonterminals!
+            (triedTerminals = true) &&                                                  // [first set triedTerminals]
+            terminals.length != 0)                                                      // AND if there are available terminals
+            {
+            GPNode n = (GPNode)(terminals[state.random[thread].nextInt(terminals.length)].lightClone());
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+            return n;
+            }
+        else
+            {
+            if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);        // we tried terminals and we're here because there were none!
+                        
+            // grab all the nodes whose arity is <= maxlength-1
+            int len = set.nonterminalsUnderArity[type.type].length-1;
+            if (len > maxLength-1) len = maxLength-1;
+            GPNode[] okayNonterms = set.nonterminalsUnderArity[type.type][len];
+
+            if (okayNonterms.length == 0) // no nodes, pick a terminal
+                {
+                if (terminals.length == 0) 
+                    errorAboutNoNodeWithType(type, state);   // total failure
+                                
+                GPNode n = (GPNode)(terminals[state.random[thread].nextInt(terminals.length)].lightClone());
+                n.resetNode(state,thread);  // give ERCs a chance to randomize
+                n.argposition = (byte)argposition;
+                n.parent = parent;
+                return n;
+                }
+            else // we've got nonterminals, pick one at random
+                {
+                GPNode n = (GPNode)(okayNonterms[state.random[thread].nextInt(okayNonterms.length)].lightClone());
+                n.resetNode(state,thread);  // give ERCs a chance to randomize
+                n.argposition = (byte)argposition;
+                n.parent = parent;
+
+                // Populate the node...
+                GPType[] childtypes = n.constraints(((GPInitializer)state.initializer)).childtypes;
+                for(int x=0;x<childtypes.length;x++)
+                    n.children[x] = randomBranch(
+                        state,childtypes[x],
+                        (maxLength-1)/childtypes.length, // note int division
+                        thread,n,x,set);
+                return n;
+                }
+            }
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/Uniform.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/build/Uniform.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/build/Uniform.java	(revision 6152)
@@ -0,0 +1,599 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.build;
+import ec.gp.*;
+import java.util.*;
+import java.math.*;
+import ec.util.*;
+import ec.*;
+import java.io.*;
+
+/* 
+ * Uniform.java
+ * 
+ * Created Fri Jan 26 14:02:08 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+   Uniform implements the algorithm described in 
+
+   <p>Bohm, Walter and Andreas Geyer-Schulz. 1996. "Exact Uniform Initialization for Genetic Programming".  In <i>Foundations of Genetic Algorithms IV,</i> Richard Belew and Michael Vose, eds.  Morgan Kaufmann.  379-407. (ISBN 1-55860-460-X) 
+
+   <p> The user-provided requested tree size is either provided directly to the Uniform algorithm, or if the size is NOSIZEGIVEN, then Uniform will pick one at random from the GPNodeBuilder probability distribution system (using either max-depth and min-depth, or using num-sizes).  
+
+   <p>Further, if the user sets the <tt>true-dist</tt> parameter, the Uniform will ignore the user's specified probability distribution and instead pick from a distribution between the minimum size and the maximum size the user specified, where the sizes are distributed according to the <i>actual</i> number of trees that can be created with that size.  Since many more trees of size 10 than size 3 can be created, for example, size 10 will be picked that much more often.
+
+   <p>Uniform also prints out the actual number of trees that exist for a given size, return type, and function set.  As if this were useful to you.  :-)
+
+   <p> The algorithm, which is quite complex, is described in pseudocode below.  Basically what the algorithm does is this:
+
+   <ol>
+   <li> For each function set and return type, determine the number of trees of each size which exist for that function set and tree type.  Also determine all the permutations of tree sizes among children of a given node.  All this can be done with dynamic programming.  Do this just once offline, after the function sets are loaded. 
+   <li> Using these tables, construct distributions of choices of tree size, child tree size permutations, etc.
+   <li> When you need to create a tree, pick a size, then use the distriutions to recursively create the tree (top-down).
+   </ol>
+
+   <p> <b>Dealing with Zero Distributions</b>
+   <p> Some domains have NO tree of a certain size.  For example, 
+   Artificial Ant's function set can make NO trees of size 2.
+   What happens when we're asked to make a tree of (invalid) size 2 in
+   Artificial Ant then?  Uniform presently handles it as follows:
+   <ol><li> If the system specifically requests a given size that's invalid, Uniform will 
+   look for the next larger size which is valid.  If it can't find any,
+   it will then look for the next smaller size which is valid.
+   <li> If a random choice yields a given size that's invalid,
+   Uniform will pick again.
+   <li> If there is *no* valid size for a given return type, which probably indicates
+   an error, Uniform will halt and complain.
+   </ol>
+        
+   <h3>Pseudocode:</h3>
+
+   <pre>
+
+   *    Func NumTreesOfType(type,size)
+   *        If NUMTREESOFTYPE[type,size] not defined,       // memoize
+   *            N[type] = all nodes compatible with type
+   *            NUMTREESOFTYPE[type,size] = Sum(n in N[type], NumTreesRootedByNode(n,size))
+   *            return NUMTREESOFTYPE[type,size]
+   *
+   *    Func NumTreesRootedByNode(node,size)
+   *        If NUMTREESROOTEDBYNODE[node,size] not defined,   // memoize
+   *            count = 0
+   *            left = size - 1
+   *            If node.children.length = 0 and left = 0  // a valid terminal
+   *                count = 1
+   *            Else if node.children.length <= left  // a valid nonterminal
+   *                For s is 1 to left inclusive  // yeah, that allows some illegal stuff, it gets set to 0
+   *                    count += NumChildPermutations(node,s,left,0)
+   *            NUMTREESROOTEDBYNODE[node,size] = count
+   *        return NUMTREESROOTEBYNODE[node,size]
+   *
+   *
+   *    Func NumChildPermutations(parent,size,outof,pickchild)
+   *    // parent is our parent node
+   *    // size is the size of pickchild's tree that we're considering
+   *    // pickchild is the child we're considering
+   *    // outof is the total number of remaining nodes (including size) yet to fill
+   *        If NUMCHILDPERMUTATIONS[parent,size,outof,pickchild] is not defined,        // memoize
+   *            count = 0
+   *            if pickchild = parent.children.length - 1        and outof==size        // our last child, outof must be size
+   *                count = NumTreesOfType(parent.children[pickchild].type,size)
+   *            else if pickchild < parent.children.length - 1 and 
+   *                                outof-size >= (parent.children.length - pickchild-1)    // maybe we can fill with terminals
+   *                cval = NumTreesOfType(parent.children[pickchild].type,size)
+   *                tot = 0
+   *                For s is 1 to outof-size // some illegal stuff, it gets set to 0
+   *                    tot += NumChildPermutations(parent,s,outof-size,pickchild+1)
+   *                count = cval * tot
+   *            NUMCHILDPERMUTATIONS [parent,size,outof,pickchild] = count            
+   *        return NUMCHILDPERMUTATIONS[parent,size,outof,pickchild]
+   *
+   *
+   *    For each type type, size size
+   *        ROOT_D[type,size] = probability distribution of nodes of type and size, derived from
+   *                            NUMTREESOFTYPE[type,size], our node list, and NUMTREESROOTEDBYNODE[node,size]
+   *
+   *    For each parent,outof,pickchild
+   *        CHILD_D[parent,outof,pickchild] = probability distribution of tree sizes, derived from
+   *                            NUMCHILDPERMUTATIONS[parent,size,outof,pickchild]
+   *
+   *    Func FillNodeWithChildren(parent,pickchild,outof)
+   *        If pickchild = parent.children.length - 1               // last child
+   *            Fill parent.children[pickchild] with CreateTreeOfType(parent.children[pickchild].type,outof)
+   *        Else choose size from CHILD_D[parent,outof,pickchild]
+   *            Fill parent.pickchildren[pickchild] with CreateTreeOfType(parent.children[pickchild].type,size)
+   *            FillNodeWithChildren(parent,pickchild+1,outof-size)
+   *        return
+   </pre>
+
+   Func CreateTreeOfType(type,size)
+   Choose node from ROOT_D[type,size]
+   If size > 1
+   FillNodeWithChildren(node,0,size-1)
+   return node
+
+
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>true-dist</tt><br>
+   <font size=-1>bool= true or false (default)</font></td>
+   <td valign=top>(should we use the true numbers of trees for each size as the distribution for picking trees, as opposed to the user-specified distribution?)</td></tr>
+   </table>
+
+   <p><b>Default Base</b><br>
+   gp.breed.uniform
+
+*/
+
+
+
+public class Uniform extends GPNodeBuilder 
+    {
+    public static final String P_UNIFORM = "uniform";
+    public static final String P_TRUEDISTRIBUTION = "true-dist";
+    
+    public Parameter defaultBase()
+        {
+        return GPBuildDefaults.base().push(P_UNIFORM);
+        }
+
+    // Mapping of integers to function sets
+    public GPFunctionSet[] functionsets;
+    
+    // Mapping of function sets to Integers
+    public Hashtable _functionsets;
+    
+    // Mapping of GPNodes to Integers (thus to ints)
+    public Hashtable funcnodes;
+    
+    // number of nodes
+    public int numfuncnodes;
+    
+    // max arity of any node
+    public int maxarity;
+    
+    // maximum size of nodes computed
+    public int maxtreesize;
+    
+    // true size distributions
+    public BigInteger[/*functionset*/][/*type*/][/*size*/] _truesizes;
+    public double[/*functionset*/][/*type*/][/*size*/] truesizes;
+    
+    // do we use the true distributions to pick tree sizes?
+    public boolean useTrueDistribution;
+    
+    // Sun in its infinite wisdom (what idiots) decided to make
+    // BigInteger IMMUTABLE.  There is a MutableBigInteger, but it's not
+    // public!  And Sun only caches the first 16 positive and 16 negative
+    // integer constants, not exactly that useful for us.  As a result, we'll
+    // be making a dang lot of BigIntegers here.  Garbage-collection hell.  :-(
+    // ...well, it's not all that slow really.
+    public BigInteger NUMTREESOFTYPE[/*FunctionSet*/][/*type*/][/*size*/];
+    public BigInteger NUMTREESROOTEDBYNODE[/*FunctionSet*/][/*nodenum*/][/*size*/];
+    public BigInteger NUMCHILDPERMUTATIONS[/*FunctionSet*/][/*parentnodenum*/][/*size*/][/*outof*/][/*pickchild*/];
+    
+    
+    
+    // tables derived from the previous ones through some massaging
+    
+    // [/*the nodes*/] is an array of <node,probability> pairs for all possible nodes rooting
+    // trees of the desired size and compatible with the given return type.  It says that if you
+    // were to pick a tree, this would be the probability that this node would be the root of it.
+    public UniformGPNodeStorage ROOT_D[/*FunctionSet*/][/*type*/][/*size*/][/*the nodes*/];
+    
+    // True if ROOT_D all zero for all possible nodes in [/*the nodes*/] above. 
+    public boolean ROOT_D_ZERO[/*FunctionSet*/][/*type*/][/*size*/];
+    
+    public double CHILD_D[/*FunctionSet*/][/*type*/][/*outof*/][/*pickchild*/][/* the nodes*/];
+    
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+        
+        // use true distributions? false is default
+        useTrueDistribution = state.parameters.getBoolean(
+            base.push(P_TRUEDISTRIBUTION), def.push(P_TRUEDISTRIBUTION),false);
+        
+        if (minSize>0)  // we're using maxSize and minSize
+            maxtreesize=maxSize;
+        else if (sizeDistribution != null)
+            maxtreesize = sizeDistribution.length;
+        else state.output.fatal("Uniform is used for the GP node builder, but no distribution was specified." +
+            "  You must specify either a min/max size, or a full size distribution.",
+            base.push(P_MINSIZE), def.push(P_MINSIZE));
+        // preprocess offline
+        preprocess(state,maxtreesize);
+        }
+        
+    public int pickSize(final EvolutionState state, final int thread, 
+        final int functionset, final int type)
+        {
+        if (useTrueDistribution)
+            return RandomChoice.pickFromDistribution(
+                truesizes[functionset][type],state.random[thread].nextDouble());
+        else return super.pickSize(state,thread);
+        }
+    
+    public void preprocess(final EvolutionState state, final int _maxtreesize)
+        {
+        state.output.message("Determining Tree Sizes");
+        
+        maxtreesize = _maxtreesize;
+        
+        Hashtable functionSetRepository = ((GPInitializer)state.initializer).functionSetRepository;
+        
+        // Put each function set into the arrays
+        functionsets = new GPFunctionSet[functionSetRepository.size()];
+        _functionsets = new Hashtable();
+        Enumeration e = functionSetRepository.elements();
+        int count=0;
+        while(e.hasMoreElements())
+            {
+            GPFunctionSet set = (GPFunctionSet)(e.nextElement());
+            _functionsets.put(set,new Integer(count));
+            functionsets[count++] = set;
+            }
+        
+        // For each function set, assign each GPNode to a unique integer
+        // so we can keep track of it (ick, this will be inefficient!)
+        funcnodes = new Hashtable();
+        Hashtable t_nodes = new Hashtable();
+        count = 0;
+        maxarity=0;
+        GPNode n;
+        for(int x=0;x<functionsets.length;x++)
+            {
+            // hash all the nodes so we can remove duplicates
+            for(int typ=0;typ<functionsets[x].nodes.length;typ++)
+                for(int nod=0;nod<functionsets[x].nodes[typ].length;nod++)
+                    t_nodes.put(n=functionsets[x].nodes[typ][nod],n);
+            // rehash with Integers, yuck
+            e = t_nodes.elements();
+            GPNode tmpn;
+            while(e.hasMoreElements())
+                {
+                tmpn = (GPNode)(e.nextElement());
+                if (maxarity < tmpn.children.length) 
+                    maxarity = tmpn.children.length;
+                if (!funcnodes.containsKey(tmpn))  // don't remap the node; it'd make holes
+                    funcnodes.put(tmpn,new Integer(count++));
+                }
+            }
+        
+        numfuncnodes = funcnodes.size();
+        
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        int numAtomicTypes = initializer.numAtomicTypes;
+        int numSetTypes = initializer.numSetTypes;
+        
+        // set up the arrays
+        NUMTREESOFTYPE = new BigInteger[functionsets.length][numAtomicTypes+numSetTypes][maxtreesize+1];
+        NUMTREESROOTEDBYNODE = new BigInteger[functionsets.length][numfuncnodes][maxtreesize+1];
+        NUMCHILDPERMUTATIONS = new BigInteger[functionsets.length][numfuncnodes][maxtreesize+1][maxtreesize+1][maxarity];
+        ROOT_D = new UniformGPNodeStorage[functionsets.length][numAtomicTypes+numSetTypes][maxtreesize+1][];
+        ROOT_D_ZERO = new boolean[functionsets.length][numAtomicTypes+numSetTypes][maxtreesize+1];
+        CHILD_D = new double[functionsets.length][numfuncnodes][maxtreesize+1][maxtreesize+1][];
+
+        GPType[] types = ((GPInitializer)(state.initializer)).types;
+        // Go through each function set and determine numbers
+        // (this will take quite a while!  Thankfully it's offline)
+        _truesizes = new BigInteger[functionsets.length][numAtomicTypes+numSetTypes][maxtreesize+1];
+        for(int x=0;x<functionsets.length;x++)
+            for(int y=0;y<numAtomicTypes+numSetTypes;y++)
+                for(int z=1;z<=maxtreesize;z++)
+                    state.output.message("FunctionSet: " + functionsets[x].name + ", Type: " + types[y].name + ", Size: " + z + " num: " + 
+                        (_truesizes[x][y][z] = numTreesOfType(initializer,x,y,z)));
+
+        state.output.message("Compiling Distributions");
+
+        // convert to doubles and organize distribution
+        truesizes = new double[functionsets.length][numAtomicTypes+numSetTypes][maxtreesize+1];
+        for(int x=0;x<functionsets.length;x++)
+            for(int y=0;y<numAtomicTypes+numSetTypes;y++)
+                {
+                for(int z=1;z<=maxtreesize;z++)
+                    truesizes[x][y][z] = _truesizes[x][y][z].doubleValue();
+                // and if this is all zero (a possibility) we should be forgiving (hence the 'true') -- I *think*
+                RandomChoice.organizeDistribution(truesizes[x][y],true);
+                }
+        
+        // compute our percentages
+        computePercentages();
+        }
+    
+    // hopefully this will get inlined
+    public final int intForNode(GPNode node)
+        {
+        return ((Integer)(funcnodes.get(node))).intValue();
+        }
+    
+    
+    public BigInteger numTreesOfType(final GPInitializer initializer, 
+        final int functionset, final int type, final int size)
+        {
+        if (NUMTREESOFTYPE[functionset][type][size]==null)
+            {
+            GPNode[] nodes = functionsets[functionset].nodes[type];
+            BigInteger count = BigInteger.valueOf(0);
+            for(int x=0;x<nodes.length;x++)
+                count = count.add(numTreesRootedByNode(initializer,functionset,nodes[x],size));
+            NUMTREESOFTYPE[functionset][type][size] = count;
+            }
+        return NUMTREESOFTYPE[functionset][type][size];
+        }
+    
+    public BigInteger numTreesRootedByNode(final GPInitializer initializer,
+        final int functionset, final GPNode node, final int size)
+        {
+        if (NUMTREESROOTEDBYNODE[functionset][intForNode(node)][size]==null)
+            {
+            BigInteger one = BigInteger.valueOf(1);
+            BigInteger count = BigInteger.valueOf(0);
+            int outof = size-1;
+            if (node.children.length == 0 && outof == 0) // a valid terminal
+                count = one;
+            else if (node.children.length <= outof)  // a valid nonterminal
+                for (int s=1;s<=outof;s++)
+                    count = count.add(numChildPermutations(initializer,functionset,node,s,outof,0));
+            //System.out.println("Node: " + node + " Size: " + size + " Count: " +count);
+            NUMTREESROOTEDBYNODE[functionset][intForNode(node)][size] = count;
+            }
+        return NUMTREESROOTEDBYNODE[functionset][intForNode(node)][size];
+        }
+    
+    public BigInteger numChildPermutations( final GPInitializer initializer,
+        final int functionset, final GPNode parent, final int size,
+        final int outof, final int pickchild)
+        {
+        if (NUMCHILDPERMUTATIONS[functionset][intForNode(parent)][size][outof][pickchild]==null)
+            {
+            BigInteger count = BigInteger.valueOf(0);
+            if (pickchild == parent.children.length - 1 && size==outof)
+                count = numTreesOfType(initializer,functionset,parent.constraints(initializer).childtypes[pickchild].type,size);
+            else if (pickchild < parent.children.length - 1 && 
+                outof-size >= (parent.children.length - pickchild-1))
+                {
+                BigInteger cval = numTreesOfType(initializer,functionset,parent.constraints(initializer).childtypes[pickchild].type,size);
+                BigInteger tot = BigInteger.valueOf(0);
+                for (int s=1; s<=outof-size; s++)
+                    tot = tot.add(numChildPermutations(initializer,functionset,parent,s,outof-size,pickchild+1));
+                count = cval.multiply(tot);
+                }
+            // System.out.println("Parent: " + parent + " Size: " + size + " OutOf: " + outof + 
+            //       " PickChild: " + pickchild + " Count: " +count);
+            NUMCHILDPERMUTATIONS[functionset][intForNode(parent)][size][outof][pickchild] = count;
+            }
+        return NUMCHILDPERMUTATIONS[functionset][intForNode(parent)][size][outof][pickchild];
+        }
+    
+    private final double getProb(final BigInteger i)
+        {
+        if (i==null) return 0.0f;
+        else return i.doubleValue();
+        }
+        
+    public void computePercentages()
+        {
+        // load ROOT_D
+        for(int f = 0;f<NUMTREESOFTYPE.length;f++)
+            for(int t=0;t<NUMTREESOFTYPE[f].length;t++)
+                for(int s=0;s<NUMTREESOFTYPE[f][t].length;s++)
+                    {
+                    ROOT_D[f][t][s] = new UniformGPNodeStorage[functionsets[f].nodes[t].length];
+                    for(int x=0;x<ROOT_D[f][t][s].length;x++)
+                        {
+                        ROOT_D[f][t][s][x] = new UniformGPNodeStorage();
+                        ROOT_D[f][t][s][x].node = functionsets[f].nodes[t][x];
+                        ROOT_D[f][t][s][x].prob = getProb(NUMTREESROOTEDBYNODE[f][intForNode(ROOT_D[f][t][s][x].node)][s]);
+                        }
+                    // organize the distribution
+                    //System.out.println("Organizing " + f + " " + t + " " + s);
+                    // check to see if it's all zeros
+                    for(int x=0;x<ROOT_D[f][t][s].length;x++)
+                        if (ROOT_D[f][t][s][x].prob != 0.0)
+                            {
+                            // don't need to check for negatives here I believe
+                            RandomChoice.organizeDistribution(ROOT_D[f][t][s],ROOT_D[f][t][s][0]);
+                            ROOT_D_ZERO[f][t][s] = false;
+                            break;
+                            }
+                        else
+                            {
+                            ROOT_D_ZERO[f][t][s] = true;
+                            }
+                    }
+
+        // load CHILD_D
+        for(int f = 0;f<NUMCHILDPERMUTATIONS.length;f++)
+            for(int p=0;p<NUMCHILDPERMUTATIONS[f].length;p++)
+                for(int o=0;o<maxtreesize+1;o++)
+                    for(int c=0;c<maxarity;c++)
+                        {
+                        CHILD_D[f][p][o][c] = new double[o+1];
+                        for(int s=0;s<CHILD_D[f][p][o][c].length;s++)
+                            CHILD_D[f][p][o][c][s] = getProb(NUMCHILDPERMUTATIONS[f][p][s][o][c]);
+                        // organize the distribution
+                        //System.out.println("Organizing " + f + " " + p + " " + o + " " + c);
+                        // check to see if it's all zeros
+                        for(int x=0;x<CHILD_D[f][p][o][c].length;x++)
+                            if (CHILD_D[f][p][o][c][x] != 0.0)
+                                {
+                                // don't need to check for negatives here I believe
+                                RandomChoice.organizeDistribution(CHILD_D[f][p][o][c]);
+                                break;
+                                }
+                        }
+        }
+        
+    GPNode createTreeOfType(final EvolutionState state, final int thread, final GPInitializer initializer, 
+        final int functionset, final int type, final int size, final MersenneTwisterFast mt)
+        
+        {
+        //System.out.println("" + functionset + " " + type + " " + size);
+        int choice = RandomChoice.pickFromDistribution(
+            ROOT_D[functionset][type][size],ROOT_D[functionset][type][size][0],
+            mt.nextDouble());
+        GPNode node = (GPNode)(ROOT_D[functionset][type][size][choice].node.lightClone());
+        node.resetNode(state,thread);  // give ERCs a chance to randomize
+        //System.out.println("Size: " + size + "Rooted: " + node);
+        if (node.children.length == 0 && size !=1) // uh oh
+            {
+            System.out.println("Size: " + size + " Node: " + node);
+            for(int x=0;x<ROOT_D[functionset][type][size].length;x++)
+                System.out.println("" + x + (GPNode)(ROOT_D[functionset][type][size][x].node) + " " + ROOT_D[functionset][type][size][x].prob );
+            }
+        if (size > 1)  // nonterminal
+            fillNodeWithChildren(state,thread,initializer,functionset,node,ROOT_D[functionset][type][size][choice].node,0,size-1,mt);
+        return node;
+        }
+       
+    void fillNodeWithChildren(final EvolutionState state, final int thread, final GPInitializer initializer,
+        final int functionset, final GPNode parent, final GPNode parentc, 
+        final int pickchild, final int outof, final MersenneTwisterFast mt)
+        
+        {
+        if (pickchild == parent.children.length - 1)
+            {
+            parent.children[pickchild] = 
+                createTreeOfType(state,thread,initializer,functionset,parent.constraints(initializer).childtypes[pickchild].type,outof, mt);
+            }
+        else 
+            {
+            int size = RandomChoice.pickFromDistribution(
+                CHILD_D[functionset][intForNode(parentc)][outof][pickchild],
+                mt.nextDouble());
+            parent.children[pickchild] = 
+                createTreeOfType(state,thread,initializer,functionset,parent.constraints(initializer).childtypes[pickchild].type,size,mt);
+            fillNodeWithChildren(state,thread,initializer,functionset,parent,parentc,pickchild+1,outof-size,mt);
+            }
+        parent.children[pickchild].parent = parent;
+        parent.children[pickchild].argposition = (byte)pickchild;            
+        }
+        
+
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        
+        if (requestedSize == NOSIZEGIVEN)  // pick from the distribution
+            {
+            final int BOUNDARY = 20;  // if we try 20 times and fail, check to see if it's possible to succeed
+            int bound=0;
+                
+            int fset = ((Integer)(_functionsets.get(set))).intValue();
+            int siz = pickSize(state,thread,fset,type.type);
+            int typ = type.type;
+            
+            // this code is confusing.  The idea is:
+            // if the number of trees of our arbitrarily-picked size is zero, we try BOUNDARY
+            // number of times to find a tree which will work, picking new sizes each
+            // time.  If we still haven't found anything, we will continue to search
+            // for a working tree only if we know for sure that one exists in the distribution.
+            
+            boolean checked = false;
+            while(ROOT_D_ZERO[fset][typ][siz])
+                {
+                if (++bound == BOUNDARY)
+                    {
+                    check: 
+                    if (!checked) 
+                        {
+                        checked = true;
+                        for(int x=0;x<ROOT_D_ZERO[fset][typ].length;x++)
+                            if (!ROOT_D_ZERO[fset][typ][x]) 
+                                break check;  // found a non-zero
+                        // uh oh, we're all zeroes
+                        state.output.fatal("ec.gp.build.Uniform was asked to build a tree with functionset " + set + " rooted with type " + type + ", but cannot because for some reason there are no trees of any valid size (within the specified size range) which exist for this function set and type.");       
+                        }   
+                    }
+                siz = pickSize(state,thread,fset,typ);
+                }
+                    
+            // okay, now we have a valid size.
+            GPNode n = createTreeOfType(state,thread,initializer,fset,typ,siz,state.random[thread]);
+            n.parent = parent;
+            n.argposition = (byte)argposition;
+            return n;
+            }
+        else if (requestedSize<1)
+            {
+            state.output.fatal("ec.gp.build.Uniform requested to build a tree, but a requested size was given that is < 1.");
+            return null;  // never happens
+            }
+        else 
+            {
+            int fset = ((Integer)(_functionsets.get(set))).intValue();
+            int typ = type.type;
+            int siz = requestedSize;
+            
+            // if the number of trees of the requested size is zero, we first march up until we
+            // find a tree size with non-zero numbers of trees.  Failing that, we march down to
+            // find one.  If that still fails, we issue an error.  Otherwise we use the size
+            // we discovered.
+            
+            determineSize:
+            if (ROOT_D_ZERO[fset][typ][siz])
+                {
+                // march up
+                for(int x=siz+1;x<ROOT_D_ZERO[fset][typ].length;x++)
+                    if (ROOT_D_ZERO[fset][typ][siz])
+                        { siz=x; break determineSize; }
+                // march down
+                for(int x=siz-1;x>=0;x--)
+                    if (ROOT_D_ZERO[fset][typ][siz])
+                        { siz=x; break determineSize; }
+                // issue an error
+                state.output.fatal("ec.gp.build.Uniform was asked to build a tree with functionset " + set + " rooted with type " + type + ", and of size " + requestedSize + ", but cannot because for some reason there are no trees of any valid size (within the specified size range) which exist for this function set and type.");
+                }
+                
+            GPNode n = createTreeOfType(state,thread,initializer,fset,typ,siz,state.random[thread]);
+            n.parent = parent;
+            n.argposition = (byte)argposition;
+            return n;
+            }
+        }
+        
+    }
+    
+    
+class UniformGPNodeStorage implements RandomChoiceChooserD, Serializable
+    {
+    public GPNode node;
+    public double prob;
+    public double getProbability(final Object obj)
+        { return (((UniformGPNodeStorage)obj).prob); }
+    public void setProbability(final Object obj, final double _prob)
+        { ((UniformGPNodeStorage)obj).prob = _prob; }
+    }
+
+    
+    
+    
+    
+    
+    
+
+    
+    
+    
+    
+    
+    
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEDefaults.java	(revision 6152)
@@ -0,0 +1,37 @@
+/*
+  Copyright 2010 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.ge;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * GEDefaults.java
+ * 
+ * Created: Fri May 28 14:29:41 EDT 2010
+ * By: Sean Luke
+ */
+
+/**
+ * A static class that returns the base for "default values" which GE-style
+ * operators use, rather than making the user specify them all on a per-
+ * species basis.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class GEDefaults implements DefaultsForm
+    {
+    public static final String P_GE = "ge";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_GE);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEIndividual.java	(revision 6152)
@@ -0,0 +1,39 @@
+/*
+  Copyright 20010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.ge;
+
+import ec.*;
+import ec.gp.*;
+import ec.vector.*;
+
+/* 
+ * GEIndividual.java
+ * 
+ * Created: Sat Oct 16 23:21:01 EDT 2010
+ * By: Joseph Zelibor, Eric Kangas, and Sean Luke
+ */
+
+/** 
+    GEIndividual is a simple subclass of ByteVectorIndividual which not only prints out (for humans)
+    the Individual as a byte vector but also prints out the Individual's tree representation.
+*/
+
+public class GEIndividual extends ByteVectorIndividual
+    {
+    public static final String TREE_PREAMBLE = "Equivalent Tree: ";
+    public static final String BAD_TREE = "[BAD]";
+        
+    public void printIndividualForHumans(EvolutionState state, int log)
+        {
+        super.printIndividualForHumans(state, log);
+        state.output.println(TREE_PREAMBLE, log);
+        GPIndividual ind = (((GESpecies)species).map(state, this, 0));
+        if (ind == null) state.output.println(BAD_TREE, log);
+        else ind.printTrees(state, log);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEProblem.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEProblem.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GEProblem.java	(revision 6152)
@@ -0,0 +1,206 @@
+/*
+  Copyright 20010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+package ec.gp.ge;
+
+import ec.*;
+import ec.gp.*;
+import ec.gp.koza.*;
+import ec.simple.*;
+import ec.coevolve.*;
+import ec.util.*;
+
+/* 
+ * GEProblem.java
+ * 
+ * Created: Sat Oct 16 23:21:01 EDT 2010
+ * By: Joseph Zelibor III, Eric Kangas, and Sean Luke
+ */
+
+/** 
+    GEProblem is a special replacement for Problem which performs GE mapping.  You do not subclass
+    from GEProblem.  Rather, create a GPProblem subclass and set it to be the 'problem' parameter of the GEProblem.
+    The GEProblem will convert the GEIndividual into a GPIndividual, then pass this GPIndividual to the GPProblem
+    to be evaluated.
+        
+    <p>The procedure is as follows.  Let's say your GPProblem is the Artificial Ant problem.  Instead of saying...
+        
+    <p><tt>eval.problem = ec.app.ant.Ant<br>
+    eval.problem = ec.app.ant.Ant<br>
+    eval.problem.data = ec.app.ant.AntData<br>
+    eval.problem.moves = 400<br>
+    eval.problem.file = santafe.trl
+    </tt>
+
+    <p>... you instead make your problem a GEProblem like this:
+
+    <p><tt>eval.problem = ec.gp.ge.GEProblem</tt>
+        
+    <p>... and then you hang the Ant problem, and all its subsidiary data, as the 'problem' parameter from the GEProblem like so:
+
+    <p><tt>eval.problem.problem = ec.app.ant.Ant<br>
+    eval.problem.problem.data = ec.app.ant.AntData<br>
+    eval.problem.problem.moves = 400<br>
+    eval.problem.problem.file = santafe.trl
+    </tt>
+
+    <p>Everything else should be handled for you.  GEProblem is also compatible with the MasterProblem procedure
+    for distributed evaluation, and is also both a SimpleProblemForm and a GroupedProblemForm.  We've got you covered.
+
+    <p><b>Parameters</b><br>
+    <table>
+    <tr><td valign=top><i>base</i>.<tt>problem</tt><br>
+    <font size=-1>classname, inherits from GPProblem</font></td>
+    <td valign=top>(The GPProblem which actually performs the evaluation of the mapped GPIndividual)</td></tr>
+    </table>
+*/
+
+public class GEProblem extends Problem implements SimpleProblemForm, GroupedProblemForm
+    {
+    public final static String P_PROBLEM = "problem";
+    public GPProblem problem;
+        
+    public void setup(EvolutionState state, Parameter base)
+        {
+        problem = (GPProblem)state.parameters.getInstanceForParameter(base.push(P_PROBLEM), null, GPProblem.class);
+        problem.setup(state, base.push(P_PROBLEM));
+        }
+        
+    public Object clone()
+        {
+        GEProblem other = (GEProblem)(super.clone());
+        other.problem = (GPProblem)(problem.clone());
+        return other;
+        }
+        
+    public void prepareToEvaluate(final EvolutionState state, final int threadnum)
+        {
+        problem.prepareToEvaluate(state, threadnum);
+        }
+
+    public void finishEvaluating(final EvolutionState state, final int threadnum)
+        {
+        problem.finishEvaluating(state, threadnum);
+        }
+
+    public void initializeContacts( EvolutionState state )
+        {
+        problem.initializeContacts(state);
+        }
+
+    public void reinitializeContacts( EvolutionState state )
+        {
+        problem.reinitializeContacts(state);
+        }
+    
+    public void closeContacts(EvolutionState state, int result)
+        {
+        problem.closeContacts(state, result);
+        }
+        
+    public boolean canEvaluate()
+        {
+        return problem.canEvaluate();
+        }
+
+    public void preprocessPopulation(final EvolutionState state, Population pop, final boolean countVictoriesOnly)
+        {
+        if (!(problem instanceof GroupedProblemForm))
+            state.output.fatal("GEProblem's underlying Problem is not a GroupedProblemForm");
+        ((GroupedProblemForm)problem).preprocessPopulation(state, pop, countVictoriesOnly);
+        }
+
+    public void postprocessPopulation(final EvolutionState state, Population pop, final boolean countVictoriesOnly)
+        {
+        ((GroupedProblemForm)problem).preprocessPopulation(state, pop, countVictoriesOnly);
+        }
+        
+    /** Default version assumes that every individual is a GEIndividual.
+        The underlying problem.evaluate() must be prepared for the possibility that some
+        GPIndividuals handed it are in fact null, meaning that they couldn't be extracted
+        from the GEIndividual string.  You should assign them bad fitness in some appropriate way.
+    */
+    public void evaluate(final EvolutionState state,
+        final Individual[] ind,  // the individuals to evaluate together
+        final boolean[] updateFitness,  // should this individuals' fitness be updated?
+        final boolean countVictoriesOnly, // don't bother updating Fitness with socres, just victories
+        final int[] subpops,
+        final int threadnum)
+        {
+        // the default version assumes that every subpopulation is a GE Individual
+        GPIndividual[] gpi = new GPIndividual[ind.length];
+        for(int i = 0; i < gpi.length; i++)
+            {
+            GEIndividual indiv = (GEIndividual) ind[i];
+            GESpecies species = (GESpecies) (ind[i].species);
+                
+            // warning: gpi[i] may be null
+            gpi[i] = species.map(state, indiv, threadnum);
+            }
+                        
+        ((GroupedProblemForm)problem).evaluate(state, gpi, updateFitness, countVictoriesOnly, subpops, threadnum);
+                        
+        for(int i = 0; i < gpi.length; i++)
+            {
+            // Now we need to move the evaluated flag from the GPIndividual
+            // to the GEIndividual, and also for good measure, let's copy over
+            // the GPIndividual's fitness because even though the mapping function
+            // set the two Individuals to share the same fitness, it's possible
+            // that the evaluation function may have replaced the fitness.
+            ind[i].fitness = gpi[i].fitness;
+            ind[i].evaluated = gpi[i].evaluated;
+            }
+        }
+
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum)
+        {
+        if (!(problem instanceof SimpleProblemForm))
+            state.output.fatal("GEProblem's underlying Problem is not a SimpleProblemForm");
+
+        GEIndividual indiv = (GEIndividual) ind;
+        GESpecies species = (GESpecies) (ind.species);
+        GPIndividual gpi = species.map(state, indiv, threadnum);
+        if (gpi == null)
+            {
+            KozaFitness fitness = (KozaFitness) (ind.fitness);
+            fitness.setStandardizedFitness(state, Float.MAX_VALUE);
+            } 
+        else
+            {
+            ((SimpleProblemForm)problem).evaluate(state, gpi, subpopulation, threadnum);
+            // Now we need to move the evaluated flag from the GPIndividual
+            // to the GEIndividual, and also for good measure, let's copy over
+            // the GPIndividual's fitness because even though the mapping function
+            // set the two Individuals to share the same fitness, it's possible
+            // that the evaluation function may have replaced the fitness.
+            ind.fitness = gpi.fitness;
+            ind.evaluated = gpi.evaluated;
+            }
+        }
+
+    public void describe(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum,
+        final int log)
+        {
+        GEIndividual indiv = (GEIndividual) ind;
+        GESpecies species = (GESpecies) (ind.species);
+        GPIndividual gpi = species.map(state, indiv, threadnum);
+        if (gpi != null)
+            {
+            problem.describe(state, gpi, subpopulation, threadnum, log);
+
+            // though this is probably not necessary for describe(...),
+            // for good measure we're doing the same rigamarole that we
+            // did for evaluate(...) above.
+            ind.fitness = gpi.fitness;
+            ind.evaluated = gpi.evaluated;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GESpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GESpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GESpecies.java	(revision 6152)
@@ -0,0 +1,423 @@
+/*
+  Copyright 20010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+package ec.gp.ge;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import ec.gp.*;
+import ec.*;
+import ec.vector.*;
+import ec.util.*;
+
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/*
+ * GESpecies.java
+ *
+ * Created: Sun Dec  5 11:33:43 EST 2010
+ * By: Eric Kangas, Joseph Zelibor III, Houston Mooers, and Sean Luke
+ *
+ */
+
+/**
+ * <p>GESpecies generates GPIndividuals from GEIndividuals through the application of a grammar parse graph
+ * computed by the GrammarParser.
+ *
+ * <p>GESpecies uses a <b>GrammarParser</b> to do its dirty work.  This parser's job is to take a grammar (in the form of a BufferedReader) 
+ * and convert it to a tree of GrammarNodes which define the parse graph of the grammar. The GESpecies then interprets his parse graph
+ * according to the values in the GEIndividual to produce the equivalent GPIndividual, which is then evaluated.
+ * 
+ * <p>To do this, GESpecies relies on a subsidiary GPSpecies which defines the GPIndividual and various GPFunctionSets from which to
+ * build the parser.  This is a grand hack -- the GPSpecies does not know it's being used this way, and so we must provide various dummy
+ * parameters to keep the GPSpecies happy even though they'll never be used.
+ *
+ * <p>If you are daring, you can replace the GrammarParser with one of your own to customize the parse structure and grammar.
+ * 
+ * <p><b>ECJ's Default GE Grammar</b>  GE traditionally can use any grammar, and builds parse graphs from that.  For simplicity, and in order to
+ * remain as compatable as possible with ECJ's existing GP facilities (and GP tradition), ECJ only uses a single Lisp-like grammar which
+ * generates standard ECJ trees.  This doesn't lose much in generality as the grammar is quite genral.
+ * 
+ * <p>The grammar assumes that expansion points are enclosed in &lt;> and functions are enclosed in ().  For example:
+ *
+ * <p><tt>
+ * # This is a comment
+ * &lt;prog> ::= &lt;op><br>
+ * &lt;op> ::= (if-food-ahead &lt;op> &lt;op>)<br>
+ * &lt;op> ::=  (progn2 &lt;op> &lt;op>)<br>
+ * &lt;op> ::= (progn3 &lt;op> &lt;op> &lt;op>)<br>
+ * &lt;op> ::= (left) | (right) | (move)<br>
+ * </tt>
+ * 
+ * <p>alternatively the grammar could also be writen in the following format:
+ * 
+ * <p><tt>
+ * &lt;prog> ::= &lt;op><br>
+ * &lt;op> ::= (if-food-ahead &lt;op> &lt;op>) | (progn2 &lt;op> &lt;op>) | (progn3 &lt;op> &lt;op> &lt;op>) | (left) | (right) | (move)<br>
+ * </tt>
+ *
+ * <p>Note that you can use several lines to define the same grammar rule: for example, <tt>&lt;op></tt> was defined by several lines when
+ * it could have consisted of several elements separated by vertical pipes ( <tt>|</tt> ).  Either way is fine, or a combination of both.
+ *
+ * <p>GPNodes are included in the grammar by using their name.  This includes ERCs, ADFs, ADMs, and ADFArguments, which should all work just fine.
+ * For example, since most ERC GPNodes are simply named "ERC", if you have only one ERC GPNode in your function set, you can just use <tt>(ERC)</tt>
+ * in your grammar.
+ *
+ * <p>Once the gammar file has been created and setup has been run trees can the be created using the genome (chromosome) of a GEIndividual.
+ * A genome of an individual is an array of random integers each of which are one byte long.  These numbers are used when a decision point 
+ * (a rule having more that one choice) is reached within the grammar.  Once a particular gene (index) in the genome has been used it will 
+ * not be used again (this may change) when creating the tree.
+ *
+ * <p>For example:<br>
+ * number of chromosomes used = 0<br>
+ * genome = {23, 654, 86}<br>
+ * the current rule we are considering is &lt;op>.<br>
+ * %lt;op> can map into one of the following: (if-food-ahead &lt;op> &lt;op>) | (progn2 &lt;op> &lt;op>) | (progn3 &lt;op> &lt;op> &lt;op>) 
+ * | (left) | (right) | (move)<br>
+ * Since the rule &lt;op> has more than one choice that it can map to, we must consult the genome to decide which choice to take.  In this case
+ * the number of chromosomes used is 0 so genome[0] is used and number of chromosomes used is incremented.  Since values in the genome can
+ * be negitive values they are offset by 128 (max negitive of a byte) giving us a value from 0-255.  A modulus is performed on this resulting 
+ * number by the number of choices present for the given rule.  In the above example since we are using genome[0] the resulting operation would 
+ * look like: 23+128=151, number of choices for &lt;op> = 6, 151%6=1 so we use choices[1] which is: (progn2 &lt;op> &lt;op>).  If all the genes
+ * in a genome are used and the tree is still incompete an invalid tree error is returned.
+ *
+ * <p>Each node in the tree is a GPNode and trees are constructed depth first. 
+ *
+ *
+ * <p><b>Parameters</b><br>
+ * <table>
+ * <tr><td valign=top><i>base.</i><tt>file</tt><br>
+ * <font size=-1>String</font></td>
+ * <td valign=top>(the file is where the rules of the gammar are stored)</td></tr>
+ * 
+ * <tr><td valign=top><i>base.</i><tt>gp-species</tt><br>
+ * <font size=-1>classname, inherits and != ec.gp.GPSpecies</font></td>
+ * <td valign=top>(the GPSpecies subservient to the GESpecies)</td></tr>
+ *
+ * <tr><td valign=top><i>base.</i><tt>parser</tt><br>
+ * <font size=-1>classname, inherits and != ec.gp.ge.GrammarParser</font></td>
+ * <td valign=top>(the GrammarParser used by the GESpecies)</td></tr>
+ *
+ * </table>
+ *
+ * <p><b>Default Base</b><br>
+ * ec.gp.ge.GESpecies
+ *
+ * @author Joseph Zelibor III, Eric Kangas, Houston Mooers, and Sean Luke
+ * @version 1.0 
+ */
+ 
+public class GESpecies extends IntegerVectorSpecies
+    {
+    public static final String P_GESPECIES = "species";
+    public static final String P_FILE = "file";
+    public static final String P_GPSPECIES = "gp-species";
+    public static final String P_PARSER = "parser";
+        
+    /* Return value which denotes that the tree has grown too large. */
+    public static final int BIG_TREE_ERROR = -1;
+        
+    /** The GPSpecies subsidiary to GESpecies. */
+    public GPSpecies gpspecies;
+
+    /** All the ERCs created so far. */
+    public HashMap ERCBank;
+
+    /** The parsed grammars. */
+    public GrammarRuleNode[] grammar;
+
+    /** The prototypical parser used to parse the grammars. */
+    public GrammarParser parser_prototype;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+
+        Parameter p = base;
+        Parameter def = defaultBase();
+
+        p = base.push(P_GPSPECIES);
+        gpspecies = (GPSpecies) (state.parameters.getInstanceForParameterEq(p, def.push(P_GPSPECIES), GPSpecies.class));
+        gpspecies.setup(state, p);
+
+        // check to make sure that our individual prototype is a GPIndividual
+        if (!(i_prototype instanceof ByteVectorIndividual))
+            {
+            state.output.fatal("The Individual class for the Species " + getClass().getName() + " is must be a subclass of ec.gp.ge.GEIndividual.", base);
+            }
+
+        ERCBank = new HashMap();
+
+        // load the grammars, one per ADF tree
+        GPIndividual gpi = (GPIndividual) (gpspecies.i_prototype);
+        GPTree[] trees = gpi.trees;
+        int numGrammars = trees.length;
+
+        parser_prototype = (GrammarParser) (state.parameters.getInstanceForParameterEq(base.push(P_PARSER), def.push(P_PARSER), GrammarParser.class));
+
+        grammar = new GrammarRuleNode[numGrammars];
+        for(int i = 0; i < numGrammars; i++)
+            {
+            p = base.push(P_FILE);
+            def = defaultBase();
+                        
+            File grammarFile = state.parameters.getFile(p, def.push(P_FILE).push("" + i));
+            if(grammarFile == null)
+                {
+                state.output.fatal("Error retrieving grammar file(s): " + def.toString() + "."+ P_FILE + "." + i + " is undefined.");
+                }
+
+            try
+                {
+                GPFunctionSet gpfs = trees[i].constraints((GPInitializer) state.initializer).functionset;
+                GrammarParser grammarparser = (GrammarParser)(parser_prototype.clone());
+                grammar[i] = grammarparser.parseRules(state, new BufferedReader(new FileReader(grammarFile)), gpfs);
+                }
+            catch (FileNotFoundException e)
+                {
+                state.output.fatal("Error retrieving grammar file(s): " + def.toString() + "."+ P_FILE + "." + i + " does not exist or cannot be opened.");
+                }
+            }
+        }
+
+
+    /**
+     * creates all of an individual's trees
+     * @param state Evolution state
+     * @param trees array of trees for the individual
+     * @param ind the GEIndividual
+     * @param threadnum tread number
+     * @return number of chromosomes consumed
+     */
+    public int makeTrees(EvolutionState state, GEIndividual ind, GPTree[] trees, int threadnum)
+        {
+        int position = 0;
+
+        for (int i = 0; i < trees.length; i++)
+            {
+            //cannot complete one of the trees with the given chromosome
+            if(position < 0)
+                return BIG_TREE_ERROR;
+
+            position = makeTree(state, ind, trees[i], position, i, threadnum);
+            }
+
+        return position;
+        }
+
+    /**
+     * makeTree, edits the tree that its given by adding a root (and all subtrees attached)
+     * @param state
+     * @param ind
+     * @param tree
+     * @param position 
+     * @param treeNum
+     * @param threadnum
+     * @return the number of chromosomes used, or an BIG_TREE_ERROR sentinel value.
+     */
+    public int makeTree(EvolutionState state, GEIndividual ind, GPTree tree, int position, int treeNum, int threadnum)
+        {
+        int[] countNumberOfChromosomesUsed = {  position  };  // hack, use an array to pass an extra value
+        byte[] genome = ind.genome;
+        GPFunctionSet gpfs = tree.constraints((GPInitializer) state.initializer).functionset;
+        GPNode root;
+
+        try // get the tree, or return an error.
+            {
+            root = makeSubtree(countNumberOfChromosomesUsed, genome, state, gpfs, grammar[treeNum], treeNum, threadnum);
+            } 
+        catch (BigTreeException e)
+            {
+            return BIG_TREE_ERROR;
+            }
+
+        if(root == null)
+            {
+            state.output.fatal("Invalid tree: tree #" + treeNum);
+            }
+
+        root.parent = tree;
+        tree.child = root;
+        return countNumberOfChromosomesUsed[0];
+        }
+
+    // thrown by makeSubtree when chromosome is not large enough for the generated tree.
+    class BigTreeException extends RuntimeException { static final long serialVersionUID = 1L; }
+
+    GPNode makeSubtree(int[] index, byte[] genome, EvolutionState es, GPFunctionSet gpfs, GrammarRuleNode rule, int treeNum, int threadnum)
+        {
+        //have we exceeded the length of the genome?  No point in going further.
+        if (index[0] >= genome.length)
+            {
+            throw new BigTreeException();
+            }
+
+        //expand the rule with the chromosome to get a body element
+        int i;
+
+        //key for ERC hashtable look ups is the current index within the genome
+        int key = genome[index[0]];
+
+        //non existant rule got passed in
+        if (rule == null)
+            {
+            es.output.fatal("An undefined rule exists within the grammar.");
+            }
+
+        //more than one rule to consider, pick one based off the genome, and consume the current gene
+        if (rule.getNumChoices() > 1)
+            {
+            //casting to an int should be ok since the biggest these genes can be is a byte
+            i = ((genome[index[0]]) - ((int)(this.minGene(index[0])))) % rule.getNumChoices();
+            index[0]++;
+            }
+        //only 1 rule to consider
+        else
+            {
+            i = 0;
+            }               
+        GrammarNode choice = rule.getChoice(i);         
+
+        // if body is another rule head
+        //look up rule
+        if(choice instanceof GrammarRuleNode)
+            {
+            GrammarRuleNode nextrule = (GrammarRuleNode) choice;
+            return makeSubtree(index, genome, es, gpfs, nextrule, treeNum, threadnum);
+            }                               
+        else //handle functions
+            {
+            GrammarFunctionNode funcgrammarnode = (GrammarFunctionNode) choice;
+
+            GPNode validNode = funcgrammarnode.getGPNodePrototype();
+
+            int numChildren = validNode.children.length;
+            //index 0 is the node itself
+            int numChildrenInGrammar = funcgrammarnode.getNumArguments();
+
+            //does the grammar contain the correct amount of children that the GPNode requires
+            if (numChildren != numChildrenInGrammar)
+                {
+                es.output.fatal("GPNode " + validNode.toStringForHumans() + " requires " + numChildren + " children.  "
+                    + numChildrenInGrammar + " children found in the grammar.");
+                }
+
+            //check to see if it is an ERC node
+            if (validNode instanceof ERC)
+                {                
+                validNode = obtainERC(es, key, genome, threadnum, validNode);
+                }
+            //non ERC node
+            else
+                {
+                validNode = validNode.lightClone();
+                }
+
+            //get the rest.
+            for (int j = 0, childNumber = 0; j < funcgrammarnode.getNumArguments(); j++)
+                {
+                //get and link children to the current GPNode
+                validNode.children[childNumber] = makeSubtree(index, genome, es, gpfs, (GrammarRuleNode)funcgrammarnode.getArgument(j), treeNum, threadnum);
+                if (validNode.children[childNumber] == null)
+                    {
+                    return null;
+                    }
+                childNumber++;
+                }
+            return validNode;
+            }
+        }
+
+    /** Loads an ERC from the ERCBank given the value in the genome.  If there is no such ERC, then one is created and randomized, then added to the bank.
+        The point of this mechanism is to enable ERCs to appear in multiple places in a GPTree. */
+    public GPNode obtainERC(EvolutionState state, int key, byte[] genome, int threadnum, GPNode node)
+        {
+        ArrayList ERCList = (ArrayList) (ERCBank.get(new Integer(key)));
+
+        if (ERCList == null)
+            {
+            ERCList = new ArrayList();
+            ERCBank.put(new Integer(key), ERCList);
+            }
+
+        GPNode dummy = null;
+
+        // search array list for an ERC of the same type we want
+        for (int i = 0; i < ERCList.size(); i++)
+            {
+            dummy = (GPNode) ERCList.get(i);
+
+            // ERC was found inside the arraylist
+            if (dummy.nodeEquivalentTo(node))
+                {
+                return dummy.lightClone();
+                }
+            }
+
+        // erc was not found in the array list lets make one
+        node = node.lightClone();
+        node.resetNode(state, threadnum);
+        ERCList.add(node);
+
+        return node;
+        }
+
+    public Object clone()
+        {
+        GESpecies other = (GESpecies) (super.clone());
+        other.gpspecies = (GPSpecies) (gpspecies.clone());
+        return other;
+        }
+
+    public Parameter defaultBase()
+        {
+        return GEDefaults.base().push(P_GESPECIES);
+        }
+
+    /** Returns the number of elements consumed from the GEIndividual array to produce
+        the tree, else returns -1 if an error occurs, specifically if all elements were
+        consumed and the tree had still not been completed. */
+    public int consumed(EvolutionState state, GEIndividual ind, int threadnum)
+        {
+        // create a dummy individual
+        GPIndividual newind = ((GPIndividual) (gpspecies.i_prototype)).lightClone();
+
+        // do the mapping and return the number consumed
+        return makeTrees(state, ind, newind.trees, threadnum);
+        }
+
+    /** Returns a dummy GPIndividual with a single tree which was built by mapping
+        over the elements of the given GEIndividual.  Null is returned if an error occurs,
+        specifically, if all elements were consumed and the tree had still not been completed. */
+    public GPIndividual map(EvolutionState state, GEIndividual ind, int threadnum)
+        {
+        // create a dummy individual
+        GPIndividual newind = ((GPIndividual) (gpspecies.i_prototype)).lightClone();
+
+        // Do NOT initialize its trees
+
+        // Set the fitness to the ByteVectorIndividual's fitness
+        newind.fitness = ind.fitness;
+        newind.evaluated = false;
+
+        // Set the species to me
+        newind.species = gpspecies;
+
+        // do the mapping
+        if (makeTrees(state, ind, newind.trees, threadnum) < 0)  // error
+            return null;
+        else
+            return newind;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarFunctionNode.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarFunctionNode.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarFunctionNode.java	(revision 6152)
@@ -0,0 +1,63 @@
+package ec.gp.ge;
+import java.util.*;
+import ec.gp.*;
+
+/*
+ * GrammarFunctionNode.java
+ *
+ * Created: Sun Dec  5 11:33:43 EST 2010
+ * By: Houston Mooers and Sean Luke
+ *
+ */
+
+/**
+ * A GrammarNode representing a GPNode in the GE Grammar.  The head of the GrammarFunctionNode
+ * is the name of the GPNode in the grammar; and the children are various arguments to the node
+ * as defined by the grammar.  These are returned  by getArgument(...) and getNumArguments().
+ * The GrammarFunctionNode holds a prototypical GPNode from which clones can be made.
+ * 
+ */
+
+public class GrammarFunctionNode extends GrammarNode 
+    {
+    GPNode prototype;
+
+    /** Determines the GPNode from the function set by the name.  If there is more than
+        one such node (which shouldn't be the case) then only the first such node is
+        used.  Stores the prototype. */
+                
+    public GrammarFunctionNode(GPFunctionSet gpfs, String name)
+        {
+        super(name);
+        prototype = ((GPNode[]) (gpfs.nodesByName.get(name)))[0];
+        }
+        
+    /** Adds a given argument to the node. */
+    public void addArgument(GrammarNode arg)
+        {
+        children.add(arg);
+        }
+        
+    /** Returns the number of arguments. */
+    public int getNumArguments() { return children.size(); }
+
+    /** Returna given argument. */
+    public GrammarNode getArgument(int index) { return (GrammarNode)(children.get(index)); }       
+
+    /** Returns the prototype without cloning it first.  Be certain to clone before using. */
+    public GPNode getGPNodePrototype() { return prototype; }
+
+    public String toString()
+        {
+        String ret = "(" + head + " ";
+        Iterator i = children.iterator();
+        boolean first = true;
+        while(i.hasNext())
+            {
+            ret = ret + (first ? "" : " ") + ((GrammarNode)(i.next())).getHead();
+            first = false;
+            }
+        return ret + ")";
+        }
+        
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarNode.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarNode.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarNode.java	(revision 6152)
@@ -0,0 +1,30 @@
+package ec.gp.ge;
+import java.util.*;
+
+/*
+ * GrammarNode.java
+ *
+ * Created: Sun Dec  5 11:33:43 EST 2010
+ * By: Houston Mooers and Sean Luke
+ *
+ */
+
+/**
+ * The abstract superclass of nodes used by GrammarParser to construct a parse graph to generate
+ * GEIndividuals.  GrammarNode has a *head*, which typically holds the name of the node,
+ * and an array of *children*, which are themselves GrammarNodes.
+ * 
+ */
+
+public abstract class GrammarNode
+    {
+    String head;
+    protected ArrayList children = new ArrayList();  // may be empty but it's not very expensive
+        
+    public GrammarNode(String head)
+        {
+        this.head = head;
+        }
+                
+    public String getHead() { return head; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarParser.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarParser.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarParser.java	(revision 6152)
@@ -0,0 +1,261 @@
+package ec.gp.ge;
+import java.io.*;
+import java.util.*;
+import ec.*;
+import ec.gp.GPFunctionSet;
+import ec.gp.GPNode;
+import ec.util.*;
+
+/*
+ * GrammarParser.java
+ *
+ * Created: Sun Dec  5 11:33:43 EST 2010
+ * By: Houston Mooers, with modifications by Sean Luke
+ *
+ */
+
+/**
+ * A GrammarParser is the basic class for parsing a GE ruleset into a parse graph of GrammarNodes.
+ * This parse graph is then later used to produce a GPIndividual from a GEIndividual in GESpecies.
+ * It is assumed that the root will represent the first rule given in the grammar.
+ * 
+ */
+
+
+
+public class GrammarParser implements Prototype
+    {
+    public static final String P_PARSER = "parser";
+
+    // The parsed rules, hashed by name
+    HashMap rules = new HashMap();
+    // The resulting parse graph
+    GrammarRuleNode root = null;
+
+    /** The default regular expressions for tokens in the parser.  If you'd
+        like to change minor features of the regular expressions, override the
+        getRegexes() method in a subclass to return a different array.  Note that
+        if you INSERT a new regular expression into the middle of these, the values
+        of the various token constants ("LPAREN", "RULE", etc.) will be wrong, so you
+        will need to override or modify the methods which use them.*/ 
+    public static final String[] DEFAULT_REGEXES = new String[]
+    {
+    "\\p{Blank}*#[^\\n\\r]*",               // COMMENT: matches a #foo up to but not including the newline.  Should appear first.
+    "\\p{Blank}*\\(",                       // LPAREN: matches a (
+    "\\p{Blank}*\\)",                       // RPAREN: matches a )
+    "\\p{Blank}*<[^<>()\\p{Space}]*>",      // RULE: matches a rule of the form <foo>.  No <, >, (, ), |, or spaces may appear in foo
+    "\\p{Blank}*[|]",                       // PIPE: matches a |
+    "\\p{Blank}*::=",                       // EQUALS: matches a :==
+    "\\p{Blank}*::=",                       // NUMERIC_CONSTANT: does nothing right now, so set to be identical to EQUALS.  Reserved for future use.
+    "\\p{Blank}*::=",                       // BOOLEAN_CONSTANT: does nothing right now, so set to be identical to EQUALS.  Reserved for future use.
+    "\\p{Blank}*::=",                       // STRING_CONSTANT: does nothing right now, so set to be identical to EQUALS.  Reserved for future use.
+    "\\p{Blank}*[^<>()|\\p{Space}]+",       // FUNCTION (must appear after RULE and PIPE): matches a rule of the form foo.  No <, >, (, ), |, or spaces may appear in foo, and foo must have at least one character.
+    };
+        
+    protected static final int COMMENT = 0;
+    protected static final int LPAREN = 1;
+    protected static final int RPAREN = 2;
+    protected static final int RULE = 3;
+    protected static final int PIPE = 4;
+    protected static final int EQUALS = 5;
+    // the following three are reserved for future use
+    protected static final int NUMERIC_CONSTANT = 6;
+    protected static final int BOOLEAN_CONSTANT = 7;
+    protected static final int STRING_CONSTANT = 8;
+    // and now we continue with our regularly scheduled program
+    protected static final int FUNCTION = 9;
+        
+    /** Returns the regular expressions to use for tokenizing these rules.  By default DEFAULT_REGEXES are returned. */
+    public String[] getRegexes() { return DEFAULT_REGEXES; }
+        
+    public Parameter defaultBase()
+        {
+        return GEDefaults.base().push(P_PARSER);
+        }
+
+    public void setup(EvolutionState state, Parameter base)
+        {
+        }
+
+    public Object clone()
+        {
+        try 
+            {
+            GrammarParser other = (GrammarParser) (super.clone());
+            other.rules = (HashMap)(rules.clone());
+            // we'll pointer-copy the root
+            return other;
+            }
+        catch (CloneNotSupportedException e) { return null; } // never happens
+        }
+
+    // Returns a rule from the hashmap.  If one does not exist, creates a rule with the
+    // given head and stores, then returns that.
+    GrammarRuleNode getRule(HashMap rules, String head)
+        {
+        if (rules.containsKey(head))
+            return (GrammarRuleNode)(rules.get(head));
+        else
+            {
+            GrammarRuleNode node = new GrammarRuleNode(head);
+            rules.put(head, node);
+            return node;
+            }
+        }
+
+    // Parses a rule, one rule per line, from the lexer.  Adds to the existing hashmap if there's already a rule there.
+    GrammarRuleNode parseRule(EvolutionState state, Lexer lexer, GPFunctionSet gpfs)
+        {
+        GrammarRuleNode retResult = null;
+                
+        String token = lexer.nextToken();
+        if(lexer.getMatchingIndex() == COMMENT) return null; //ignore the comment
+        if(lexer.getMatchingIndex() == RULE) //rule head, good, as expected...
+            {
+            lexer.nextToken();
+            if(lexer.getMatchingIndex() != EQUALS) 
+                {
+                state.output.fatal("GE Grammar Error: Expecting equal sign after rule head: " + token);
+                }
+            retResult = getRule(rules, token);
+            parseProductions(state, retResult, lexer, gpfs);
+            }
+        else
+            {
+            state.output.fatal("GE Grammar Error - Unexpected token: Expecting rule head.: " + token);
+            }
+        return retResult;
+        // IMPLEMENTED
+        // Need to parse the rule using a recursive descent parser
+        // If there was an error, then try to call state.output.error(...).
+        //
+        // Don't merge into any existing rule -- I do that in parseRules below.  Instead, just pull out
+        // rules and hang them into your "new rule" as necessary.  
+        // Use getRule(rules, "<rulename>") to extract the rule representing the current rule name which you
+        // can hang inside there as necessary. 
+        //
+        // If you have to you can call state.output.fatal(...) which will terminate the program,
+        // but piling up some errors might be useful.  I'll handle the exitIfErors() in parseRules below
+        //
+        // Return null if there was no rule to parse (blank line or all comments) but no errors.
+        // Also return null if you called state.output.error(...).
+        }
+
+    // Parses each of a rule's production choices.
+    void parseProductions(EvolutionState state, GrammarRuleNode retResult, Lexer lexer, GPFunctionSet gpfs) 
+        {
+        GrammarFunctionNode grammarfuncnode;
+        do 
+            {
+            String token = lexer.nextToken();
+            if(lexer.getMatchingIndex() == RULE)
+                {
+                retResult.addChoice(getRule(rules, token));
+                token = lexer.nextToken();
+                }
+            else
+                {
+                if(lexer.getMatchingIndex() != LPAREN) //first expect '('
+                    {
+                    state.output.fatal("GE Grammar Error - Unexpected token for rule: " + retResult.getHead() + "Expecting '('.");
+                    }
+                token = lexer.nextToken();
+                if(lexer.getMatchingIndex() != FUNCTION) //now expecting function
+                    {
+                    state.output.fatal("GE Grammar Error - Expecting a function name after first '(' for rule: " + retResult.getHead() + " Error: " + token);
+                    }
+                else
+                    {
+                    if (!(gpfs.nodesByName.containsKey(token)))
+                        {
+                        state.output.fatal("GPNode " + token + " is not defined in the function set.");
+                        }
+                    grammarfuncnode = new GrammarFunctionNode(gpfs, token); 
+                    token = lexer.nextToken(); 
+                    while(lexer.getMatchingIndex() != RPAREN)
+                        {
+                        if(lexer.getMatchingIndex() != RULE) //this better be the name of a rule node
+                            {
+                            state.output.fatal("GE Grammar Error - Expecting a rule name as argument for function definition: " + grammarfuncnode.getHead() + " Error on : " + token);
+                            }
+                        grammarfuncnode.addArgument(getRule(rules, token));
+                        token = lexer.nextToken();
+                        }
+                    retResult.addChoice(grammarfuncnode);
+                    }
+                //after right paren, should see either '|' or newline
+                token = lexer.nextToken();
+                if(lexer.getMatchingIndex() != PIPE && lexer.getMatchingIndex() != Lexer.FAILURE)
+                    {
+                    state.output.fatal("GE Grammar Error - Expecting either '|' delimiter or newline. Error on : " + token);
+                    }
+                }
+            }
+        while(lexer.getMatchingIndex() == PIPE);
+        }
+
+    /** Parses the rules from a grammar and returns the resulting GrammarRuleNode root. */
+    public GrammarRuleNode parseRules(EvolutionState state, BufferedReader reader, GPFunctionSet gpfs)
+        {
+        rules = new HashMap();
+        try
+            {
+            String line;
+            while ((line = reader.readLine()) != null)
+                {
+                GrammarRuleNode rule = parseRule(state, new Lexer(line.trim(), DEFAULT_REGEXES), gpfs);
+                if (rule != null && root == null) root = rule;
+                }
+            }
+        catch (IOException e) { } // do nothing
+        state.output.exitIfErrors();
+        return root;
+        }
+
+    public String toString()
+        {
+        String ret = "Grammar[";
+        Iterator i = rules.values().iterator();
+        while(i.hasNext())
+            {
+            ret = ret +"\n" + i.next();
+            }
+        return ret + "\n\t]";
+        }
+
+    /**
+     * Checks that all grammar rules in ruleshashmap have at least one possible production
+     * @return true if grammar rules are properly defined, false otherwise
+     */
+    public boolean validateRules()
+        {
+        boolean isok = true;
+        Iterator i = rules.values().iterator();
+        while(i.hasNext())
+            {
+            GrammarRuleNode rule = (GrammarRuleNode)(i.next());
+            if(rule.getNumChoices() < 1)
+                {
+                System.out.println("Grammar is bad! - Rule not defined: " + rule);
+                isok = false;
+                }
+            }
+        if (isok) { System.out.println("All rules appear properly defined!"); return true; }            
+        return false;
+        }
+
+    /** A simple testing fcility. */
+    public static void main(String args[]) throws  FileNotFoundException
+        {
+        // make a dummy EvolutionState that just has an output for testing
+        EvolutionState state = new EvolutionState();
+        state.output = new Output(true);
+        state.output.addLog(ec.util.Log.D_STDOUT,false);
+        state.output.addLog(ec.util.Log.D_STDERR,true);
+
+        GrammarParser gp = new GrammarParser();
+        gp.parseRules(state, new BufferedReader(new FileReader(new File(args[0]))), null);
+        gp.validateRules();
+        System.err.println(gp);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarRuleNode.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarRuleNode.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/GrammarRuleNode.java	(revision 6152)
@@ -0,0 +1,61 @@
+package ec.gp.ge;
+import java.util.*;
+
+/*
+ * GrammarRuleNode.java
+ *
+ * Created: Sun Dec  5 11:33:43 EST 2010
+ * By: Houston Mooers and Sean Luke
+ *
+ */
+
+/**
+ * A GrammarNode representing a Rule in the GE Grammar.  The head of the GrammarRuleNode
+ * is the name of the rule; and the children are the various choices.  These are returned
+ * by getChoice(...) and getNumChoices().  The merge(...) method unifies this GrammarRuleNode
+ * with the choices of another node.
+ * 
+ */
+
+public class GrammarRuleNode extends GrammarNode 
+    {      
+    public GrammarRuleNode(String head)
+        {
+        super(head);
+        }
+        
+    /** Adds a choice to the children of this node. */
+    public void addChoice(GrammarNode choice)
+        {
+        children.add(choice);
+        }
+        
+    /** Returns the current number of choices to the node. */
+    public int getNumChoices() { return children.size(); }
+        
+    /** Returns a given choice. */
+    public GrammarNode getChoice(int index) { return (GrammarNode)(children.get(index)); }
+
+    /** Adds to this node all the choices of another node. */
+    public void merge(GrammarRuleNode other)
+        {
+        int n = other.getNumChoices();
+        for(int i = 0 ; i < n; i++)
+            addChoice(other.getChoice(i));
+        }
+
+    public String toString()
+        {
+        String ret = "" + head + " ::= ";
+        Iterator i = children.iterator();
+        boolean first = true;
+        while(i.hasNext())
+            {
+            ret = ret + (first ? "" : "| ") + ((GrammarNode)(i.next())).getHead();
+            first = false;
+            }
+        return ret;
+        }
+        
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/README	(revision 6152)
@@ -0,0 +1,145 @@
+This package defines ECJ's Grammatical Evolution package.
+
+Grammatical Evolution uses an arbitrarily-long integer list representation.
+An individual is evaluated by taking the list and interpreting it according
+to a grammar to produce (in the case of ECJ) a GP tree-style Individual, which 
+is then evaluated.  The fitness of the GP individual becomes the fitness of
+the Grammatical Evolution list representation individual
+
+Grammatical Evolution's mapping from list to tree uses a grammar file
+specified in GESpecies.  The grammar file defines the grammar for the tree.
+Here is a very simple example for Artificial Ant:
+
+<prog> ::= <op>
+<op> ::= (if-food-ahead <op> <op>) 
+<op> ::=  (progn2 <op> <op>) 
+<op> ::= (progn3 <op> <op> <op>)
+<op> ::= (left) | (right) | (move)  
+
+We say this is simple because practically the only expanded variable name is
+<op>.  This doesn't have to be the case -- a GE grammar can have a rich collection
+of expanded variables.  Grammatical Evolution's use of a grammar in fact allows
+it to define a fairly complex type system that's not easy to replicate with ECJ's
+(or GP in general) standard typing options.
+
+The mapping works as follows.  We start with the first variable (in this case,
+<prog>.  It expands solely to <op>.  Now we have a choice -- what should <op>
+expand to?  There are six choices from the grammar above.  To make the decision,
+we consult the first number in the GE Individual, mod 6.  That result is our
+expansion.  We then proceed to expand each of the new elements: for example,
+if <op> had expanded to (if-food-ahead <op> <op>), we now have two new <op>s
+to expand.  We proceed depth-first, each time consulting the next number in
+the GE Individual.  When the GPTree is completed and there are no more
+expansions, it's handed to a GPProblem to be tested.
+
+If the Individual doesn't have enough integers to cover all the needs of
+the grammar, it is considered to be a "bad" Individual and is given a poor
+fitness.
+
+Thus a Grammatical Evolution problem requires several pieces:
+
+1. A grammar file to interpret by.
+2. A GEIndividual (basically a ByteVectorIndividual) to hold the numbers.
+3. A GESpecies to load the grammar and be available to perform the mapping
+   from GEIndividual to GPIndividual.
+4. A GEProblem to take a GEIndividual, map it through the GEPSpecies, and
+   hand it off to a GPProblem to be tested.
+5. A GPProblem to do the testing.
+
+Grammatical Evolution can handle ERCs and ADFs as well.  To handle the multiple
+trees required by an ADF, we provide multiple grammar files.  See the Lawnmower
+example (ec/app/lawnmower) for a demonstration.
+
+Grammatical Evolution requires quite a lot of manipulation of the GP subsystem
+to pull all this off.  Notably:
+
+1. The problem will be a GEProbem.  It in turn holds onto the "true" GPProblem
+   in a 'problem' parameter
+2. The species will be a GESpecies.  It in turn holds onto the "true" GPSpecies
+   in a 'gp-species' parameter.
+
+Generally Grammatical Evolution is surprisingly easy to implement in ECJ.  The 
+ec/gp/ge/ge.params file will do most of the heavy lifting for you if you're dealing
+with just a single tree (no ADFs say).  But in some cases we'll need to add 
+special GP elements to this subsidiary GPSpecies, mostly for additiona trees.
+For example, in the Lawnmower problem, to have three trees, we need to define
+them manually as shown in ec/app/lawnmower/ge.params
+
+Grammatical Evolution has two common breeding operators for its lists of
+integers:
+
+- TRUNCATION: Integers unused during the mapping process are later chopped off
+  the end of the Individual.
+
+- GENE DUPLICATION: A string of integers in the list is copied and reinserted
+  "downstream" in the list.  This is implemented elsehwere by the class 
+  ec/vector/breed/GeneDuplicationPipeline
+
+To this any number of other list crossover and mutation operators could be used.
+NOTE that the pipeline defined in ge.params is pretty arbitrary -- you might want
+to build something better.
+
+
+
+EXAMPLES
+
+See the ec/app/ant, ec/app/regression, and ec/app/lawnmower directories for
+GE versions of these GP problems.
+
+
+
+CLASSES
+
+
+GEIndividual.java
+
+This class is just a simple subclass of ByteVectorIndividual which also prints out
+the tree form of the Individual.
+
+
+GESpecies.java
+
+A version of IntegerVectorSpecies which loads the grammar file or files, holds onto
+the GPSpecies, and performs the actual mapping prior to evaluation of GEIndividuals.
+
+
+GrammarParser.java
+
+The parser which reads the grammar rules from the provided grammar files and converts
+them into a parse graph.  This parse graph is then what's actually used by GESpecies
+to map GEIndividuals into GPIndividuals.  You can replace this parser with one of your
+own.
+
+
+GrammarNode.java
+GrammarFunctionNode.java
+GrammarRuleNode.java
+
+These form the actual objects in the parse graph.  GrammarNode is an abstract superclass.
+GrammarFunctionNode defines functions with arguments (its children).  GrammarRuleNode
+defines rules with rule options (its children).
+
+
+GEProblem.java
+
+A version of Problem which is inserted in lieu of the GPProblem, and which in turn
+holds onto the GPProblem.  The GEProblem first maps the GEIndividual into a GPIndividual
+using the GESpecies.  It then hands the GPIndividual to the GPProblem to be evaluated.
+
+
+[in the ec.gp.ge.breed subpackage] 
+
+GETruncationPipeline.java
+
+A special list operator which only works with GEIndividuals.  Truncates from the 
+list all those integers which weren't used during the mapping process.
+
+
+[elsewhere in the ec.vector.breed package]
+
+GeneDuplicationPipeline.java
+
+A special list operator which duplicates genes downstream.  Generally used by
+GEIndividuals but it's available in ec.vector.breed because it can be used by any
+VectorIndividual if you'd really want to.
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/breed/GETruncationPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/breed/GETruncationPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/breed/GETruncationPipeline.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.gp.ge.breed;
+import ec.gp.ge.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GEProblem.java
+ * 
+ * Created: Sat Oct 16 23:21:01 EDT 2010
+ * By: Sean Luke, Joseph Zelibor III, and Eric Kangas
+ */
+
+
+/**
+ * <p>GETruncationPipeline removes the unused genes from the end of the vector.
+ * The number of used chromosomes are tracked by GESpecies' <b>comsumed(...)</b> function.
+ *
+ * Note: truncaton only occurs if the number of comsumed genes is greater than 1.</p>
+ *
+ * <p><b>Default Base</b><br>
+ * ec.gp.ge.breed.GETruncationPipeline
+ *
+ * @author Sean Luke, Joseph Zelibor III, and Eric Kangas
+ * @version 1.0
+ */
+ 
+public class GETruncationPipeline extends BreedingPipeline
+    {
+    public static final String P_TRUNCATION = "truncate";
+    public static final int NUM_SOURCES = 1;
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Parameter defaultBase()
+        {
+        return GEDefaults.base().push(P_TRUNCATION);
+        }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            if (sources[0] instanceof SelectionMethod)
+                inds[q] = (Individual)(inds[q].clone());
+
+            GEIndividual ind = (GEIndividual)(inds[q]);
+            GESpecies species = (GESpecies) (ind.species);
+
+            int consumed = species.consumed(state, ind, thread);
+            if (consumed > 1)
+                {
+                Object[] pieces = new Object[2];
+                //System.err.println(consumed);
+                ind.split(new int[] { consumed }, pieces);
+                ind.join(new Object[] {pieces[0]});
+                }
+            }
+        return n;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/breed/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/breed/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/breed/README	(revision 6152)
@@ -0,0 +1,2 @@
+This package holds breeding operators special to Grammatical Evolution.
+See the README in the parent directory for more information.
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/ge.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/ge.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/ge/ge.params	(revision 6152)
@@ -0,0 +1,89 @@
+
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# We don't include koza.params as a parent here -- doing so creates
+# lots of parameter file inheritance problems.  Instead you should
+# include this parameter file FIRST, and then include something 
+# which ultimately includes the koza.params parameter file later.
+
+
+# The problem is redefined as a GEProblem.  The ACTUAL problem
+# will be defined in eval.problem.problem
+
+eval.problem = ec.gp.ge.GEProblem
+
+# We first define the GESpecies and state that it uses a GrammarParser
+# by default.
+
+pop.subpop.0.species = ec.gp.ge.GESpecies
+pop.subpop.0.species.parser = ec.gp.ge.GrammarParser
+
+# The individual is a GEIndividual
+pop.subpop.0.species = ec.gp.ge.GESpecies
+pop.subpop.0.species.ind = ec.gp.ge.GEIndividual
+pop.subpop.0.species.fitness = ec.gp.koza.KozaFitness
+
+# We'll allow 256 possibilities per gene (the maximum anyway
+# since GEIndividual is a ByteVectorIndividual).  Crossover-type
+# is entirely unused.
+pop.subpop.0.species.min-gene = -128
+pop.subpop.0.species.max-gene = 127
+pop.subpop.0.species.mutation-prob = 0.01
+# This isn't used at all but we include it here to quiet a warning from ECJ
+pop.subpop.0.species.crossover-type = one
+
+
+# Individuals are built using geometric series.  The minimum allowed
+# size is 5. 
+pop.subpop.0.species.genome-size = geometric
+pop.subpop.0.species.geometric-prob = 0.85
+pop.subpop.0.species.min-initial-size = 5
+
+
+# The following pipeline is fairly arbitrary.  You may wish to create
+# your own pipeline instead.
+
+pop.subpop.0.species.pipe = ec.breed.MultiBreedingPipeline
+pop.subpop.0.species.pipe.num-sources = 3
+
+pop.subpop.0.species.pipe.source.0 = ec.vector.breed.ListCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = ec.gp.ge.breed.GETruncationPipeline
+pop.subpop.0.species.pipe.source.0.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = same
+pop.subpop.0.species.pipe.source.0.prob = 0.2
+
+pop.subpop.0.species.pipe.source.1 = ec.vector.breed.GeneDuplicationPipeline
+pop.subpop.0.species.pipe.source.1.source.0 = ec.gp.ge.breed.GETruncationPipeline
+pop.subpop.0.species.pipe.source.1.source.0.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.1.prob = 0.55
+
+pop.subpop.0.species.pipe.source.2 = ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.2.source.0 = ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.2.prob = 0.05
+
+# This does a nice job but we're getting rid of it for now
+#breed.elite.0 = 1
+
+select.tournament.size = 7
+
+
+
+
+
+# Build the dummy GP Individual information.  This stuff is necessary to convince
+# GP that all is well and good with the trees that GE is creating and handing to
+# GP to evaluate.
+
+pop.subpop.0.species.gp-species = ec.gp.GPSpecies
+pop.subpop.0.species.gp-species.fitness = ec.gp.koza.KozaFitness
+pop.subpop.0.species.gp-species.ind = ec.gp.GPIndividual
+pop.subpop.0.species.gp-species.ind.numtrees = 1
+pop.subpop.0.species.gp-species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.gp-species.ind.tree.0.tc = tc0
+# We'll never use this, so let's set it to Reproduction, which is simple
+pop.subpop.0.species.gp-species.pipe = ec.breed.ReproductionPipeline
+pop.subpop.0.species.gp-species.pipe.num-sources = 1
+pop.subpop.0.species.gp-species.pipe.source.0 = ec.select.TournamentSelection
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/gp.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/gp.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/gp.params	(revision 6152)
@@ -0,0 +1,50 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+
+# This parameter file extends simple to provide some GP-specific stuff.
+# Default type constraints are given for typeless GP programming also.
+#
+
+
+# My parent:
+parent.0 =				../simple/simple.params
+
+
+# ec.gp.GPData
+# ==============================
+
+# set this elsewhere!
+# gp.gpdata =
+
+
+# ec.Subpopulation
+# ==============================
+
+# You might change this, but it must be a GPSpeciesForm!
+pop.subpop.0.species = 			ec.gp.GPSpecies
+
+# ec.Species
+# ==============================
+
+pop.subpop.0.species.ind = 		ec.gp.GPIndividual
+
+#You need to provide a basic pipe -- if you want to pick from among
+#pipes (like Koza does, 10% reproduction and 90% crossover), see
+#ec.breed.MultiBreedingPipeline
+#pop.subpop.0.species.pipe =
+#...
+
+
+# ec.GPIndividual
+# ==============================
+
+# We'll define a single tree -- you might want to change its class
+pop.subpop.0.species.ind.numtrees =	1
+pop.subpop.0.species.ind.tree.0 =	ec.gp.GPTree
+
+
+# ec.GPTree
+# ==============================
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/CrossoverPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/CrossoverPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/CrossoverPipeline.java	(revision 6152)
@@ -0,0 +1,436 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * CrossoverPipeline.java
+ * 
+ * Created: Mon Aug 30 19:15:21 1999
+ * By: Sean Luke
+ */
+
+
+/**
+ * CrossoverPipeline is a GPBreedingPipeline which performs a strongly-typed
+ * version of 
+ * Koza-style "Subtree Crossover".  Two individuals are selected,
+ * then a single tree is chosen in each such that the two trees
+ * have the same GPTreeConstraints.  Then a random node is chosen
+ * in each tree such that the two nodes have the same return type.
+ * If by swapping subtrees at these nodes the two trees will not
+ * violate maximum depth constraints, then the trees perform the
+ * swap, otherwise, they repeat the hunt for random nodes.
+ *
+ * <p>The pipeline tries at most <i>tries</i> times to a pair
+ * of random nodes BOTH with valid swap constraints.  If it
+ * cannot find any such pairs after <i>tries</i> times, it 
+ * uses the pair of its last attempt.  If either of the nodes in the pair
+ * is valid, that node gets substituted with the other node.  Otherwise
+ * an individual invalid node isn't changed at all (it's "reproduced").
+ *
+ * <p><b>Compatibility with constraints.</b> 
+ * Since Koza-I/II only tries 1 time, and then follows this policy, this is
+ * compatible with Koza.  lil-gp either tries 1 time, or tries forever.
+ * Either way, this is compatible with lil-gp.  My hacked 
+ * <a href="http://www.cs.umd.edu/users/seanl/gp/">lil-gp kernel</a>
+ * either tries 1 time, <i>n</i> times, or forever.  This is compatible
+ * as well.
+ *
+ * <p>This pipeline typically produces up to 2 new individuals (the two newly-
+ * swapped individuals) per produce(...) call.  If the system only
+ * needs a single individual, the pipeline will throw one of the
+ * new individuals away.  The user can also have the pipeline always
+ * throw away the second new individual instead of adding it to the population.
+ * In this case, the pipeline will only typically 
+ * produce 1 new individual per produce(...) call.
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ 2 * minimum typical number of individuals produced by each source, unless tossSecondParent
+ is set, in which case it's simply the minimum typical number.
+
+ <p><b>Number of Sources</b><br>
+ 2
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>maxdepth</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(maximum valid depth of a crossed-over subtree)</td></tr>
+ 
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(first tree for the crossover; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.1</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(second tree for the crossover; if parameter doesn't exist, tree is picked at random.  This tree <b>must</b> have the same GPTreeConstraints as <tt>tree.0</tt>, if <tt>tree.0</tt> is defined.)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>ns.</tt><i>n</i><br>
+ <font size=-1>classname, inherits and != GPNodeSelector,<br>
+ or String <tt>same<tt></font></td>
+ <td valign=top>(GPNodeSelector for parent <i>n</i> (n is 0 or 1) If, for <tt>ns.1</tt> the value is <tt>same</tt>, then <tt>ns.1</tt> a copy of whatever <tt>ns.0</tt> is.  Note that the default version has no <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>toss</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font>/td>
+ <td valign=top>(after crossing over with the first new individual, should its second sibling individual be thrown away instead of adding it to the population?)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.koza.xover
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ns.</tt><i>n</i><br>
+ <td>nodeselect<i>n</i> (<i>n</i> is 0 or 1)</td></tr>
+ </table>
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class CrossoverPipeline extends GPBreedingPipeline
+    {
+    public static final String P_NUM_TRIES = "tries";
+    public static final String P_MAXDEPTH = "maxdepth";
+    public static final String P_CROSSOVER = "xover";
+    public static final String P_TOSS = "toss";
+    public static final int INDS_PRODUCED = 2;
+    public static final int NUM_SOURCES = 2;
+
+    /** How the pipeline selects a node from individual 1 */
+    public GPNodeSelector nodeselect1;
+
+    /** How the pipeline selects a node from individual 2 */
+    public GPNodeSelector nodeselect2;
+
+    /** Is the first tree fixed?  If not, this is -1 */
+    public int tree1;
+
+    /** Is the second tree fixed?  If not, this is -1 */
+    public int tree2;
+
+    /** How many times the pipeline attempts to pick nodes until it gives up. */
+    public int numTries;
+
+    /** The deepest tree the pipeline is allowed to form.  Single terminal trees are depth 1. */
+    public int maxDepth;
+
+    /** Should the pipeline discard the second parent after crossing over? */
+    public boolean tossSecondParent;
+
+    /** Temporary holding place for parents */
+    public GPIndividual parents[];
+
+    public CrossoverPipeline() { parents = new GPIndividual[2]; }
+
+    public Parameter defaultBase() { return GPKozaDefaults.base().push(P_CROSSOVER); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        CrossoverPipeline c = (CrossoverPipeline)(super.clone());
+
+        // deep-cloned stuff
+        c.nodeselect1 = (GPNodeSelector)(nodeselect1.clone());
+        c.nodeselect2 = (GPNodeSelector)(nodeselect2.clone());
+        c.parents = (GPIndividual[]) parents.clone();
+
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+        Parameter p = base.push(P_NODESELECTOR).push("0");
+        Parameter d = def.push(P_NODESELECTOR).push("0");
+
+        nodeselect1 = (GPNodeSelector)
+            (state.parameters.getInstanceForParameter(
+                p,d, GPNodeSelector.class));
+        nodeselect1.setup(state,p);
+
+        p = base.push(P_NODESELECTOR).push("1");
+        d = def.push(P_NODESELECTOR).push("1");
+
+        if (state.parameters.exists(p,d) &&
+            state.parameters.getString(p,d).equals(V_SAME))
+            // can't just copy it this time; the selectors
+            // use internal caches.  So we have to clone it no matter what
+            nodeselect2 = (GPNodeSelector)(nodeselect1.clone());
+        else
+            {
+            nodeselect2 = (GPNodeSelector)
+                (state.parameters.getInstanceForParameter(
+                    p,d, GPNodeSelector.class));
+            nodeselect2.setup(state,p);
+            }
+
+        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES),1);
+        if (numTries == 0)
+            state.output.fatal("GPCrossover Pipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+
+        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),def.push(P_MAXDEPTH),1);
+        if (maxDepth==0)
+            state.output.fatal("GPCrossover Pipeline has an invalid maximum depth (it must be >= 1).",base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+
+        tree1 = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree1 = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree1==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+
+        tree2 = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+1),
+                def.push(P_TREE).push(""+1)))
+            {
+            tree2 = state.parameters.getInt(base.push(P_TREE).push(""+1),
+                def.push(P_TREE).push(""+1),0);
+            if (tree2==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        tossSecondParent = state.parameters.getBoolean(base.push(P_TOSS),
+            def.push(P_TOSS),false);
+
+        }
+
+    /** Returns 2 * minimum number of typical individuals produced by any sources, else
+        1* minimum number if tossSecondParent is true. */
+    public int typicalIndsProduced()
+        {
+        return (tossSecondParent? minChildProduction(): minChildProduction()*2);
+        }
+
+    /** Returns true if inner1 can feasibly be swapped into inner2's position. */
+
+    public boolean verifyPoints(final GPInitializer initializer,
+        final GPNode inner1, final GPNode inner2)
+        {
+        // first check to see if inner1 is swap-compatible with inner2
+        // on a type basis
+        if (!inner1.swapCompatibleWith(initializer, inner2)) return false;
+
+        // next check to see if inner1 can fit in inner2's spot
+        if (inner1.depth()+inner2.atDepth() > maxDepth) return false;
+
+        // checks done!
+        return true;
+        }
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, true);  // DO produce children from source -- we've not done so already
+
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+        
+        for(int q=start;q<n+start; /* no increment */)  // keep on going until we're filled up
+            {
+            // grab two individuals from our sources
+            if (sources[0]==sources[1])  // grab from the same source
+                sources[0].produce(2,2,0,subpopulation,parents,state,thread);
+            else // grab from different sources
+                {
+                sources[0].produce(1,1,0,subpopulation,parents,state,thread);
+                sources[1].produce(1,1,1,subpopulation,parents,state,thread);
+                }
+            
+            // at this point, parents[] contains our two selected individuals
+            
+            // are our tree values valid?
+            if (tree1!=TREE_UNFIXED && (tree1<0 || tree1 >= parents[0].trees.length))
+                // uh oh
+                state.output.fatal("GP Crossover Pipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+            if (tree2!=TREE_UNFIXED && (tree2<0 || tree2 >= parents[1].trees.length))
+                // uh oh
+                state.output.fatal("GP Crossover Pipeline attempted to fix tree.1 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+
+            int t1=0; int t2=0;
+            if (tree1==TREE_UNFIXED || tree2==TREE_UNFIXED) 
+                {
+                do
+                    // pick random trees  -- their GPTreeConstraints must be the same
+                    {
+                    if (tree1==TREE_UNFIXED) 
+                        if (parents[0].trees.length > 1)
+                            t1 = state.random[thread].nextInt(parents[0].trees.length);
+                        else t1 = 0;
+                    else t1 = tree1;
+
+                    if (tree2==TREE_UNFIXED) 
+                        if (parents[1].trees.length>1)
+                            t2 = state.random[thread].nextInt(parents[1].trees.length);
+                        else t2 = 0;
+                    else t2 = tree2;
+                    } while (parents[0].trees[t1].constraints(initializer) != parents[1].trees[t2].constraints(initializer));
+                }
+            else
+                {
+                t1 = tree1;
+                t2 = tree2;
+                // make sure the constraints are okay
+                if (parents[0].trees[t1].constraints(initializer) 
+                    != parents[1].trees[t2].constraints(initializer)) // uh oh
+                    state.output.fatal("GP Crossover Pipeline's two tree choices are both specified by the user -- but their GPTreeConstraints are not the same");
+                }
+
+
+
+            // validity results...
+            boolean res1 = false;
+            boolean res2 = false;
+            
+            
+            // prepare the nodeselectors
+            nodeselect1.reset();
+            nodeselect2.reset();
+            
+            
+            // pick some nodes
+            
+            GPNode p1=null;
+            GPNode p2=null;
+            
+            for(int x=0;x<numTries;x++)
+                {
+                // pick a node in individual 1
+                p1 = nodeselect1.pickNode(state,subpopulation,thread,parents[0],parents[0].trees[t1]);
+                
+                // pick a node in individual 2
+                p2 = nodeselect2.pickNode(state,subpopulation,thread,parents[1],parents[1].trees[t2]);
+                
+                // check for depth and swap-compatibility limits
+                res1 = verifyPoints(initializer,p2,p1);  // p2 can fill p1's spot -- order is important!
+                if (n-(q-start)<2 || tossSecondParent) res2 = true;
+                else res2 = verifyPoints(initializer,p1,p2);  // p1 can fill p2's spot -- order is important!
+                
+                // did we get something that had both nodes verified?
+                // we reject if EITHER of them is invalid.  This is what lil-gp does.
+                // Koza only has numTries set to 1, so it's compatible as well.
+                if (res1 && res2) break;
+                }
+
+            // at this point, res1 AND res2 are valid, OR
+            // either res1 OR res2 is valid and we ran out of tries, OR
+            // neither res1 nor res2 is valid and we rand out of tries.
+            // So now we will transfer to a tree which has res1 or res2
+            // valid, otherwise it'll just get replicated.  This is
+            // compatible with both Koza and lil-gp.
+
+
+            // at this point I could check to see if my sources were breeding
+            // pipelines -- but I'm too lazy to write that code (it's a little
+            // complicated) to just swap one individual over or both over,
+            // -- it might still entail some copying.  Perhaps in the future.
+            // It would make things faster perhaps, not requiring all that
+            // cloning.
+
+            
+            
+            // Create some new individuals based on the old ones -- since
+            // GPTree doesn't deep-clone, this should be just fine.  Perhaps we
+            // should change this to proto off of the main species prototype, but
+            // we have to then copy so much stuff over; it's not worth it.
+                    
+            GPIndividual j1 = (GPIndividual)(parents[0].lightClone());
+            GPIndividual j2 = null;
+            if (n-(q-start)>=2 && !tossSecondParent) j2 = (GPIndividual)(parents[1].lightClone());
+            
+            // Fill in various tree information that didn't get filled in there
+            j1.trees = new GPTree[parents[0].trees.length];
+            if (n-(q-start)>=2 && !tossSecondParent) j2.trees = new GPTree[parents[1].trees.length];
+            
+            // at this point, p1 or p2, or both, may be null.
+            // If not, swap one in.  Else just copy the parent.
+            
+            for(int x=0;x<j1.trees.length;x++)
+                {
+                if (x==t1 && res1)  // we've got a tree with a kicking cross position!
+                    { 
+                    j1.trees[x] = (GPTree)(parents[0].trees[x].lightClone());
+                    j1.trees[x].owner = j1;
+                    j1.trees[x].child = parents[0].trees[x].child.cloneReplacing(p2,p1); 
+                    j1.trees[x].child.parent = j1.trees[x];
+                    j1.trees[x].child.argposition = 0;
+                    j1.evaluated = false; 
+                    }  // it's changed
+                else 
+                    {
+                    j1.trees[x] = (GPTree)(parents[0].trees[x].lightClone());
+                    j1.trees[x].owner = j1;
+                    j1.trees[x].child = (GPNode)(parents[0].trees[x].child.clone());
+                    j1.trees[x].child.parent = j1.trees[x];
+                    j1.trees[x].child.argposition = 0;
+                    }
+                }
+            
+            if (n-(q-start)>=2 && !tossSecondParent) 
+                for(int x=0;x<j2.trees.length;x++)
+                    {
+                    if (x==t2 && res2)  // we've got a tree with a kicking cross position!
+                        { 
+                        j2.trees[x] = (GPTree)(parents[1].trees[x].lightClone());           
+                        j2.trees[x].owner = j2;
+                        j2.trees[x].child = parents[1].trees[x].child.cloneReplacing(p1,p2); 
+                        j2.trees[x].child.parent = j2.trees[x];
+                        j2.trees[x].child.argposition = 0;
+                        j2.evaluated = false; 
+                        } // it's changed
+                    else 
+                        {
+                        j2.trees[x] = (GPTree)(parents[1].trees[x].lightClone());           
+                        j2.trees[x].owner = j2;
+                        j2.trees[x].child = (GPNode)(parents[1].trees[x].child.clone());
+                        j2.trees[x].child.parent = j2.trees[x];
+                        j2.trees[x].child.argposition = 0;
+                        }
+                    }
+            
+            // add the individuals to the population
+            inds[q] = j1;
+            q++;
+            if (q<n+start && !tossSecondParent)
+                {
+                inds[q] = j2;
+                q++;
+                }
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/FullBuilder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/FullBuilder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/FullBuilder.java	(revision 6152)
@@ -0,0 +1,134 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.gp.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * FullBuilder.java
+ * 
+ * Created: Thu Oct  7 18:03:25 1999
+ * By: Sean Luke
+ */
+
+/**
+   FullBuilder is a GPNodeBuilder which implements the FULL tree building method described in Koza I/II.  
+   
+   <p>GROW works by choosing a random integer <i>d</i> between minDepth and maxDepth, inclusive.  It then grows a full tree of depth <i>d</i>.
+   
+   <p>Actually, claiming to implement the Koza I/II approach is a bit of a fib -- Koza's original code is somewhat ad-hoc.  In the Koza approach, <i>d</i> is chosen in a kind of round-robin fashion rather than at random, if RAMPED HALF/HALF is used.  Also, for all three algorithms (RAMPED HALF/HALF, GROW, FULL), the algorithm will not generate a tree consisting of a single terminal, unless forced to.
+
+   <p>This implementation instead follows lil-gp's approach, which is to choose <i>d</i> at random from between minDepth and maxDepth, inclusive, and to allow trees consisting of single terminals.   
+
+   <p>Determining what various algorithms do is a little confusing, mostly because the source code for lil-gp and Koza don't actually quite do what they claim.  The table below lists the depth values actually used (counting nodes, rather than edges, for depth).  It's probably not what you had expected!
+
+
+   <br>
+   <br>
+   <div align="center">
+   <table border="0" cellspacing="1" cellpadding="2">
+   <tr>
+   <td bgcolor="#ffffff"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" ></font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza I Min</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza I Max</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza II Min</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza II Max</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >lil-gp Min</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >lil-gp Max</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >ECJ Min</font><br></td>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >ECJ Max</font><br></td>
+   </tr><tr>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">GROW (mut)</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <tr></tr>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">GROW (new)</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+   <tr></tr>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">FULL (new)</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+   <tr></tr>
+   <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">HALF (new)</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5? 6?</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+   <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6</font><br></td>
+   </tr></table>
+   </div>
+   <br>
+   <br>
+
+   The table cell is empty when that parameter is not defined by the system by default.  Koza II has two values each because of a possible typo in the text -- while page 656 gives one maximum, page 671 gives another.  Note the odd fact that in Koza I/II GROW and FULL have <i>effectively</i> one-deeper tree values than HALF does, even though they use the same code parameters!  This is because of a quirk in Koza's code.
+
+   <p> This algorithm ignores <tt>requestedSize</tt>, so no pipelines can ask it to grow a tree of a specific fixed size.  The algorithm also ignores any user-provided size distributions.
+
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>min-depth</tt><br>
+   <font size=-1>int &gt;= 1</font></td>
+   <td valign=top>(smallest "maximum" depth the builder may use for building a tree. 2 is the default.)</td></tr>
+
+   <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
+   <font size=-1>int &gt;= <i>base</i>.<tt>min-depth</tt></font></td>
+   <td valign=top>(largest "maximum" depth the builder may use for building a tree. 6 is the default.)</td></tr>
+   </table>
+
+   <p><b>Default Base</b><br>
+   gp.koza.full
+
+   * @author Sean Luke
+   * @version 1.0 
+   */
+
+
+
+public class FullBuilder extends KozaBuilder
+    {
+    public static final String P_FULLBUILDER = "full";
+
+    public Parameter defaultBase()
+        {
+        return GPKozaDefaults.base().push(P_FULLBUILDER); 
+        }
+
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        return fullNode(state,0,state.random[thread].nextInt(maxDepth-minDepth+1) + minDepth,type,thread,parent,argposition,set);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/GPKozaDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/GPKozaDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/GPKozaDefaults.java	(revision 6152)
@@ -0,0 +1,38 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.gp.GPDefaults;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * GPKozaDefaults.java
+ * 
+ * Created: Tue Oct 12 17:44:47 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A static class that returns the base for "default values" which Koza-style
+ * operators use, rather than making the user specify them all on a per-
+ * species basis.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class GPKozaDefaults implements DefaultsForm
+    {
+    public static final String P_KOZA = "koza";
+
+    /** Returns the default base, which is built off of the GPDefaults base. */
+    public static final Parameter base()
+        {
+        return GPDefaults.base().push(P_KOZA);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/GrowBuilder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/GrowBuilder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/GrowBuilder.java	(revision 6152)
@@ -0,0 +1,145 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * GrowBuilder.java
+ * 
+ * Created: Thu Oct  7 18:03:49 1999
+ * By: Sean Luke
+ */
+
+
+/** GrowBuilder is a GPNodeBuilder which
+    implements the GROW tree building method described in Koza I/II.  
+    
+    <p>GROW works by choosing a random integer <i>d</i> between minDepth and maxDepth, inclusive.  It then grows a tree of depth 1 to <i>d</i> inclusive.  Unlike lil-gp and Koza's texts, ECJ defines the "depth" of a tree to be the number of <i>nodes</i> (not edges) in the longest path from the root to any node in the tree.
+
+    <p>Actually, claiming to implement the Koza I/II approach is a bit of a fib -- Koza's original code is somewhat ad-hoc.  In the Koza approach, <i>d</i> is chosen in a kind of round-robin fashion rather than at random, if RAMPED HALF/HALF is used.  Also, for all three algorithms (RAMPED HALF/HALF, GROW, FULL), the algorithm will not generate a tree consisting of a single terminal, unless forced to.
+
+    <p>This implementation instead follows lil-gp's approach, which is to choose <i>d</i> at random from between minDepth and maxDepth, inclusive, and to allow trees consisting of single terminals.   
+
+    <p>Determining what various algorithms do is a little confusing, mostly because the source code for lil-gp and Koza don't actually quite do what they claim.  The table below lists the depth values actually used (counting nodes, rather than edges, for depth).  It's probably not what you had expected!
+
+
+
+    <br>
+    <br>
+    <div align="center">
+    <table border="0" cellspacing="1" cellpadding="2">
+    <tr>
+    <td bgcolor="#ffffff"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" ></font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza I Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza I Max</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza II Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza II Max</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >lil-gp Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >lil-gp Max</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >ECJ Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >ECJ Max</font><br></td>
+    </tr><tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">GROW (mut)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <tr></tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">GROW (new)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <tr></tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">FULL (new)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <tr></tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">HALF (new)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5? 6?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6</font><br></td>
+    </tr></table>
+    </div>
+    <br>
+    <br>
+
+
+
+
+
+
+    The table cell is empty when that parameter is not defined by the system by default.  Koza II has two values each because of a possible typo in the text -- while page 656 gives one maximum, page 671 gives another.  Note the odd fact that in Koza I/II GROW and FULL have <i>effectively</i> one-deeper tree values than HALF does, even though they use the same code parameters!  This is because of a quirk in Koza's code.
+
+
+    <p> This algorithm ignores <tt>requestedSize</tt>, so no pipelines can ask it to grow a tree of a specific fixed size.  The algorithm also ignores any user-provided size distributions.
+
+    <p><b>Parameters</b><br>
+    <table>
+    <tr><td valign=top><i>base</i>.<tt>min-depth</tt><br>
+    <font size=-1>int &gt;= 1</font></td>
+    <td valign=top>(smallest "maximum" depth the builder may use for building a tree. 2 is the default.)</td></tr>
+    
+    <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
+    <font size=-1>int &gt;= <i>base</i>.<tt>min-depth</tt></font></td>
+    <td valign=top>(largest "maximum" depth thie builder may use for building a tree. 6 is the default.)</td></tr>
+    </table>
+    
+    <p><b>Default Base</b><br>
+    gp.koza.grow
+
+    * @author Sean Luke
+    * @version 1.0 
+    */
+
+
+
+public class GrowBuilder extends KozaBuilder
+    {
+    public static final String P_GROWBUILDER = "grow";
+
+    public Parameter defaultBase()
+        {
+        return GPKozaDefaults.base().push(P_GROWBUILDER); 
+        }
+
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        GPNode n = growNode(state,0,state.random[thread].nextInt(maxDepth-minDepth+1) + minDepth,type,thread,parent,argposition,set);
+        return n;
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/HalfBuilder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/HalfBuilder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/HalfBuilder.java	(revision 6152)
@@ -0,0 +1,163 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * HalfBuilder.java
+ * 
+ * Created: Thu Oct  7 18:03:49 1999
+ * By: Sean Luke
+ */
+
+/** HalfBuilder is a GPNodeBuilder which 
+    implements the RAMPED HALF-AND-HALF tree building method described in Koza I/II.  
+
+    <p>RAMPED HALF-AND-HALF works by choosing a random integer <i>d</i> between minDepth and maxDepth, inclusive.  It then grows a tree of depth 1 to <i>d</i> inclusive.  (1-pickGrowProbability) of the time (by default, 0.5) it grows a tree using the FULL method, which generates full trees of exactly depth <i>d</i>.  (pickGrowProbability) of the time, it grows a tree using the GROW method, which may generate trees of any size between 1 and <i>d</i> inclusive.
+
+    <p>Actually, claiming to implement the Koza I/II approach is a bit of a fib -- Koza's original code is somewhat ad-hoc.  In the Koza approach, <i>d</i> is chosen in a kind of round-robin fashion rather than at random, if RAMPED HALF/HALF is used.  Also, for all three algorithms (RAMPED HALF/HALF, GROW, FULL), the algorithm will not generate a tree consisting of a single terminal, unless forced to.
+
+    <p>This implementation instead follows lil-gp's approach, which is to choose <i>d</i> at random from between minDepth and maxDepth, inclusive, and to allow trees consisting of single terminals.   
+
+    <p>Determining what various algorithms do is a little confusing, mostly because the source code for lil-gp and Koza don't actually quite do what they claim.  The table below lists the depth values actually used (counting nodes, rather than edges, for depth).  It's probably not what you had expected!
+
+
+    <br>
+    <br>
+    <div align="center">
+    <table border="0" cellspacing="1" cellpadding="2">
+    <tr>
+    <td bgcolor="#ffffff"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" ></font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza I Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza I Max</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza II Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >Koza II Max</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >lil-gp Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >lil-gp Max</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >ECJ Min</font><br></td>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff" >ECJ Max</font><br></td>
+    </tr><tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">GROW (mut)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <tr></tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">GROW (new)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5</font><br></td>
+    <tr></tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">FULL (new)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6? 7?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">&nbsp;</font><br></td>
+    <tr></tr>
+    <td bgcolor="#3366cc"><font size="-1" face="simple,geneva,arial,helvetica" color="#ffffff">HALF (new)</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">5? 6?</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">3</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">7</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">2</font><br></td>
+    <td bgcolor="#cccccc"><font size="-1" face="simple,geneva,arial,helvetica">6</font><br></td>
+    </tr></table>
+    </div>
+    <br>
+    <br>
+
+
+
+    The table cell is empty when that parameter is not defined by the system by default.  Koza II has two values each because of a possible typo in the text -- while page 656 gives one maximum, page 671 gives another.  Note the odd fact that in Koza I/II GROW and FULL have <i>effectively</i> one-deeper tree values than HALF does, even though they use the same code parameters!  This is because of a quirk in Koza's code.
+
+    <p> This algorithm ignores <tt>requestedSize</tt>, so no pipelines can ask it to grow a tree of a specific fixed size.  The algorithm also ignores any user-provided size distributions.
+
+
+    <p><b>Parameters</b><br>
+    <table>
+    <tr><td valign=top><i>base</i>.<tt>growp</tt><br>
+    <font size=-1>0.0 &lt;= float &lt;= 1.0</font></td>
+    <td valign=top>(the likelihood of choosing GROW (as opposed to FULL)></tr>
+
+    <tr><td valign=top><i>base</i>.<tt>min-depth</tt><br>
+    <font size=-1>int &gt;= 1</font></td>
+    <td valign=top>(smallest "maximum" depth the builder may use for building a tree.  2 is the default.)</td></tr>
+   
+    <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
+    <font size=-1>int &gt;= <i>base</i>.<tt>min-depth</tt></font></td>
+    <td valign=top>(largest "maximum" depth the builder may use for building a tree. 6 is the default.)</td></tr>
+    </table>
+   
+    <p><b>Default Base</b><br>
+    gp.koza.half
+
+    * @author Sean Luke
+    * @version 1.0 
+    */
+
+
+public class HalfBuilder extends KozaBuilder
+    {
+    public static final String P_HALFBUILDER = "half";
+    public static final String P_PICKGROWPROBABILITY = "growp";
+
+    /** The likelihood of using GROW over FULL. */
+    public float pickGrowProbability;
+    
+    public Parameter defaultBase()
+        {
+        return GPKozaDefaults.base().push(P_HALFBUILDER); 
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        pickGrowProbability = state.parameters.getFloatWithMax(
+            base.push(P_PICKGROWPROBABILITY),
+            def.push(P_PICKGROWPROBABILITY),0.0f,1.0f);
+        if (pickGrowProbability < 0.0f)
+            state.output.fatal("The Pick-Grow Probability for HalfBuilder must be a floating-point value between 0.0 and 1.0 inclusive.", base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+        }
+    
+    public GPNode newRootedTree(final EvolutionState state,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final GPFunctionSet set,
+        final int argposition,
+        final int requestedSize)
+        {
+        if (state.random[thread].nextFloat() < pickGrowProbability)
+            return growNode(state,0,state.random[thread].nextInt(maxDepth-minDepth+1) + minDepth,type,thread,parent,argposition,set);
+        else
+            return fullNode(state,0,state.random[thread].nextInt(maxDepth-minDepth+1) + minDepth,type,thread,parent,argposition,set);
+        }
+
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaBuilder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaBuilder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaBuilder.java	(revision 6152)
@@ -0,0 +1,193 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * KozaBuilder.java
+ * 
+ * Created: Sun Oct 29 22:35:34 EST 2006
+ * By: Sean Luke
+ */
+
+/*
+  KozaBuilder is an abstract superclass of three tree builders: GROW, FULL, and RAMPED HALF-AND-HALF,
+  all described in I/II.  As all three classes specify a minimum and maximum depth, these instance
+  variables and setup methods appear here; but they are described in detail in the relevant subclasses
+  (GrowBuilder, HalfBuilder, and FullBuilder).
+
+  <p><b>Parameters</b><br>
+  <table>
+  <tr><td valign=top><i>base</i>.<tt>min-depth</tt><br>
+  <font size=-1>int &gt;= 1</font></td>
+  <td valign=top>(smallest "maximum" depth the builder may use for building a tree.  2 is the default.)</td></tr>
+
+  <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
+  <font size=-1>int &gt;= <i>base</i>.<tt>min-depth</tt></font></td>
+  <td valign=top>(largest "maximum" depth the builder may use for building a tree. 6 is the default.)</td></tr>
+  </table>
+
+  @author Sean Luke
+  @version 1.0 
+*/
+
+public abstract class KozaBuilder extends GPNodeBuilder
+    {
+    public static final String P_MAXDEPTH = "max-depth";
+    public static final String P_MINDEPTH = "min-depth";
+
+    /** The largest maximum tree depth RAMPED HALF-AND-HALF can specify. */
+    public int maxDepth;
+
+    /** The smallest maximum tree depth RAMPED HALF-AND-HALF can specify. */
+    public int minDepth;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        // load maxdepth and mindepth, check that maxdepth>0, mindepth>0, maxdepth>=mindepth
+        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),def.push(P_MAXDEPTH),1);
+        if (maxDepth<=0)
+            state.output.fatal("The Max Depth for a KozaBuilder must be at least 1.",
+                base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+                        
+        minDepth = state.parameters.getInt(base.push(P_MINDEPTH),def.push(P_MINDEPTH),1);
+        if (minDepth<=0)
+            state.output.fatal("The Min Depth for a KozaBuilder must be at least 1.",
+                base.push(P_MINDEPTH),def.push(P_MINDEPTH));
+
+        if (maxDepth<minDepth)
+            state.output.fatal("Max Depth must be >= Min Depth for a KozaBuilder",
+                base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+        }
+                
+    /** A private recursive method which builds a FULL-style tree for newRootedTree(...) */
+    protected GPNode fullNode(final EvolutionState state,
+        final int current,
+        final int max,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final int argposition,
+        final GPFunctionSet set) 
+        {
+        // fullNode can mess up if there are no available terminals for a given type.  If this occurs,
+        // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
+        // and pick a nonterminal, violating the "FULL" contract.  This can lead to pathological situations
+        // where the system will continue to go on and on unable to stop because it can't pick a terminal,
+        // resulting in running out of memory or some such.  But there are cases where we'd want to let
+        // this work itself out.
+        boolean triedTerminals = false;   // did we try -- and fail -- to fetch a terminal?
+        
+        int t = type.type;
+        GPNode[] terminals = set.terminals[t];
+        GPNode[] nonterminals = set.nonterminals[t];
+        GPNode[] nodes = set.nodes[t];          
+
+        if (nodes.length == 0)
+            errorAboutNoNodeWithType(type, state);   // total failure
+
+        // pick a terminal when we're at max depth or if there are NO nonterminals
+        if ((  current+1 >= max ||                                                      // Now pick if we're at max depth
+                warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&     // OR if there are NO nonterminals!
+            (triedTerminals = true) &&                                                  // [first set triedTerminals]
+            terminals.length != 0)                                                      // AND if there are available terminals
+            {
+            GPNode n = (GPNode)(terminals[state.random[thread].nextInt(terminals.length)].lightClone());
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+            return n;
+            }
+                        
+        // else force a nonterminal unless we have no choice
+        else
+            {
+            if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);        // we tried terminals and we're here because there were none!
+                                
+            GPNode[] nodesToPick = set.nonterminals[type.type];
+            if (nodesToPick==null || nodesToPick.length ==0)                            // no nonterminals, hope the guy knows what he's doing!
+                nodesToPick = set.terminals[type.type];                                 // this can only happen with the warning about nonterminals above
+
+            GPNode n = (GPNode)(nodesToPick[state.random[thread].nextInt(nodesToPick.length)].lightClone());
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+
+            // Populate the node...
+            GPType[] childtypes = n.constraints(((GPInitializer)state.initializer)).childtypes;
+            for(int x=0;x<childtypes.length;x++)
+                n.children[x] = fullNode(state,current+1,max,childtypes[x],thread,n,x,set);
+
+            return n;
+            }
+        }
+
+    /** A private function which recursively returns a GROW tree to newRootedTree(...) */
+    protected GPNode growNode(final EvolutionState state,
+        final int current,
+        final int max,
+        final GPType type,
+        final int thread,
+        final GPNodeParent parent,
+        final int argposition,
+        final GPFunctionSet set) 
+        {
+        // growNode can mess up if there are no available terminals for a given type.  If this occurs,
+        // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
+        // and pick a nonterminal, violating the maximum-depth contract.  This can lead to pathological situations
+        // where the system will continue to go on and on unable to stop because it can't pick a terminal,
+        // resulting in running out of memory or some such.  But there are cases where we'd want to let
+        // this work itself out.
+        boolean triedTerminals = false;
+
+        int t = type.type;
+        GPNode[] terminals = set.terminals[t];
+        GPNode[] nonterminals = set.nonterminals[t];
+        GPNode[] nodes = set.nodes[t];          
+
+        if (nodes.length == 0)
+            errorAboutNoNodeWithType(type, state);   // total failure
+
+        // pick a terminal when we're at max depth or if there are NO nonterminals
+        if ((current+1 >= max) &&                                                       // Now pick if we're at max depth
+            (triedTerminals = true) &&                                                  // [first set triedTerminals]
+            terminals.length != 0)                                                      // AND if there are available terminals
+            {
+            GPNode n = (GPNode)(terminals[state.random[thread].nextInt(terminals.length)].lightClone());
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+            return n;
+            }
+                        
+        // else pick a random node
+        else
+            {
+            if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);        // we tried terminals and we're here because there were none!
+
+            GPNode n = (GPNode)(nodes[state.random[thread].nextInt(nodes.length)].lightClone());
+            n.resetNode(state,thread);  // give ERCs a chance to randomize
+            n.argposition = (byte)argposition;
+            n.parent = parent;
+
+            // Populate the node...
+            GPType[] childtypes = n.constraints(((GPInitializer)state.initializer)).childtypes;
+            for(int x=0;x<childtypes.length;x++)
+                n.children[x] = growNode(state,current+1,max,childtypes[x],thread,n,x,set);
+
+            return n;
+            }
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaFitness.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaFitness.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaFitness.java	(revision 6152)
@@ -0,0 +1,199 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.util.*;
+import ec.*;
+import java.io.*;
+
+/* 
+ * KozaFitness.java
+ * 
+ * Created: Fri Oct 15 14:26:44 1999
+ * By: Sean Luke
+ */
+
+/**
+ * KozaFitness is a Fitness which stores an individual's fitness as described in
+ * Koza I.  Well, almost.  In KozaFitness, standardized fitness and raw fitness
+ * are considered the same (there are different methods for them, but they return
+ * the same thing).  Standardized fitness ranges from 0.0 inclusive (the best)
+ * to infinity exclusive (the worst).  Adjusted fitness converts this, using
+ * the formula adj_f = 1/(1+f), into a scale from 0.0 exclusive (worst) to 1.0
+ * inclusive (best).  While it's the standardized fitness that is stored, it
+ * is the adjusted fitness that is printed out.
+ * This is all just convenience stuff anyway; selection methods
+ * generally don't use these fitness values but instead use the betterThan
+ * and equalTo methods.
+ *
+ <p><b>Default Base</b><br>
+ gp.koza.fitness
+ *
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class KozaFitness extends Fitness
+    {
+    public static final String P_KOZAFITNESS = "fitness";
+
+    /** This ranges from 0 (best) to infinity (worst).    I
+        define it here as equivalent to the standardized fitness. */
+    protected float standardizedFitness;
+
+    /** This auxillary measure is used in some problems for additional
+        information.  It's a traditional feature of Koza-style GP, and so
+        although I think it's not very useful, I'll leave it in anyway. */
+    public int hits;
+
+    public Parameter defaultBase()
+        {
+        return GPKozaDefaults.base().push(P_KOZAFITNESS);
+        }
+        
+    /**
+       Do not use this function.  Use the identical setStandardizedFitness() instead.
+       The reason for the name change is that fitness() returns a differently-defined
+       value than setFitness() sets, ugh.
+       @deprecated
+    */
+    public final void setFitness(final EvolutionState state, final float _f)
+        {
+        setStandardizedFitness(state,_f);
+        }
+
+    /** Set the standardized fitness in the half-open interval [0.0,infinity)
+        which is defined (NOTE: DIFFERENT FROM fitness()!!!) as 0.0 
+        being the IDEAL and infinity being worse than the worst possible.
+        This is the GP tradition.  The fitness() function instead will output
+        the equivalent of Adjusted Fitness.
+    */
+    public final void setStandardizedFitness(final EvolutionState state, final float _f)
+        {
+        if (_f < 0.0f || _f == Float.POSITIVE_INFINITY || Float.isNaN(_f))
+            {
+            state.output.warning("Bad fitness (may not be < 0, NaN, or infinity): " + _f  + ", setting to 0.");
+            standardizedFitness = 0;
+            }
+        else standardizedFitness = _f;
+        }
+
+    /** Returns the adjusted fitness metric, which recasts the
+        fitness to the half-open interval (0,1], where 1 is ideal and
+        0 is worst.  Same as adjustedFitness().  */
+
+    public final float fitness()
+        {
+        return 1.0f/(1.0f+standardizedFitness);     
+        }
+
+    /** Returns the raw fitness metric.  
+        @deprecated use standardizedFitness()
+    */
+    public final float rawFitness()
+        {
+        return standardizedFitness();
+        }
+
+    /** Returns the standardized fitness metric. */
+
+    public final float standardizedFitness()
+        {
+        return standardizedFitness;
+        }
+
+    /** Returns the adjusted fitness metric, which recasts the fitness
+        to the half-open interval (0,1], where 1 is ideal and 0 is worst.
+        This metric is used when printing the fitness out. */
+
+    public final float adjustedFitness()
+        {
+        return fitness();
+        }
+
+    public void setup(final EvolutionState state, final Parameter base) { }
+    
+    public final boolean isIdealFitness()
+        {
+        return standardizedFitness == 0.0f;
+        }
+    
+    public boolean equivalentTo(final Fitness _fitness)
+        {
+        return _fitness.fitness() == fitness();
+        }
+
+    public boolean betterThan(final Fitness _fitness)
+        {
+        return _fitness.fitness() < fitness();
+        }
+ 
+    public String fitnessToString()
+        {
+        return FITNESS_PREAMBLE + Code.encode(standardizedFitness) + Code.encode(hits);
+        }
+        
+    public String fitnessToStringForHumans()
+        {
+        return FITNESS_PREAMBLE + "Standardized=" + standardizedFitness + " Adjusted=" + adjustedFitness() + " Hits=" + hits;
+        }
+            
+    public final void readFitness(final EvolutionState state, 
+        final LineNumberReader reader)
+        throws IOException
+        {
+        DecodeReturn d = Code.checkPreamble(FITNESS_PREAMBLE, state, reader);
+        
+        // extract fitness
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_FLOAT)
+            state.output.fatal("Reading Line " + d.lineNumber + ": " +
+                "Bad Fitness.");
+        standardizedFitness = (float)d.d;
+        
+        // extract hits
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_INT)
+            state.output.fatal("Reading Line " + d.lineNumber + ": " +
+                "Bad Fitness.");
+        hits = (int)d.l;
+        }
+
+    public void writeFitness(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeFloat(standardizedFitness);
+        dataOutput.writeInt(hits);
+        }
+
+    public void readFitness(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        standardizedFitness = dataInput.readFloat();
+        hits = dataInput.readInt();
+        }
+
+    public void setToMeanOf(EvolutionState state, Fitness[] fitnesses)
+        {
+        // this is not numerically stable.  Perhaps we should have a numerically stable algorithm for sums
+        // we're presuming it's not a very large number of elements, so it's probably not a big deal,
+        // since this function is meant to be used mostly for gathering trials together.
+        double f = 0;
+        long h = 0;
+        for(int i = 0; i < fitnesses.length; i++)
+            {
+            KozaFitness fit = (KozaFitness)(fitnesses[i]);
+            f += fit.standardizedFitness;
+            h += fit.hits;
+            }
+        f /= fitnesses.length;
+        h /= fitnesses.length;
+        standardizedFitness = (float)f;
+        hits = (int)h;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaNodeSelector.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaNodeSelector.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaNodeSelector.java	(revision 6152)
@@ -0,0 +1,213 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.gp.*;
+import ec.util.*;
+
+/* 
+ * KozaNodeSelector.java
+ * 
+ * Created: Tue Oct 12 17:21:28 1999
+ * By: Sean Luke
+ */
+
+/**
+ * KozaNodeSelector is a GPNodeSelector which picks nodes in trees a-la Koza I,
+ * with the addition of having a probability of always picking the root.
+ * The method divides the range 0.0...1.0 into four probability areas: 
+
+ <ul>
+ <li>One area specifies that the selector must pick a terminal.
+ <li>Another area specifies that the selector must pick a nonterminal (if there is one, else a terminal).
+ <li>The third area specifies that the selector pick the root node.
+ <li>The fourth area specifies that the selector pick any random node.
+ </ul>
+
+ * <p>The KozaNodeSelector chooses by probability between these four situations.
+ * Then, based on the situation it has picked, it selects either a random 
+ * terminal, nonterminal, root, or arbitrary node from the tree and returns it.
+ *
+ * <p>As the selector picks a node, it builds up some statistics information
+ * which makes it able to pick a little faster in subsequent passes.  Thus
+ * if you want to reuse this selector on another tree, you need to call
+ * reset() first.
+ *
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>terminals</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0,<br>
+ nonterminals + terminals + root <= 1.0</font></td>
+ <td valign=top>(the probability we must pick a terminal)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>nonterminals</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0,<br>
+ nonterminals + terminals + root <= 1.0</font></td>
+ <td valign=top>(the probability we must pick a nonterminal if possible)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>root</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0,<br>
+ nonterminals + terminals + root <= 1.0</font></td>
+ <td valign=top>(the probability we must pick the root)</td></tr>
+
+ </table>
+
+ <p><b>DefaultBase</b><br>
+ gp.koza.ns
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class KozaNodeSelector implements GPNodeSelector 
+    {
+    public static final String P_NODESELECTOR = "ns";
+    public static final String P_TERMINAL_PROBABILITY = "terminals";
+    public static final String P_NONTERMINAL_PROBABILITY = "nonterminals";
+    public static final String P_ROOT_PROBABILITY = "root";
+
+    /** The probability the root must be chosen */
+    public float rootProbability;
+    
+    /** The probability a terminal must be chosen */
+    public float terminalProbability;
+
+    /** The probability a nonterminal must be chosen. */
+    public float nonterminalProbability;
+
+    /** The number of nonterminals in the tree, -1 if unknown. */
+    public int nonterminals;
+    /** The number of terminals in the tree, -1 if unknown. */
+    public int terminals;
+    /** The number of nodes in the tree, -1 if unknown. */
+    public int nodes;
+
+    /** Used internally to look for a node.  This is threadsafe as long as
+        an instance of KozaNodeSelector is used by only one thread. */
+    protected GPNodeGatherer gatherer;
+
+    public Parameter defaultBase()
+        {
+        return GPKozaDefaults.base().push(P_NODESELECTOR);
+        }
+
+    public KozaNodeSelector() 
+        {
+        gatherer = new GPNodeGatherer(); 
+        reset();
+        }
+
+    public Object clone()
+        {
+        try
+            {
+            KozaNodeSelector s = (KozaNodeSelector)(super.clone());
+            // allocate a new gatherer, so we're always threadsafe
+            s.gatherer = new GPNodeGatherer();
+            s.reset();
+            return s;
+            }
+        catch (CloneNotSupportedException e)
+            { throw new InternalError(); } // never happens
+        }
+
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        terminalProbability = state.parameters.getFloatWithMax(
+            base.push(P_TERMINAL_PROBABILITY),
+            def.push(P_TERMINAL_PROBABILITY), 0.0, 1.0);
+        if (terminalProbability==-1.0)
+            state.output.fatal("Invalid terminal probability for KozaNodeSelector ",
+                base.push(P_TERMINAL_PROBABILITY),
+                def.push(P_TERMINAL_PROBABILITY));
+        
+        nonterminalProbability = state.parameters.getFloatWithMax(
+            base.push(P_NONTERMINAL_PROBABILITY), 
+            def.push(P_NONTERMINAL_PROBABILITY),0.0, 1.0);
+        if (nonterminalProbability==-1.0)
+            state.output.fatal("Invalid nonterminal probability for KozaNodeSelector ",
+                base.push(P_NONTERMINAL_PROBABILITY), 
+                def.push(P_NONTERMINAL_PROBABILITY));
+
+        rootProbability = state.parameters.getFloatWithMax(
+            base.push(P_ROOT_PROBABILITY),
+            def.push(P_ROOT_PROBABILITY),0.0, 1.0);
+        
+        if (rootProbability==-1.0)
+            state.output.fatal("Invalid root probability for KozaNodeSelector ",
+                base.push(P_ROOT_PROBABILITY),
+                def.push(P_ROOT_PROBABILITY));
+
+        if (rootProbability+terminalProbability+nonterminalProbability > 1.0f)
+            state.output.fatal("The terminal, nonterminal, and root for KozaNodeSelector" + base + " may not sum to more than 1.0. (" + terminalProbability + " " + nonterminalProbability + " " + rootProbability + ")",base);
+
+        reset();
+        }
+
+
+    public void reset()
+        {
+        nonterminals = terminals = nodes = -1;
+        }
+
+    public GPNode pickNode(final EvolutionState s,
+        final int subpopulation,
+        final int thread,
+        final GPIndividual ind,
+        final GPTree tree)
+        {
+        float rnd = s.random[thread].nextFloat();
+        
+        if (rnd > nonterminalProbability + terminalProbability + rootProbability)  // pick anyone
+            {
+            if (nodes==-1) nodes= 
+                               tree.child.numNodes(GPNode.NODESEARCH_ALL);
+                    {
+                    tree.child.nodeInPosition(s.random[thread].nextInt(nodes),
+                        gatherer,
+                        GPNode.NODESEARCH_ALL);
+                    return gatherer.node;
+                    }
+            }
+        else if (rnd > nonterminalProbability + terminalProbability)  // pick the root
+            {
+            return tree.child;
+            }
+        else if (rnd > nonterminalProbability)  // pick terminals
+            {
+            if (terminals==-1) terminals = 
+                                   tree.child.numNodes(GPNode.NODESEARCH_TERMINALS);
+            
+            tree.child.nodeInPosition(s.random[thread].nextInt(terminals),
+                gatherer,
+                GPNode.NODESEARCH_TERMINALS);
+            return gatherer.node;
+            }
+        else  // pick nonterminals if you can
+            {
+            if (nonterminals==-1)
+                nonterminals = tree.child.numNodes(GPNode.NODESEARCH_NONTERMINALS);
+            if (nonterminals > 0) // there are some nonterminals
+                {
+                tree.child.nodeInPosition(s.random[thread].nextInt(nonterminals),
+                    gatherer,
+                    GPNode.NODESEARCH_NONTERMINALS);
+                return gatherer.node;
+                }
+            else // there ARE no nonterminals!  It must be the root node
+                {
+                return tree.child;
+                }
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaShortStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaShortStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaShortStatistics.java	(revision 6152)
@@ -0,0 +1,336 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.gp.*;
+import java.io.*;
+import ec.util.*;
+
+/* 
+ * KozaShortStatistics.java
+ * 
+ * Created: Fri Nov  5 16:03:44 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A Koza-style statistics generator, intended to be easily parseable with
+ * awk or other Unix tools.  Prints fitness information,
+ * one generation (or pseudo-generation) per line.
+ * If gather-full is true, then timing information, number of nodes
+ * and depths of trees, etc. are also given.  No final statistics information
+ * is given.
+ *
+ * <p> Each line represents a single generation.  
+ * The first items on a line are always:
+ <ul>
+ <li> The generation number
+ <li> (if gather-full) how long initialization took in milliseconds, or how long the previous generation took to breed to form this generation
+ <li> (if gather-full) how many bytes initialization took, or how how many bytes the previous generation took to breed to form this generation.  This utilization is an approximation only, made by the Java system, and does not take into consideration the possibility of garbage collection (which might make the number negative).
+ <li> (if gather-full) How long evaluation took in milliseconds this generation
+ <li> (if gather-full) how many bytes evaluation took this generation.  This utilization is an approximation only, made by the Java system, and does not take into consideration the possibility of garbage collection (which might make the number negative).
+ </ul>
+
+ <p>Then the following items appear, per subpopulation:
+ <ul>
+ <li> (if gather-full) The average number of nodes used per individual this generation
+ <li> (if gather-full) [a|b|c...], representing the average number of nodes used in tree <i>a</i>, <i>b</i>, etc. of individuals this generation
+ <li> (if gather-full) The average number of nodes used per individual so far in the run
+ <li> (if gather-full) The average depth of any tree per individual this generation
+ <li> (if gather-full) [a|b|c...], representing the average depth of tree <i>a</i>, <i>b</i>, etc. of individuals this generation
+ <li> (if gather-full) The average depth of any tree per individual so far in the run
+ <li> The mean standardized fitness of the subpopulation this generation
+ <li> The mean adjusted fitness of the subpopulation this generation
+ <li> The mean hits of the subpopulation this generation
+ <li> The best standardized fitness of the subpopulation this generation
+ <li> The best adjusted fitness of the subpopulation this generation
+ <li> The best hits of the subpopulation this generation
+ <li> The best standardized fitness of the subpopulation so far in the run
+ <li> The best adjusted fitness of the subpopulation so far in the run
+ <li> The best hits of the subpopulation so far in the run
+ </ul>
+
+ Compressed files will be overridden on restart from checkpoint; uncompressed files will be 
+ appended on restart.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>gzip</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether or not to compress the file (.gz suffix added)</td></tr>
+ <tr><td valign=top><i>base.</i><tt>file</tt><br>
+ <font size=-1>String (a filename), or nonexistant (signifies stdout)</font></td>
+ <td valign=top>(the log for statistics)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>gather-full</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we full statistics on individuals (will run slower, though the slowness is due to off-line processing that won't mess up timings)</td></tr>
+ </table>
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class KozaShortStatistics extends Statistics
+    {
+    public Individual[] getBestSoFar() { return best_of_run; }
+
+    /** compress? */
+    public static final String P_COMPRESS = "gzip";
+
+    public static final String P_FULL = "gather-full";
+
+    public boolean doFull;
+
+    public Individual[] best_of_run;
+    public long totalNodes[];
+    public long totalDepths[];
+
+    // timings
+    public long lastTime;
+    
+    // usage
+    public long lastUsage;
+    
+    /** log file parameter */
+    public static final String P_STATISTICS_FILE = "file";
+
+    /** The Statistics' log */
+    public int statisticslog;
+
+    public KozaShortStatistics() { /*best_of_run = null;*/ statisticslog = 0; /* stdout */ }
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        File statisticsFile = state.parameters.getFile(
+            base.push(P_STATISTICS_FILE),null);
+
+        if (statisticsFile!=null) try
+                                      {
+                                      statisticslog = state.output.addLog(statisticsFile,
+                                          !state.parameters.getBoolean(base.push(P_COMPRESS),null,false),
+                                          state.parameters.getBoolean(base.push(P_COMPRESS),null,false));
+                                      }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + statisticsFile + ":\n" + i);
+                }
+        doFull = state.parameters.getBoolean(base.push(P_FULL),null,false);
+        }
+
+
+    public void preInitializationStatistics(final EvolutionState state)
+        {
+        super.preInitializationStatistics(state);
+
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+    
+    public void postInitializationStatistics(final EvolutionState state)
+        {
+        super.postInitializationStatistics(state);
+        // set up our best_of_run array -- can't do this in setup, because
+        // we don't know if the number of subpopulations has been determined yet
+        best_of_run = new Individual[state.population.subpops.length];
+        
+        // print out our generation number
+        state.output.print("0 ", statisticslog);
+
+        // gather timings       
+        if (doFull)
+            {
+            totalNodes = new long[state.population.subpops.length];
+            for(int x=0;x<totalNodes.length;x++) totalNodes[x] = 0;
+            totalDepths = new long[state.population.subpops.length];
+            for(int x=0;x<totalDepths.length;x++) totalDepths[x] = 0;
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();          
+            state.output.print("" + (System.currentTimeMillis()-lastTime) + " ",  statisticslog);
+            state.output.print("" + (curU-lastUsage) + " ",  statisticslog);            
+            }
+        }
+
+    public void preBreedingStatistics(final EvolutionState state)
+        {
+        super.preBreedingStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    public void postBreedingStatistics(final EvolutionState state) 
+        {
+        super.postBreedingStatistics(state);
+        state.output.print("" + (state.generation + 1) + " ", statisticslog); // 1 because we're putting the breeding info on the same line as the generation it *produces*, and the generation number is increased *after* breeding occurs, and statistics for it
+
+        // gather timings
+        if (doFull)
+            {
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();          
+            state.output.print("" + (System.currentTimeMillis()-lastTime) + " ",  statisticslog);
+            state.output.print("" + (curU-lastUsage) + " ",  statisticslog);            
+            }
+        }
+
+    public void preEvaluationStatistics(final EvolutionState state)
+        {
+        super.preEvaluationStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    /** Prints out the statistics, but does not end with a println --
+        this lets overriding methods print additional statistics on the same line */
+    protected void _postEvaluationStatistics(final EvolutionState state)
+        {
+        // gather timings
+        if (doFull)
+            {
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();          
+            state.output.print("" + (System.currentTimeMillis()-lastTime) + " ",  statisticslog);
+            state.output.print("" + (curU-lastUsage) + " ",  statisticslog);
+            }
+
+
+        Individual[] best_i = new Individual[state.population.subpops.length];  // quiets compiler complaints
+                
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            if (doFull)
+                {
+                long totNodesPerGen = 0;
+                long totDepthPerGen = 0;
+
+                // check to make sure they're the right class
+                if ( !(state.population.subpops[x].species instanceof GPSpecies ))
+                    state.output.fatal("Subpopulation " + x +
+                        " is not of the species form GPSpecies." + 
+                        "  Cannot do timing statistics with KozaShortStatistics.");
+                
+                long[] numNodes = new long[((GPIndividual)(state.population.subpops[x].species.i_prototype)).trees.length];
+                long[] numDepth = new long[((GPIndividual)(state.population.subpops[x].species.i_prototype)).trees.length];
+                
+                for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                    {
+                    GPIndividual i = 
+                        (GPIndividual)(state.population.subpops[x].individuals[y]);
+                    for(int z=0;z<i.trees.length;z++)
+                        {
+                        numNodes[z] += i.trees[z].child.numNodes(GPNode.NODESEARCH_ALL);
+                        numDepth[z] += i.trees[z].child.depth();
+                        }
+                    }
+                
+                for(int tr=0;tr<numNodes.length;tr++) totNodesPerGen += numNodes[tr];
+                
+                totalNodes[x] += totNodesPerGen;
+
+
+                state.output.print("" + ((double)totNodesPerGen)/state.population.subpops[x].individuals.length + " [",  statisticslog);
+
+                for(int tr=0;tr<numNodes.length;tr++)
+                    {
+                    if (tr>0) state.output.print("|", statisticslog);
+                    state.output.print(""+((double)numNodes[tr])/state.population.subpops[x].individuals.length, statisticslog);
+                    }
+                state.output.print("] ", statisticslog);
+
+                state.output.print("" + ((double)totalNodes[x])/(state.population.subpops[x].individuals.length * (state.generation + 1)) + " ",
+                    statisticslog);
+
+                for(int tr=0;tr<numDepth.length;tr++) totDepthPerGen += numDepth[tr];
+
+                totalDepths[x] += totDepthPerGen;
+
+                state.output.print("" + ((double)totDepthPerGen)/
+                        (state.population.subpops[x].individuals.length *
+                        numDepth.length) 
+                    + " [",  statisticslog);
+
+
+                for(int tr=0;tr<numDepth.length;tr++)
+                    {
+                    if (tr>0) state.output.print("|", statisticslog);
+                    state.output.print(""+((double)numDepth[tr])/state.population.subpops[x].individuals.length, statisticslog);
+                    }
+                state.output.print("] ", statisticslog);
+
+                state.output.print("" + ((double)totalDepths[x])/(state.population.subpops[x].individuals.length * (state.generation + 1)) + " ",
+                    statisticslog);
+                }
+            
+
+            
+            // fitness information
+            float meanStandardized = 0.0f;
+            float meanAdjusted = 0.0f;
+            long hits = 0;
+            
+            if (!(state.population.subpops[x].species.f_prototype instanceof KozaFitness))
+                state.output.fatal("Subpopulation " + x +
+                    " is not of the fitness KozaFitness.  Cannot do timing statistics with KozaStatistics.");
+
+            best_i[x] = null;
+            for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                {
+                // best individual
+                if (best_i[x]==null ||
+                    state.population.subpops[x].individuals[y].fitness.betterThan(best_i[x].fitness))
+                    best_i[x] = state.population.subpops[x].individuals[y];
+
+                // mean for population
+                meanStandardized += ((KozaFitness)(state.population.subpops[x].individuals[y].fitness)).standardizedFitness();
+                meanAdjusted += ((KozaFitness)(state.population.subpops[x].individuals[y].fitness)).adjustedFitness();
+                hits += ((KozaFitness)(state.population.subpops[x].individuals[y].fitness)).hits;
+                }
+            
+            // compute fitness stats
+            meanStandardized /= state.population.subpops[x].individuals.length;
+            meanAdjusted /= state.population.subpops[x].individuals.length;
+            state.output.print("" + meanStandardized + " " + meanAdjusted + " " + 
+                ((double)hits)/state.population.subpops[x].individuals.length + " ", 
+                statisticslog);
+            state.output.print("" + ((KozaFitness)(best_i[x].fitness)).standardizedFitness() +
+                " " + ((KozaFitness)(best_i[x].fitness)).adjustedFitness() +
+                " " + ((KozaFitness)(best_i[x].fitness)).hits + " ",
+                statisticslog);
+
+            // now test to see if it's the new best_of_run[x]
+            if (best_of_run[x]==null || best_i[x].fitness.betterThan(best_of_run[x].fitness))
+                best_of_run[x] = best_i[x];
+            
+            state.output.print("" + ((KozaFitness)(best_of_run[x].fitness)).standardizedFitness() +
+                " " + ((KozaFitness)(best_of_run[x].fitness)).adjustedFitness() +
+                " " + ((KozaFitness)(best_of_run[x].fitness)).hits + " ",
+                statisticslog);
+            }
+        // we're done!
+        }
+
+    public void postEvaluationStatistics(final EvolutionState state)
+        {
+        super.postEvaluationStatistics(state);
+        _postEvaluationStatistics(state);
+        state.output.println("", statisticslog);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/KozaStatistics.java	(revision 6152)
@@ -0,0 +1,377 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.steadystate.*;
+import ec.*;
+import ec.simple.*;
+import ec.gp.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * KozaStatistics.java
+ * 
+ * Created: Fri Nov  5 16:03:44 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A simple Koza-style statistics generator.  Prints the mean fitness 
+ * (raw,adjusted,hits) and best individual of each generation.
+ * At the end, prints the best individual of the run and the number of
+ * individuals processed.
+ *
+ * <p>If gather-full is true, then final timing information, number of nodes
+ * and depths of trees, approximate final memory utilization, etc. are also given.
+ *
+ * <p>Compressed files will be overridden on restart from checkpoint; uncompressed files will be 
+ * appended on restart.
+ *
+ * <p>KozaStatistics implements a simple version of steady-state statistics in the
+ * same fashion that SimpleStatistics does: if it quits before a generation boundary,
+ * it will include the best individual discovered, even if the individual was discovered
+ * after the last boundary.  This is done by using individualsEvaluatedStatistics(...)
+ * to update best-individual-of-generation in addition to doing it in
+ * postEvaluationStatistics(...).
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>gzip</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether or not to compress the file (.gz suffix added)</td></tr>
+ <tr><td valign=top><i>base.</i><tt>file</tt><br>
+ <font size=-1>String (a filename), or nonexistant (signifies stdout)</font></td>
+ <td valign=top>(the log for statistics)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>gather-full</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we full statistics on individuals (will run slower, though the slowness is due to off-line processing that won't mess up timings)</td></tr>
+ </table>
+ * @author Sean Luke
+ * @deprecated use SimpleStatistics instead
+ */
+
+public class KozaStatistics extends Statistics implements SteadyStateStatisticsForm
+    {
+    public Individual[] getBestSoFar() { return best_of_run; }
+
+    /** log file parameter */
+    public static final String P_STATISTICS_FILE = "file";
+
+    /** The Statistics' log */
+    public int statisticslog;
+
+    /** The best individual we've found so far */
+    public Individual[] best_of_run;
+
+    /** compress? */
+    public static final String P_COMPRESS = "gzip";
+
+    public static final String P_FULL = "gather-full";
+
+    boolean doFull;
+
+    // total number of individuals
+    long numInds;
+
+    // timings
+    long lastTime;
+    long initializationTime;
+    long breedingTime;
+    long evaluationTime;
+    long nodesInitialized;
+    long nodesEvaluated;
+    long nodesBred;
+
+    // memory usage info
+    long lastUsage = 0;
+    long initializationUsage = 0;
+    long breedingUsage = 0;
+    long evaluationUsage = 0;
+
+    public KozaStatistics() { best_of_run = null; statisticslog = 0; /* stdout */ }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+                
+        state.output.warnOnce("KozaStatistics is deprecated and will soon be deleted.  Use SimpleStatistics instead.");
+        
+        File statisticsFile = state.parameters.getFile(
+            base.push(P_STATISTICS_FILE),null);
+
+        if (statisticsFile!=null) try
+                                      {
+                                      statisticslog = state.output.addLog(statisticsFile,
+                                          !state.parameters.getBoolean(base.push(P_COMPRESS),null,false),
+                                          state.parameters.getBoolean(base.push(P_COMPRESS),null,false));
+                                      }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + statisticsFile + ":\n" + i);
+                }
+            
+        doFull = state.parameters.getBoolean(base.push(P_FULL),null,false);
+        nodesInitialized = nodesEvaluated = nodesBred = 0;
+        breedingTime=evaluationTime=0;
+        }
+
+
+    public void preInitializationStatistics(final EvolutionState state)
+        {
+        super.preInitializationStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    public void postInitializationStatistics(final EvolutionState state)
+        {
+        super.postInitializationStatistics(state);
+
+        // set up our best_of_run array -- can't do this in setup, because
+        // we don't know if the number of subpopulations has been determined yet
+        best_of_run = new Individual[state.population.subpops.length];
+
+        // gather timings       
+        if (doFull)
+            {
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();
+            if (curU > lastUsage) initializationUsage = curU - lastUsage;
+            initializationTime = System.currentTimeMillis()-lastTime;
+            
+            // Determine how many nodes we have
+            for(int x=0;x<state.population.subpops.length;x++)
+                {
+                // check to make sure they're the right class
+                if ( !(state.population.subpops[x].species instanceof GPSpecies ))
+                    state.output.fatal("Subpopulation " + x +
+                        " is not of the species form GPSpecies." + 
+                        "  Cannot do timing statistics with KozaStatistics.");
+                
+                for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                    {
+                    GPIndividual i = 
+                        (GPIndividual)(state.population.subpops[x].individuals[y]);
+                    for(int z=0;z<i.trees.length;z++)
+                        nodesInitialized += i.trees[z].child.numNodes(GPNode.NODESEARCH_ALL);
+                    }
+                }
+            }
+        }
+
+    public void preBreedingStatistics(final EvolutionState state)
+        {
+        super.preBreedingStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    public void postBreedingStatistics(final EvolutionState state) 
+        {
+        super.postBreedingStatistics(state);
+        // gather timings
+        if (doFull)
+            {
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();
+            if (curU > lastUsage) breedingUsage += curU - lastUsage;
+            breedingTime += System.currentTimeMillis()-lastTime;
+            
+            // Determine how many nodes we have
+            for(int x=0;x<state.population.subpops.length;x++)
+                {
+                // check to make sure they're the right class
+                if ( !(state.population.subpops[x].species instanceof GPSpecies ))
+                    state.output.fatal("Subpopulation " + x +
+                        " is not of the species form GPSpecies." + 
+                        "  Cannot do timing statistics with KozaStatistics.");
+                                
+                for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                    {
+                    GPIndividual i = 
+                        (GPIndividual)(state.population.subpops[x].individuals[y]);
+                    for(int z=0;z<i.trees.length;z++)
+                        nodesBred += i.trees[z].child.numNodes(GPNode.NODESEARCH_ALL);
+                    }
+                }
+            }
+        }
+
+    public void preEvaluationStatistics(final EvolutionState state)
+        {
+        super.preEvaluationStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    public void postEvaluationStatistics(final EvolutionState state)
+        {
+        super.postEvaluationStatistics(state);
+        
+        // Gather statistics
+        Runtime r = Runtime.getRuntime();
+        long curU =  r.totalMemory() - r.freeMemory();
+        if (curU > lastUsage) evaluationUsage += curU - lastUsage;
+        if (doFull) evaluationTime += System.currentTimeMillis()-lastTime;
+
+
+        state.output.println("\n\n\nGeneration " + state.generation + "\n================",statisticslog);
+
+        Individual[] best_i = new Individual[state.population.subpops.length];
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            state.output.println("\nSubpopulation " + x + "\n----------------",statisticslog);
+
+            // gather timings
+            if (doFull)
+                {
+                long totNodesPerGen = 0;
+                long totDepthPerGen = 0;
+                
+                // check to make sure they're the right class
+                if ( !(state.population.subpops[x].species instanceof GPSpecies ))
+                    state.output.fatal("Subpopulation " + x +
+                        " is not of the species form GPSpecies." + 
+                        "  Cannot do timing statistics with KozaStatistics.");
+                
+                long[] numNodes = new long[((GPIndividual)(state.population.subpops[x].species.i_prototype)).trees.length];
+                long[] numDepth = new long[((GPIndividual)(state.population.subpops[x].species.i_prototype)).trees.length];
+
+                for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                    {
+                    GPIndividual i = 
+                        (GPIndividual)(state.population.subpops[x].individuals[y]);
+                    for(int z=0;z<i.trees.length;z++)
+                        {
+                        nodesEvaluated += i.trees[z].child.numNodes(GPNode.NODESEARCH_ALL);
+                        numNodes[z] += i.trees[z].child.numNodes(GPNode.NODESEARCH_ALL);
+                        numDepth[z] += i.trees[z].child.depth();
+                        }
+                    }
+                
+                for(int tr=0;tr<numNodes.length;tr++) totNodesPerGen += numNodes[tr];
+                state.output.println("Avg Nodes: " + ((double)totNodesPerGen)/state.population.subpops[x].individuals.length, statisticslog);
+                state.output.print("Nodes/tree: [", statisticslog);
+                for(int tr=0;tr<numNodes.length;tr++)
+                    {
+                    if (tr>0) state.output.print("|", statisticslog);
+                    state.output.print(""+((double)numNodes[tr])/state.population.subpops[x].individuals.length, statisticslog);
+                    }
+                state.output.println("]", statisticslog);
+
+
+                for(int tr=0;tr<numDepth.length;tr++) totDepthPerGen += numDepth[tr];
+                state.output.println("Avg Depth: " + ((double)totDepthPerGen)/
+                    (state.population.subpops[x].individuals.length * numDepth.length), statisticslog);
+                state.output.print("Depth/tree: [", statisticslog);
+                for(int tr=0;tr<numDepth.length;tr++)
+                    {
+                    if (tr>0) state.output.print("|", statisticslog);
+                    state.output.print(""+((double)numDepth[tr])/state.population.subpops[x].individuals.length, statisticslog);
+                    }
+                state.output.println("]", statisticslog);
+
+                }           
+            
+            
+            float meanStandardized = 0.0f;
+            float meanAdjusted = 0.0f;
+            long hits = 0;
+
+            if (!(state.population.subpops[x].species.f_prototype instanceof KozaFitness))
+                state.output.fatal("Subpopulation " + x +
+                    " is not of the fitness KozaFitness.  Cannot do timing statistics with KozaStatistics.");
+                
+
+            best_i[x] = state.population.subpops[x].individuals[0];
+            for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                {
+                // best individual
+                if (state.population.subpops[x].individuals[y].fitness.betterThan(best_i[x].fitness))
+                    best_i[x] = state.population.subpops[x].individuals[y];
+                // mean for population
+                meanStandardized += ((KozaFitness)(state.population.subpops[x].individuals[y].fitness)).standardizedFitness();
+                meanAdjusted += ((KozaFitness)(state.population.subpops[x].individuals[y].fitness)).adjustedFitness();
+                hits += ((KozaFitness)(state.population.subpops[x].individuals[y].fitness)).hits;
+                }
+
+            // compute fitness stats
+            meanStandardized /= state.population.subpops[x].individuals.length;
+            meanAdjusted /= state.population.subpops[x].individuals.length;
+            state.output.print("Mean fitness raw: " + meanStandardized + " adjusted: " + meanAdjusted + " hits: " + ((double)hits)/state.population.subpops[x].individuals.length, statisticslog);
+                    
+            state.output.println("", statisticslog);
+
+            // compute inds stats
+            numInds += state.population.subpops[x].individuals.length;
+            }
+
+        // now test to see if it's the new best_of_run
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            if (best_of_run[x]==null || best_i[x].fitness.betterThan(best_of_run[x].fitness))
+                best_of_run[x] = (Individual)(best_i[x].clone());
+
+            // print the best-of-generation individual
+            state.output.println("\nBest Individual of Generation:",statisticslog);
+            best_i[x].printIndividualForHumans(state,statisticslog);
+            state.output.message("Subpop " + x + " best fitness of generation: " + best_i[x].fitness.fitnessToStringForHumans());
+            }
+        }
+
+
+    /** Logs the best individual of the run. */
+    public void finalStatistics(final EvolutionState state, final int result)
+        {
+        super.finalStatistics(state,result);
+        
+        state.output.println("\n\n\nFinal Statistics\n================",statisticslog);
+
+        state.output.println("Total Individuals Evaluated: " + numInds,statisticslog);
+        // for now we just print the best fitness 
+        
+        state.output.println("\nBest Individual of Run:",statisticslog);
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            best_of_run[x].printIndividualForHumans(state,statisticslog);
+            state.output.message("Subpop " + x + " best fitness of run: " + best_of_run[x].fitness.fitnessToStringForHumans());
+
+            // finally describe the winner if there is a description
+            ((SimpleProblemForm)(state.evaluator.p_problem.clone())).describe(state, best_of_run[x], x, 0, statisticslog);  
+            }
+
+        // Output timings
+        if (doFull)
+            {
+            state.output.println("\n\n\nTimings\n=======",statisticslog);
+
+            state.output.println("Initialization: " + ((float)initializationTime)/1000 + " secs total, " + nodesInitialized + " nodes, " + nodesInitialized/(((float)initializationTime)/1000) + " nodes/sec",statisticslog);
+            state.output.println("Evaluating: " + ((float)evaluationTime)/1000 + " secs total, " + nodesEvaluated + " nodes, " + nodesEvaluated/(((float)evaluationTime)/1000) + " nodes/sec",statisticslog);
+            state.output.println("Breeding: " + ((float)breedingTime)/1000 + " secs total, " + nodesBred + " nodes, " + nodesBred/(((float)breedingTime)/1000) + " nodes/sec",statisticslog);
+
+            state.output.println("\n\n\nMemory Usage\n==============",statisticslog);
+            state.output.println("Initialization: " + ((float)initializationUsage)/1024 + " KB total, " + nodesInitialized + " nodes, " + nodesInitialized/(((float)initializationUsage)/1024) + " nodes/KB",statisticslog);
+            state.output.println("Evaluating: " + ((float)evaluationUsage)/1024 + " KB total, " + nodesEvaluated + " nodes, " + nodesEvaluated/(((float)evaluationUsage)/1024) + " nodes/KB",statisticslog);
+            state.output.println("Breeding: " + ((float)breedingUsage)/1024 + " KB total, " + nodesBred + " nodes, " + nodesBred/(((float)breedingUsage)/1024) + " nodes/KB",statisticslog);            
+            }
+        
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/MutationPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/MutationPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/MutationPipeline.java	(revision 6152)
@@ -0,0 +1,326 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.gp.koza;
+import ec.*;
+import ec.util.*;
+import ec.gp.*;
+
+/* 
+ * MutationPipeline.java
+ * 
+ * Created: Tue Oct 12 18:50:56 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MutationPipeline is a GPBreedingPipeline which 
+ * implements a strongly-typed version of the 
+ * "Point Mutation" operator as described in Koza I.
+ * Actually, that's not quite true.  Koza doesn't have any tree depth restrictions
+ * on his mutation operator.  This one does -- if the tree gets deeper than
+ * the maximum tree depth, then the new subtree is rejected and another one is
+ * tried.  Similar to how the Crosssover operator is implemented.
+ *
+ * <p>Mutated trees are restricted to being <tt>maxdepth</tt> depth at most.
+ * If in <tt>tries</tt> attemptes, the pipeline cannot come up with a mutated
+ * tree within the depth limit, then it simply copies the original individual
+ * wholesale with no mutation.
+ *
+ * <p>One additional feature: if <tt>equal</tt> is true, then MutationPipeline
+ * will attempt to replace the subtree with a tree of approximately equal size.
+ * How this is done exactly, and how close it is, is entirely up to the pipeline's
+ * tree builder -- for example, Grow/Full/HalfBuilder don't support this at all, while
+ * RandomBranch will replace it with a tree of the same size or "slightly smaller"
+ * as described in the algorithm.
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ ...as many as the child produces
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>maxdepth</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(maximum valid depth of a crossed-over subtree)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
+ <font size=-1>classname, inherits and != GPNodeSelector</font></td>
+ <td valign=top>(GPNodeSelector for tree)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>build</tt>.0<br>
+ <font size=-1>classname, inherits and != GPNodeBuilder</font></td>
+ <td valign=top>(GPNodeBuilder for new subtree)</td></tr>
+
+ <tr><td valign=top><tt>equal</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
+ <td valign=top>(do we attempt to replace the subtree with a new one of roughly the same size?)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
+ <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
+ <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ gp.koza.mutate
+
+ <p><b>Parameter bases</b><br>
+ <table>
+
+ <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
+ <td>nodeselect</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>build</tt><br>
+ <td>builder</td></tr>
+
+ </table>
+
+
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MutationPipeline extends GPBreedingPipeline
+    {
+    public static final String P_NUM_TRIES = "tries";
+    public static final String P_MAXDEPTH = "maxdepth";
+    public static final String P_MUTATION = "mutate";
+    public static final String P_BUILDER = "build";
+    public static final String P_EQUALSIZE = "equal";
+    public static final int INDS_PRODUCED = 1;
+    public static final int NUM_SOURCES = 1;
+
+    /** How the pipeline chooses a subtree to mutate */
+    public GPNodeSelector nodeselect;
+
+    /** How the pipeline builds a new subtree */
+    public GPNodeBuilder builder;
+
+    /** The number of times the pipeline tries to build a valid mutated
+        tree before it gives up and just passes on the original */
+    int numTries;
+    
+    /** The maximum depth of a mutated tree */
+    int maxDepth;
+
+    /** Do we try to replace the subtree with another of the same size? */
+    boolean equalSize;
+
+    /** Is our tree fixed?  If not, this is -1 */
+    int tree;
+
+    public Parameter defaultBase() { return GPKozaDefaults.base().push(P_MUTATION); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        MutationPipeline c = (MutationPipeline)(super.clone());
+
+        // deep-cloned stuff
+        c.nodeselect = (GPNodeSelector)(nodeselect.clone());
+
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+        Parameter p = base.push(P_NODESELECTOR).push(""+0);
+        Parameter d = def.push(P_NODESELECTOR).push(""+0);
+
+        nodeselect = (GPNodeSelector)
+            (state.parameters.getInstanceForParameter(
+                p,d, GPNodeSelector.class));
+        nodeselect.setup(state,p);
+
+        p = base.push(P_BUILDER).push(""+0);
+        d = def.push(P_BUILDER).push(""+0);
+
+        builder = (GPNodeBuilder)
+            (state.parameters.getInstanceForParameter(
+                p,d, GPNodeBuilder.class));
+        builder.setup(state,p);
+
+        numTries = state.parameters.getInt(
+            base.push(P_NUM_TRIES),def.push(P_NUM_TRIES),1);
+        if (numTries ==0)
+            state.output.fatal("Mutation Pipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
+
+        maxDepth = state.parameters.getInt(
+            base.push(P_MAXDEPTH),def.push(P_MAXDEPTH),1);
+        if (maxDepth==0)
+            state.output.fatal("The Mutation Pipeline " + base + "has an invalid maximum depth (it must be >= 1).",base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
+
+        equalSize = state.parameters.getBoolean(
+            base.push(P_EQUALSIZE),def.push(P_EQUALSIZE),false);
+
+        tree = TREE_UNFIXED;
+        if (state.parameters.exists(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0)))
+            {
+            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
+                def.push(P_TREE).push(""+0),0);
+            if (tree==-1)
+                state.output.fatal("Tree fixed value, if defined, must be >= 0");
+            }
+        }
+
+
+    /** Returns true if inner1 can feasibly be swapped into inner2's position */
+
+    public boolean verifyPoints(GPNode inner1, GPNode inner2)
+        {
+        // We know they're swap-compatible since we generated inner1
+        // to be exactly that.  So don't bother.
+
+        // next check to see if inner1 can fit in inner2's spot
+        if (inner1.depth()+inner2.atDepth() > maxDepth) return false;
+
+        // checks done!
+        return true;
+        }
+
+
+
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+        GPInitializer initializer = ((GPInitializer)state.initializer);
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            GPIndividual i = (GPIndividual)inds[q];
+
+            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
+                // uh oh
+                state.output.fatal("GP Mutation Pipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual"); 
+                
+
+            int t;
+            // pick random tree
+            if (tree==TREE_UNFIXED)
+                if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
+                else t = 0;
+            else t = tree;
+
+            // validity result...
+            boolean res = false;
+            
+            // prepare the nodeselector
+            nodeselect.reset();
+            
+            // pick a node
+            
+            GPNode p1=null;  // the node we pick
+            GPNode p2=null;
+            
+            for(int x=0;x<numTries;x++)
+                {
+                // pick a node in individual 1
+                p1 = nodeselect.pickNode(state,subpopulation,thread,i,i.trees[t]);
+                
+                // generate a tree swap-compatible with p1's position
+                
+                
+                int size = GPNodeBuilder.NOSIZEGIVEN;
+                if (equalSize) size = p1.numNodes(GPNode.NODESEARCH_ALL);
+
+                p2 = builder.newRootedTree(state,
+                    p1.parentType(initializer),
+                    thread,
+                    p1.parent,
+                    i.trees[t].constraints(initializer).functionset,
+                    p1.argposition,
+                    size);
+                
+                // check for depth and swap-compatibility limits
+                res = verifyPoints(p2,p1);  // p2 can fit in p1's spot  -- the order is important!
+                
+                // did we get something that had both nodes verified?
+                if (res) break;
+                }
+            
+            GPIndividual j;
+
+            if (sources[0] instanceof BreedingPipeline)
+                // it's already a copy, so just smash the tree in
+                {
+                j=i;
+                if (res)  // we're in business
+                    {
+                    p2.parent = p1.parent;
+                    p2.argposition = p1.argposition;
+                    if (p2.parent instanceof GPNode)
+                        ((GPNode)(p2.parent)).children[p2.argposition] = p2;
+                    else ((GPTree)(p2.parent)).child = p2;
+                    j.evaluated = false;  // we've modified it
+                    }
+                }
+            else // need to clone the individual
+                {
+                j = (GPIndividual)(i.lightClone());
+                
+                // Fill in various tree information that didn't get filled in there
+                j.trees = new GPTree[i.trees.length];
+                
+                // at this point, p1 or p2, or both, may be null.
+                // If not, swap one in.  Else just copy the parent.
+                for(int x=0;x<j.trees.length;x++)
+                    {
+                    if (x==t && res)  // we've got a tree with a kicking cross position!
+                        {
+                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                        j.trees[x].owner = j;
+                        j.trees[x].child = i.trees[x].child.cloneReplacingNoSubclone(p2,p1);
+                        j.trees[x].child.parent = j.trees[x];
+                        j.trees[x].child.argposition = 0;
+                        j.evaluated = false; 
+                        } // it's changed
+                    else 
+                        {
+                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
+                        j.trees[x].owner = j;
+                        j.trees[x].child = (GPNode)(i.trees[x].child.clone());
+                        j.trees[x].child.parent = j.trees[x];
+                        j.trees[x].child.argposition = 0;                   
+                        }
+                    }
+                }
+            
+            // add the new individual, replacing its previous source
+            inds[q] = j;
+            }
+        return n;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/README	(revision 6152)
@@ -0,0 +1,30 @@
+See the README file in the superdiretoctory (ecj/ec/gp/), which describes
+the files in this directory as well.  Some specifics not described there:
+
+
+ec.gp.koza.CrossoverPipeline
+
+A GPBreedingPipeline which performs subtree crossover.
+
+
+ec.gp.koza.MutationPipeline
+
+A GPBreedingPipeline which performs subtree mutation (replacing a randomly
+chosen subtree with a randomly-generated subtree).
+
+
+ec.gp.GrowBuilder
+
+A GPNodeBuilder which implements Koza's GROW algorithm.
+
+
+ec.gp.FullBuilder
+
+A GPNodeBuilder which implements Koza's FULL algorithm.
+
+
+ec.gp.HalfBuilder
+
+A GPNodeBuilder which implements Koza's RAMPED HALF-AND-HALF algorithm.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/koza.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/koza.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/koza.params	(revision 6152)
@@ -0,0 +1,272 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+#
+# This file roughly defines a typeless, Koza-I-style
+# generational GP system with a single tree (meaning
+# no ADFs or ADMs.  We use Tournament selection instead
+# of Koza-style Fitness-proportionate selection because
+# fitness-proportionate selection, well, is kinda icky.
+#
+
+# We're derived some of this
+# from ../../simple/params, which defines
+# generational, basic evolutionary mechanisms, selection mechanisms...
+
+parent.0 = ../../simple/simple.params
+
+
+#
+# We define the fitness of an individual to use the traditional
+# Koza-style fitness metrics, just to make everyone happy :-)
+#
+
+pop.subpop.0.species.fitness = ec.gp.koza.KozaFitness
+
+#
+# We have a GP-specific initializer.  But we'll keep the
+# statistics as a SimpleStatistics (defined in simple.params)
+
+init = ec.gp.GPInitializer
+
+
+# We have a single subpopulation containing a GPSpecies,
+# using GPIndividuals as the prototypical individual class.
+
+pop.subpop.0.species = ec.gp.GPSpecies
+pop.subpop.0.species.ind = ec.gp.GPIndividual
+
+# We retry 100 times for duplicates (this is the lil-gp default)
+# in our subpopulation 0
+
+pop.subpop.0.duplicate-retries = 100
+
+# That GPIndividual has a single tree, which uses the
+# "tc0" Tree Constraints (which we define below later)
+
+pop.subpop.0.species.ind.numtrees = 1
+pop.subpop.0.species.ind.tree.0 = ec.gp.GPTree
+pop.subpop.0.species.ind.tree.0.tc = tc0
+
+
+# The GPSpecies has 2 pipelines, Crossover and Reproduction,
+# chosen with 0.9 and 0.1 likelihood respectively.
+
+pop.subpop.0.species.pipe = ec.breed.MultiBreedingPipeline
+# Koza's decision here was odd...
+pop.subpop.0.species.pipe.generate-max = false
+# Subsidiary pipelines:
+pop.subpop.0.species.pipe.num-sources = 2
+pop.subpop.0.species.pipe.source.0 = ec.gp.koza.CrossoverPipeline
+pop.subpop.0.species.pipe.source.0.prob = 0.9
+pop.subpop.0.species.pipe.source.1 = ec.breed.ReproductionPipeline
+pop.subpop.0.species.pipe.source.1.prob = 0.1
+
+
+
+
+#
+# Here we define the default values for Crossover,
+# Reproduction, Mutation, as well as our selection
+# approaches (Koza I).  These can be overridden on a per-species
+# level of course.
+#
+
+# Reproduction will use Tournament Selection 
+breed.reproduce.source.0 = ec.select.TournamentSelection
+
+# Crossover will use Tournament Selection, try only 1
+# time, have a max depth of 17, and use KozaNodeSelector
+gp.koza.xover.source.0 = ec.select.TournamentSelection
+gp.koza.xover.source.1 = same
+gp.koza.xover.ns.0 = ec.gp.koza.KozaNodeSelector
+gp.koza.xover.ns.1 = same
+gp.koza.xover.maxdepth = 17
+# This is the default for Koza and lil-gp, though it's
+# a little wimpy; on the other hand, a higher number can
+# make things really slow
+gp.koza.xover.tries = 1
+
+
+
+
+# Point Mutation will use Tournament Selection, try only 1
+# time, have a max depth of 17, and use KozaNodeSelector
+# and GROW for building.  Also, Point Mutation uses a GrowBuilder
+# by default, with a default of min-depth=max-depth=5
+# as shown a ways below
+gp.koza.mutate.source.0 = ec.select.TournamentSelection
+gp.koza.mutate.ns.0 = ec.gp.koza.KozaNodeSelector
+gp.koza.mutate.build.0 = ec.gp.koza.GrowBuilder
+gp.koza.mutate.maxdepth = 17
+# This is the default for Koza and lil-gp, though it's
+# a little wimpy; on the other hand, a higher number can
+# make things really slow
+gp.koza.mutate.tries = 1
+
+
+
+
+#
+# The default tournament size for TournamentSelection is 7
+#
+
+select.tournament.size = 7
+
+
+
+
+# Since GROW is only used for subtree mutation, ECJ uses
+# the Koza-standard subtree mutation GROW values for the
+# default for GROW as a whole.  This default is
+# min-depth=max-depth=5, which I don't like very much,
+# but hey, that's the standard.  
+# This means that if someone decided to use GROW to generate
+# new individual trees, it's also use the defaults below
+# unless he overrided them locally.
+gp.koza.grow.min-depth = 5
+gp.koza.grow.max-depth = 5
+
+
+
+#
+# We specify a few things about ADFs  -- what kind 
+# of stack they use, and what kind of context
+#
+
+gp.problem.stack = ec.gp.ADFStack
+gp.adf-stack.context = ec.gp.ADFContext
+
+# 
+# Here we define the default values for KozaNodeSelection;
+# as always, these can be overridden by values hanging off
+# of the Crossover/Reproduction/Mutation/whatever pipelines,
+# like we did for node-building, but hey, whatever. 
+# The default is 10% terminals, 90% nonterminals when possible,
+# 0% "always pick the root", 0% "pick any node"
+
+gp.koza.ns.terminals = 0.1
+gp.koza.ns.nonterminals = 0.9
+gp.koza.ns.root = 0.0
+
+
+
+
+# You need to create at least one function set, 
+# called "f0", which your first tree will use.  
+# You don't need to include the class declaration here,
+# but it quiets warnings.
+
+gp.fs.size = 1
+gp.fs.0 = ec.gp.GPFunctionSet
+gp.fs.0.name = f0
+#fill the rest of this out on a per-problem basis
+
+
+# Here we define a single atomic type, "nil", which everyone will use.
+# There are no set types defined.
+
+gp.type.a.size = 1
+gp.type.a.0.name = nil
+gp.type.s.size = 0
+
+# Here we define one GPTreeConstraints object, "tc0",
+# which uses ec.gp.koza.HalfBuilder to create nodes,
+# only allows nodes from the GPFunctionSet "fset",
+# and has the single type "nil" as its tree type.
+# You don't need to include the class declaration here,
+# but it quiets warnings.
+
+gp.tc.size = 1
+gp.tc.0 = ec.gp.GPTreeConstraints
+gp.tc.0.name = tc0
+gp.tc.0.fset = f0
+gp.tc.0.returns = nil
+
+# The tree uses an ec.gp.koza.HalfBuilder to create
+# itself initially.
+# HalfBuilder will pick GROW half the time and FULL
+# the other half, with a ramp from 2 to 6 inclusive.
+# By ramp we mean that it first picks a random number between
+# 2 and 6 inclusive.  This then becomes the *maximum* tree size
+# (for the FULL approach, it's the tree size of the tree, for
+# GROW, the tree can get no bigger than this)
+
+gp.tc.0.init = ec.gp.koza.HalfBuilder
+
+# We set the default for HalfBuilder to be a ramp of 2--6,
+# with a grow probability of 0.5
+gp.koza.half.min-depth = 2
+gp.koza.half.max-depth = 6
+gp.koza.half.growp = 0.5
+
+
+
+
+# Here we define 7 GPNodeConstraints, nc0...nc6, which
+# describe nodes with 0...6 children respectively, which only
+# use a single type, "nil", for their argument and return types
+# You don't need to include the class declarations with everything
+# else below, but it quiets warnings
+
+gp.nc.size = 7
+
+gp.nc.0 = ec.gp.GPNodeConstraints
+gp.nc.0.name = nc0
+gp.nc.0.returns = nil
+gp.nc.0.size = 0
+
+gp.nc.1 = ec.gp.GPNodeConstraints
+gp.nc.1.name = nc1
+gp.nc.1.returns = nil
+gp.nc.1.size = 1
+gp.nc.1.child.0 = nil
+
+gp.nc.2 = ec.gp.GPNodeConstraints
+gp.nc.2.name = nc2
+gp.nc.2.returns = nil
+gp.nc.2.size = 2
+gp.nc.2.child.0 = nil
+gp.nc.2.child.1 = nil
+
+gp.nc.3 = ec.gp.GPNodeConstraints
+gp.nc.3.name = nc3
+gp.nc.3.returns = nil
+gp.nc.3.size = 3
+gp.nc.3.child.0 = nil
+gp.nc.3.child.1 = nil
+gp.nc.3.child.2 = nil
+
+gp.nc.4 = ec.gp.GPNodeConstraints
+gp.nc.4.name = nc4
+gp.nc.4.returns = nil
+gp.nc.4.size = 4
+gp.nc.4.child.0 = nil
+gp.nc.4.child.1 = nil
+gp.nc.4.child.2 = nil
+gp.nc.4.child.3 = nil
+
+gp.nc.5 = ec.gp.GPNodeConstraints
+gp.nc.5.name = nc5
+gp.nc.5.returns = nil
+gp.nc.5.size = 5
+gp.nc.5.child.0 = nil
+gp.nc.5.child.1 = nil
+gp.nc.5.child.2 = nil
+gp.nc.5.child.3 = nil
+gp.nc.5.child.4 = nil
+
+gp.nc.6 = ec.gp.GPNodeConstraints
+gp.nc.6.name = nc6
+gp.nc.6.returns = nil
+gp.nc.6.size = 6
+gp.nc.6.child.0 = nil
+gp.nc.6.child.1 = nil
+gp.nc.6.child.2 = nil
+gp.nc.6.child.3 = nil
+gp.nc.6.child.4 = nil
+gp.nc.6.child.5 = nil
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveDefaults.java	(revision 6152)
@@ -0,0 +1,33 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.multiobjective;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * MultiObjectiveDefaults.java
+ * 
+ * Created: Thu Jan 20 17:16:09 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class MultiObjectiveDefaults implements DefaultsForm 
+    {
+    public static final String P_MULTI = "multi";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_MULTI);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveFitness.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveFitness.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveFitness.java	(revision 6152)
@@ -0,0 +1,536 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective;
+
+import java.io.*;
+import ec.util.DecodeReturn;
+import ec.util.Parameter;
+import ec.util.Code;
+import ec.Fitness;
+import ec.EvolutionState;
+import java.util.*;
+import ec.*;
+
+/* 
+ * MultiObjectiveFitness.java
+ * 
+ * Created: Tue Aug 10 20:27:38 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MultiObjectiveFitness is a subclass of Fitness which implements basic
+ * multi-objective mechanisms suitable for being used with a variety of
+ * multi-objective selection mechanisms, including ones using pareto-optimality.
+ * 
+ * <p>
+ * The object contains two items: an array of floating point values representing
+ * the various multiple fitnesses, and a flag (maximize) indicating whether
+ * higher is considered better. By default, isIdealFitness() always returns
+ * false; you might want to override that, though it'd be unusual -- what is the
+ * ideal fitness from the perspective of a pareto front?
+ * 
+ * <p>
+ * The object also contains maximum and minimum fitness values suggested for the
+ * problem, on a per-objective basis. By default the maximum values are all 1.0
+ * and the minimum values are all 0.0, but you can change these. Note that
+ * maximum does not mean "best" unless maximize is true.
+ *
+ * <p>The class also contains utility methods or computing pareto dominance, 
+ * Pareto Fronts and Pareto Front Ranks, and distance in multiobjective space.
+ * The default comparison operators use Pareto Dominance, though this is often
+ * overridden by subclasses.
+ *
+ * <p>The fitness() method returns the maximum of the fitness values, which is
+ * clearly nonsensical: you should not be using this method.
+ * 
+ * <p>Subclasses of this class may add certain auxiliary fitness measures which
+ * are printed out by MultiObjectiveStatistics along with the multiple objectives.
+ * To have these values printed out, override the getAuxiliaryFitnessNames()
+ * and getAuxiliaryFitnessValues() methods.
+ *
+ * <p>
+ * <b>Parameters</b><br>
+ * <table>
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>num-objectives</tt><br>
+ * (else)<tt>multi.num-objectives</tt><br>
+ * <font size=-1>int &gt;= 1</font></td>
+ * <td valign=top>(the number of fitnesses in the objectives array)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>maximize</tt><br>
+ * <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ * <td valign=top>(are higher values considered "better"?)
+ * </table>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>max</tt><br>
+ * <font size=-1> float (<tt>1.0</tt> default)</font></td>
+ * <td valign=top>(maximum fitness value for all objectives)</table>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>max</tt>.<i>i</i><br>
+ * <font size=-1> float (<tt>1.0</tt> default)</font></td>
+ * <td valign=top>(maximum fitness value for objective <i>i</i>. Overrides the
+ * all-objective maximum fitness.)</table>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>min</tt><br>
+ * <font size=-1> float (<tt>0.0</tt> (default)</font></td>
+ * <td valign=top>(minimum fitness value for all objectives)</table>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>min</tt>.<i>i</i><br>
+ * <font size=-1> float = <tt>0.0</tt> (default)</font></td>
+ * <td valign=top>(minimum fitness value for objective <i>i</i>. Overrides the
+ * all-objective minimum fitness.)</table>
+ * 
+ * <p>
+ * <b>Default Base</b><br>
+ * multi.fitness
+ * 
+ * @author Sean Luke
+ * @version 1.1
+ */
+
+public class MultiObjectiveFitness extends Fitness
+    {
+    public static final String MULTI_FITNESS_POSTAMBLE = "[";
+    public static final String FITNESS_POSTAMBLE = "]";
+
+    /** parameter for size of objectives */
+    public static final String P_NUMOBJECTIVES = "num-objectives";
+
+    /** parameter for max fitness values */
+    public static final String P_MAXOBJECTIVES = "max";
+
+    /** parameter for min fitness values */
+    public static final String P_MINOBJECTIVES = "min";
+
+    /** Is higher better? */
+    public static final String P_MAXIMIZE = "maximize";
+
+    /** Desired maximum fitness values. By default these are 1.0. Shared. */
+    public float[] maxObjective;
+
+    /** Desired minimum fitness values. By default these are 0.0. Shared. */
+    public float[] minObjective;
+
+    /** The various fitnesses. */
+    protected float[] objectives; // values range from 0 (worst) to 1 INCLUSIVE
+    protected boolean maximize = true;
+
+    /** Returns auxilliary fitness value names to be printed by the statistics object.
+        By default, an empty array is returned, but various algorithms may override this to provide additional columns.
+    */
+    public String[] getAuxilliaryFitnessNames() { return new String[] { }; }
+
+    /** Returns auxilliary fitness values to be printed by the statistics object.
+        By default, an empty array is returned, but various algorithms may override this to provide additional columns.
+    */
+    public double[] getAuxilliaryFitnessValues() { return new double[] { }; }
+
+    public boolean isMaximizing()
+        {
+        return maximize;
+        }
+
+
+    public int getNumObjectives() { return objectives.length; }
+        
+    /**
+     * Returns the objectives as an array. Note that this is the *actual array*.
+     * Though you could set values in this array, you should NOT do this --
+     * rather, set them using setObjectives().
+     */
+    public float[] getObjectives()
+        {
+        return objectives;
+        }
+
+    public float getObjective(int i)
+        {
+        return objectives[i];
+        }
+
+    public void setObjectives(final EvolutionState state, float[] newObjectives)
+        {
+        if (newObjectives == null)
+            {
+            state.output.fatal("Null objective array provided to MultiObjectiveFitness.");
+            }
+        if (newObjectives.length != objectives.length)
+            {
+            state.output.fatal("New objective array length does not match current length.");
+            }
+        for (int i = 0; i < newObjectives.length; i++)
+            {
+            float _f = newObjectives[i];
+            if (_f == Float.POSITIVE_INFINITY || _f == Float.NEGATIVE_INFINITY || Float.isNaN(_f))
+                {
+                state.output.warning("Bad objective #" + i + ": " + _f + ", setting to worst value for that objective.");
+                if (maximize)
+                    newObjectives[i] = minObjective[i];
+                else
+                    newObjectives[i] = maxObjective[i];
+                }
+            }
+        objectives = newObjectives;
+        }
+
+    public Parameter defaultBase()
+        {
+        return MultiObjectiveDefaults.base().push(P_FITNESS);
+        }
+
+    public Object clone()
+        {
+        MultiObjectiveFitness f = (MultiObjectiveFitness) (super.clone());
+        f.objectives = (float[]) (objectives.clone()); // cloning an array
+
+        // note that we do NOT clone max and min fitness -- they're shared
+        return f;
+        }
+
+    /**
+     * Returns the Max() of objectives, which adheres to Fitness.java's protocol
+     * for this method. Though you should not rely on a selection or statistics
+     * method which requires this.
+     */
+    public float fitness()
+        {
+        float fit = objectives[0];
+        for (int x = 1; x < objectives.length; x++)
+            if (fit < objectives[x])
+                fit = objectives[x];
+        return fit;
+        }
+
+    /**
+     * Sets up. This must be called at least once in the prototype before
+     * instantiating any fitnesses that will actually be used in evolution.
+     */
+
+    public void setup(EvolutionState state, Parameter base)
+        {
+        super.setup(state, base); // unnecessary really
+
+        Parameter def = defaultBase();
+        int numFitnesses;
+
+        numFitnesses = state.parameters.getInt(base.push(P_NUMOBJECTIVES), def.push(P_NUMOBJECTIVES), 0);
+        if (numFitnesses <= 0)
+            state.output.fatal("The number of objectives must be an integer >= 1.", base.push(P_NUMOBJECTIVES), def.push(P_NUMOBJECTIVES));
+
+        maximize = state.parameters.getBoolean(base.push(P_MAXIMIZE), def.push(P_MAXIMIZE), true);
+
+        objectives = new float[numFitnesses];
+        maxObjective = new float[numFitnesses];
+        minObjective = new float[numFitnesses];
+
+        for (int i = 0; i < numFitnesses; i++)
+            {
+            // load default globals
+            minObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MINOBJECTIVES), def.push(P_MINOBJECTIVES), 0.0f);
+            maxObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MAXOBJECTIVES), def.push(P_MAXOBJECTIVES), 1.0f);
+
+            // load specifics if any
+            minObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MINOBJECTIVES).push("" + i), def.push(P_MINOBJECTIVES).push("" + i), minObjective[i]);
+            maxObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MAXOBJECTIVES).push("" + i), def.push(P_MAXOBJECTIVES).push("" + i), maxObjective[i]);
+            
+            // test for validity
+            if (minObjective[i] >= maxObjective[i])
+                state.output.error("For objective " + i + "the min fitness must be strictly less than the max fitness.");
+            }
+        state.output.exitIfErrors();
+        }
+
+    /**
+     * Returns true if this fitness is the "ideal" fitness. Default always
+     * returns false. You may want to override this.
+     */
+    public boolean isIdealFitness()
+        {
+        return false;
+        }
+
+    /**
+     * Returns true if I'm equivalent in fitness (neither better nor worse) to
+     * _fitness. The rule I'm using is this: If one of us is better in one or
+     * more criteria, and we are equal in the others, then equivalentTo is
+     * false. If each of us is better in one or more criteria each, or we are
+     * equal in all criteria, then equivalentTo is true.   Multiobjective optimization algorithms may
+     * choose to override this to do something else.
+     */
+
+    public boolean equivalentTo(Fitness _fitness)
+        {
+        MultiObjectiveFitness other = (MultiObjectiveFitness) _fitness;
+        boolean abeatsb = false;
+        boolean bbeatsa = false;
+
+        if (maximize != other.maximize)
+            throw new RuntimeException(
+                "Attempt made to compare two multiobjective fitnesses; but one expects higher values to be better and the other expectes lower values to be better.");
+        if (objectives.length != other.objectives.length)
+            throw new RuntimeException("Attempt made to compare two multiobjective fitnesses; but they have different numbers of objectives.");
+        if (maximize)
+            {
+            for (int x = 0; x < objectives.length; x++)
+                {
+                if (objectives[x] > other.objectives[x])
+                    abeatsb = true;
+                if (objectives[x] < other.objectives[x])
+                    bbeatsa = true;
+                if (abeatsb && bbeatsa)
+                    return true;
+                }
+            }
+        else
+            // lower is better
+            {
+            for (int x = 0; x < objectives.length; x++)
+                {
+                if (objectives[x] < other.objectives[x])
+                    abeatsb = true;
+                if (objectives[x] > other.objectives[x])
+                    bbeatsa = true;
+                if (abeatsb && bbeatsa)
+                    return true;
+                }
+            }
+        if (abeatsb || bbeatsa)
+            return false;
+        return true;
+        }
+
+    /**
+     * Returns true if I'm better than _fitness. The DEFAULT rule I'm using is this: if
+     * I am better in one or more criteria, and we are equal in the others, then
+     * betterThan is true, else it is false. Multiobjective optimization algorithms may
+     * choose to override this to do something else.
+     */
+
+    public boolean betterThan(Fitness fitness)
+        {
+        return paretoDominates((MultiObjectiveFitness)fitness);
+        }
+
+    /**
+     * Returns true if I'm better than _fitness. The rule I'm using is this: if
+     * I am better in one or more criteria, and we are equal in the others, then
+     * betterThan is true, else it is false.
+     */
+
+    public boolean paretoDominates(MultiObjectiveFitness other)
+        {
+        boolean abeatsb = false;
+        if (maximize != other.maximize)
+            throw new RuntimeException(
+                "Attempt made to compare two multiobjective fitnesses; but one expects higher values to be better and the other expectes lower values to be better.");
+        if (objectives.length != other.objectives.length)
+            throw new RuntimeException("Attempt made to compare two multiobjective fitnesses; but they have different numbers of objectives.");
+        if (maximize)
+            {
+            for (int x = 0; x < objectives.length; x++)
+                {
+                if (objectives[x] > other.objectives[x])
+                    abeatsb = true;
+                else if (objectives[x] < other.objectives[x])
+                    return false;
+                }
+            }
+        else
+            {
+            for (int x = 0; x < objectives.length; x++)
+                {
+                if (objectives[x] < other.objectives[x])
+                    abeatsb = true;
+                else if (objectives[x] > other.objectives[x])
+                    return false;
+                }
+            }
+        return abeatsb;
+        }
+
+    // Remove an individual from the ArrayList, shifting the topmost
+    // individual in his place
+    static void yank(int val, ArrayList list)
+        {
+        int size = list.size();
+        list.set(val, list.get(size - 1));
+        list.remove(size - 1);
+        }
+
+    /**
+     * Divides an array of Individuals into the Pareto front and the "nonFront" (everyone else). 
+     * The Pareto front is returned.  You may provide ArrayLists for the front and a nonFront.
+     * If you provide null for the front, an ArrayList will be created for you.  If you provide
+     * null for the nonFront, non-front individuals will not be added to it.  This algorithm is
+     * O(n^2).
+     */
+    public static ArrayList partitionIntoParetoFront(Individual[] inds, ArrayList front, ArrayList nonFront)
+        {
+        if (front == null)
+            front = new ArrayList();
+                        
+        // put the first guy in the front
+        front.add(inds[0]);
+                
+        // iterate over all the remaining individuals
+        for (int i = 1; i < inds.length; i++)
+            {
+            Individual ind = (Individual) (inds[i]);
+
+            boolean noOneWasBetter = true;
+            int frontSize = front.size();
+                        
+            // iterate over the entire front
+            for (int j = 0; j < frontSize; j++)
+                {
+                Individual frontmember = (Individual) (front.get(j));
+                                
+                // if the front member is better than the individual, dump the individual and go to the next one
+                if (((MultiObjectiveFitness) (frontmember.fitness)).paretoDominates((MultiObjectiveFitness) (ind.fitness)))
+                    {
+                    if (nonFront != null) nonFront.add(ind);
+                    noOneWasBetter = false;
+                    break;  // failed.  He's not in the front
+                    } 
+                // if the individual was better than the front member, dump the front member.  But look over the
+                // other front members (don't break) because others might be dominated by the individual as well.
+                else if (((MultiObjectiveFitness) (ind.fitness)).paretoDominates((MultiObjectiveFitness) (frontmember.fitness)))
+                    {
+                    yank(j, front);
+                    // a front member is dominated by the new individual.  Replace him
+                    frontSize--; // member got removed
+                    j--;  // because there's another guy we now need to consider in his place
+                    if (nonFront != null) nonFront.add(frontmember);
+                    }
+                }
+            if (noOneWasBetter)
+                front.add(ind);
+            }
+        return front;
+        }
+
+
+    /** Divides inds into pareto front ranks (each an ArrayList), and returns them, in order,
+        stored in an ArrayList. */
+    public static ArrayList partitionIntoRanks(Individual[] inds)
+        {
+        Individual[] dummy = new Individual[0];
+        ArrayList frontsByRank = new ArrayList();
+
+        while(inds.length > 0)
+            {
+            ArrayList front = new ArrayList();
+            ArrayList nonFront = new ArrayList();
+            MultiObjectiveFitness.partitionIntoParetoFront(inds, front, nonFront);
+                        
+            // build inds out of remainder
+            inds = (Individual[]) nonFront.toArray(dummy);
+            frontsByRank.add(front);
+            }
+        return frontsByRank;
+        }
+
+
+    /**
+     * Returns the sum of the squared difference between two Fitnesses in Objective space.
+     */
+    public double sumSquaredObjectiveDistance(MultiObjectiveFitness other)
+        {
+        double s = 0;
+        for (int i = 0; i < objectives.length; i++)
+            {
+            double a = (objectives[i] - other.objectives[i]);
+            s += a * a;
+            }
+        return s;
+        }
+
+
+    /**
+     * Returns the Manhattan difference between two Fitnesses in Objective space.
+     */
+    public double manhattanObjectiveDistance(MultiObjectiveFitness other)
+        {
+        double s = 0;
+        for (int i = 0; i < objectives.length; i++)
+            {
+            s += Math.abs(objectives[i] - other.objectives[i]);
+            }
+        return s;
+        }
+
+
+    public String fitnessToString()
+        {
+        String s = FITNESS_PREAMBLE + MULTI_FITNESS_POSTAMBLE;
+        for (int x = 0; x < objectives.length; x++)
+            {
+            if (x > 0)
+                s = s + " ";
+            s = s + Code.encode(objectives[x]);
+            }
+        s = s + " ";
+        s = s + Code.encode(maximize);
+        return s + FITNESS_POSTAMBLE;
+        }
+
+
+    public String fitnessToStringForHumans()
+        {
+        String s = FITNESS_PREAMBLE + MULTI_FITNESS_POSTAMBLE;
+        for (int x = 0; x < objectives.length; x++)
+            {
+            if (x > 0)
+                s = s + " ";
+            s = s + objectives[x];
+            }
+        s = s + " ";
+        s = s + (maximize ? "max" : "min");
+        return s + FITNESS_POSTAMBLE;
+        }
+
+    public void readFitness(final EvolutionState state, final LineNumberReader reader) throws IOException
+        {
+        DecodeReturn d = Code.checkPreamble(FITNESS_PREAMBLE + MULTI_FITNESS_POSTAMBLE, state, reader);
+        for (int x = 0; x < objectives.length; x++)
+            {
+            Code.decode(d);
+            if (d.type != DecodeReturn.T_FLOAT)
+                state.output.fatal("Reading Line " + d.lineNumber + ": " + "Bad Fitness (objectives value #" + x + ").");
+            objectives[x] = (float) d.d;
+            }
+        Code.decode(d);
+        if (d.type != DecodeReturn.T_BOOLEAN)
+            state.output.fatal("Reading Line " + d.lineNumber + ": " + "Information missing about whether higher is better");
+        maximize = (boolean) (d.l != 0);
+        }
+
+    public void writeFitness(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(objectives.length);
+        for (int x = 0; x < objectives.length; x++)
+            dataOutput.writeFloat(objectives[x]);
+        dataOutput.writeBoolean(maximize);
+        }
+
+    public void readFitness(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (objectives == null || objectives.length != len)
+            objectives = new float[len];
+        for (int x = 0; x < objectives.length; x++)
+            objectives[x] = dataInput.readFloat();
+        maximize = dataInput.readBoolean();
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/MultiObjectiveStatistics.java	(revision 6152)
@@ -0,0 +1,162 @@
+/*
+  Copyright 2010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.Subpopulation;
+import ec.multiobjective.MultiObjectiveFitness;
+import ec.simple.SimpleStatistics;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * MultiObjectiveStatistics.java
+ * 
+ * Created: Thu Feb 04 2010
+ * By: Faisal Abidi and Sean Luke
+ *
+ */
+
+/*
+ * MultiObjectiveStatistics are a SimpleStatistics subclass which overrides the finalStatistics
+ * method to output the current Pareto Front in various ways:
+ *
+ * <ul>
+ * <li><p>Every individual in the Pareto Front is written to the end of the statistics log.
+ * <li><p>A summary of the objective values of the Pareto Front is written to stdout.
+ * <li><p>The objective values of the Pareto Front are written in tabular form to a special
+ * Pareto Front file specified with the parameters below.  This file can be easily read by
+ * gnuplot or Excel etc. to display the Front (if it's 2D or perhaps 3D).
+ * 
+ * <p>
+ * <b>Parameters</b><br>
+ * <table>
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>front</tt><br>
+ * <font size=-1>String (a filename)</font></td>
+ * <td valign=top>(The Pareto Front file, if any)</td>
+ * </tr>
+ * </table>
+ */
+
+public class MultiObjectiveStatistics extends SimpleStatistics
+    {   
+    /** front file parameter */
+    public static final String P_PARETO_FRONT_FILE = "front";
+        
+    /** The pareto front log */
+        
+    public static final int NO_FRONT_LOG = -1;
+        
+    public int frontLog;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        File frontFile = state.parameters.getFile(base.push(P_PARETO_FRONT_FILE),null);
+
+        if (frontFile!=null)
+            try
+                {
+                frontLog = state.output.addLog(frontFile, !compress, compress);
+                }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + frontFile + ":\n" + i);
+                }
+        else state.output.warning("No Pareto Front statistics file specified.", base.push(P_PARETO_FRONT_FILE));
+        }
+
+
+
+    /** Logs the best individual of the run. */
+    public void finalStatistics(final EvolutionState state, final int result)
+        {
+        // super.finalStatistics(state,result);
+        // I don't want just a single best fitness
+
+        state.output.println("\n\n\n PARETO FRONTS", statisticslog);
+        for (int s = 0; s < state.population.subpops.length; s++)
+            {
+            MultiObjectiveFitness typicalFitness = (MultiObjectiveFitness)(state.population.subpops[s].individuals[0].fitness);
+            state.output.println("\n\nPareto Front of Subpopulation " + s, statisticslog);
+
+            // build front
+            ArrayList front = typicalFitness.partitionIntoParetoFront(state.population.subpops[s].individuals, null, null);
+
+            // sort by objective[0]
+            Object[] sortedFront = front.toArray();
+            QuickSort.qsort(sortedFront, new SortComparator()
+                {
+                public boolean lt(Object a, Object b)
+                    {
+                    return (((MultiObjectiveFitness) (((Individual) a).fitness)).getObjective(0) < 
+                        (((MultiObjectiveFitness) ((Individual) b).fitness)).getObjective(0));
+                    }
+                
+                public boolean gt(Object a, Object b)
+                    {
+                    return (((MultiObjectiveFitness) (((Individual) a).fitness)).getObjective(0) > 
+                        ((MultiObjectiveFitness) (((Individual) b).fitness)).getObjective(0));
+                    }
+                });
+                        
+            // print out header
+            state.output.message("Pareto Front Summary: " + sortedFront.length + " Individuals");
+            String message = "Ind";
+            int numObjectives = typicalFitness.getObjectives().length;
+            for(int i = 0; i < numObjectives; i++) 
+                message += ("\t" + "Objective " + i);
+            String[] names = typicalFitness.getAuxilliaryFitnessNames();
+            for(int i = 0; i < names.length; i++) 
+                message += ("\t" + names[i]);
+            state.output.message(message);
+                        
+            // write front to screen
+            for (int i = 0; i < sortedFront.length; i++)
+                {
+                Individual individual = (Individual) (sortedFront[i]);
+
+                float[] objectives = ((MultiObjectiveFitness) individual.fitness).getObjectives();
+                String line = "" + i;
+                for (int f = 0; f < objectives.length; f++)
+                    line += ("\t" + objectives[f]);
+
+                double[] vals = ((MultiObjectiveFitness) individual.fitness).getAuxilliaryFitnessValues();
+                for(int f = 0; f < vals.length; f++) 
+                    line += ("\t" + vals[f]);
+                state.output.message(line);
+                }
+                        
+            // print out front to statistics log
+            for (int i = 0; i < sortedFront.length; i++)
+                ((Individual)(sortedFront[i])).printIndividualForHumans(state, statisticslog);
+                
+            // write short version of front out to disk
+            if (frontLog >= 0)
+                {
+                if (state.population.subpops.length > 1)
+                    state.output.println("Subpopulation " + s, frontLog);
+                for (int i = 0; i < sortedFront.length; i++)
+                    {
+                    Individual ind = (Individual)(sortedFront[i]);
+                    MultiObjectiveFitness mof = (MultiObjectiveFitness) (ind.fitness);
+                    float[] objectives = mof.getObjectives();
+
+                    String line = "";
+                    for (int f = 0; f < objectives.length; f++)
+                        line += (objectives[f] + " ");
+                    state.output.println(line, frontLog);
+                    }
+                }
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/README	(revision 6152)
@@ -0,0 +1,40 @@
+This package, and various subpackages, contain tools for doing multiobjective
+optimization.  In the primary package (ec.multiobjective) are just useful
+top-level classes.  In the subsidiary packages (ec.multiobjective.nsga2
+and ec.multiobjective.spea2) are implementations of two popular multiobjective
+optimization algorithms, NSGA-II and SPEA2, which use these top-level classes.
+
+
+
+
+The top-level classes:
+
+
+ec.multiobjective.MultiObjectiveFitness
+
+This is the superclass of fitness classes involving multiple objectives.  This
+class holds not a single fitness value but some N objective values.  These 
+objective values can be either maximized or minimized depending on the setting
+of the fitness class.  The class can perform Pareto Dominance computation between
+two MultiObjectiveFitness classes, and in fact uses this as the basis of its
+default fitness comparison.  Additionally the class contains utility methods for
+computing Pareto Fronts.
+
+
+ec.multiobjective.MultiObjectiveStatistics
+
+This simple subclass of ec.simple.SimpleStatistics aso outputs the Pareto Front
+in various ways at the end of the run:
+
+	- A summary printed on-screen in a helpful columnar format
+	- The entire front written to the end of the statistics file
+	- The multiple objective results of the front written to a special
+	  auxillary file (nominally called 'front.stat').  This front can
+	  be easily displayed by gnuplot, Excel, or other plotting packages.  
+	  If you have a single subpopulation, for example, you can write:
+
+		echo plot \"front.stat\" | gnuplot -persist
+
+	  and the front will be displayed in gnuplot for you.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/multiobjective.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/multiobjective.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/multiobjective.params	(revision 6152)
@@ -0,0 +1,23 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+#
+# Simple default parameters for multiobjective fitness
+#
+
+# how many objectives should we have by default?
+# you can also assign this on a per-subpopulation basis
+multi.fitness.num-objectives 	= 2
+
+# max and min values of all each objective function
+multi.fitness.max 		= 1
+multi.fitness.min 		= 0
+
+# override specific max and min values, e.g
+# multi.fitness.max.0		= 1000
+
+# Use a statistics object which dumps the front
+stat =                                          ec.multiobjective.MultiObjectiveStatistics
+stat.front =                                    $front.stat
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2Breeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2Breeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2Breeder.java	(revision 6152)
@@ -0,0 +1,70 @@
+/*
+  Copyright 2010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective.nsga2;
+
+import ec.*;
+import ec.util.*;
+import ec.simple.*;
+
+/* 
+ * NSGA2Breeder.java
+ * 
+ * Created: Thu Feb 04 2010
+ * By: Faisal Abidi and Sean Luke
+ */
+
+/**
+ * This SimpleBreeder subclass breeds a set of children from the Population, then
+ * joins the original Population with the children in a (mu+mu) fashion.   An NSGA2Breeder
+ * may have multiple threads for breeding.
+ *
+ * <p>NSGA-II has fixed archive size (the population size), and so ignores the 'elites'
+ * declaration.  However it will adhere to the 'reevaluate-elites' parameter in SimpleBreeder
+ * to determine whether to force fitness reevaluation.
+
+ */
+
+public class NSGA2Breeder extends SimpleBreeder
+    {
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+        // make sure SimpleBreeder's elites facility isn't being used
+        for (int i = 0; i < elite.length; i++)
+            if (elite[i] != 0)
+                state.output.warning("Elites may not be used with NSGA2Breeder, and will be ignored.");
+        }
+
+    /**
+     * Override breedPopulation(). We take the result from the super method in
+     * SimpleBreeder and append it to the old population. Hence, after
+     * generation 0, every subsequent call to
+     * <code>NSGA2Evaluator.evaluatePopulation()</code> will be passed a
+     * population of 2x<code>originalPopSize</code> individuals.
+     */
+    public Population breedPopulation(EvolutionState state)
+        {
+        Population oldPop = (Population) state.population;
+        Population newPop = super.breedPopulation(state);
+        Individual[] combinedInds;
+        Subpopulation[] subpops = oldPop.subpops;
+        Subpopulation oldSubpop;
+        Subpopulation newSubpop;
+        int subpopsLength = subpops.length;
+
+        for (int i = 0; i < subpopsLength; i++)
+            {
+            oldSubpop = oldPop.subpops[i];
+            newSubpop = newPop.subpops[i];
+            combinedInds = new Individual[oldSubpop.individuals.length + newSubpop.individuals.length];
+            System.arraycopy(newSubpop.individuals, i, combinedInds, i,  newSubpop.individuals.length);
+            System.arraycopy(oldSubpop.individuals, i, combinedInds,  newSubpop.individuals.length, oldSubpop.individuals.length);
+            newSubpop.individuals = combinedInds;
+            }
+        return newPop;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2Evaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2Evaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2Evaluator.java	(revision 6152)
@@ -0,0 +1,209 @@
+/*
+  Copyright 2010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective.nsga2;
+
+import java.util.*;
+import ec.*;
+import ec.multiobjective.*;
+import ec.simple.*;
+import ec.util.*;
+
+/* 
+ * NSGA2Evaluator.java
+ * 
+ * Created: Sat Oct 16 00:19:57 EDT 2010
+ * By: Faisal Abidi and Sean Luke
+ */
+
+
+/**
+ * The NSGA2Evaluator is a simple generational evaluator which
+ * evaluates every single member of the population (in a multithreaded fashion).
+ * Then it reduces the population size to an <i>archive</i> consisting of the
+ * best front ranks.  When there isn't enough space to fit another front rank,
+ * individuals in that final front rank vie for the remaining slots in the archive
+ * based on their sparsity.
+ * 
+ * <p>The evaluator is also responsible for calculating the rank and
+ * sparsity values stored in the NSGA2MultiObjectiveFitness class and used largely
+ * for statistical information.
+ * 
+ * <p>NSGA-II has fixed archive size (the population size), and so ignores the 'elites'
+ * declaration.  However it will adhere to the 'reevaluate-elites' parameter in SimpleBreeder
+ * to determine whether to force fitness reevaluation.
+ *
+ */
+ 
+public class NSGA2Evaluator extends SimpleEvaluator
+    {
+    /** The original population size is stored here so NSGA2 knows how large to create the archive
+        (it's the size of the original population -- keep in mind that NSGA2Breeder had made the 
+        population larger to include the children. */
+    public int originalPopSize[];
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+        Parameter p = new Parameter(Initializer.P_POP);
+        int subpopsLength = state.parameters.getInt(p.push(Population.P_SIZE), null, 1);
+        Parameter p_subpop;
+        originalPopSize = new int[subpopsLength];
+        for (int i = 0; i < subpopsLength; i++)
+            {
+            p_subpop = p.push(Population.P_SUBPOP).push("" + i).push(Subpopulation.P_SUBPOPSIZE);
+            originalPopSize[i] = state.parameters.getInt(p_subpop, null, 1);
+            }
+        }
+
+
+    /**
+     * Evaluates the population, then builds the archive and reduces the population to just the archive.
+     */
+    public void evaluatePopulation(final EvolutionState state)
+        {
+        super.evaluatePopulation(state);
+        for (int x = 0; x < state.population.subpops.length; x++)
+            state.population.subpops[x].individuals = 
+                buildArchive(state, x);
+        }
+
+
+    /** Build the auxiliary fitness data and reduce the subpopulation to just the archive, which is
+        returned. */
+    public Individual[] buildArchive(EvolutionState state, int subpop)
+        {
+        Individual[] dummy = new Individual[0];
+        ArrayList ranks = assignFrontRanks(state.population.subpops[subpop]);
+                
+        ArrayList newSubpopulation = new ArrayList();
+        int size = ranks.size();
+        for(int i = 0; i < size; i++)
+            {
+            Individual[] rank = (Individual[])((ArrayList)(ranks.get(i))).toArray(dummy);
+            assignSparsity(rank);
+            if (rank.length + newSubpopulation.size() >= originalPopSize[subpop])
+                {
+                // first sort the rank by sparsity
+                ec.util.QuickSort.qsort(rank, new SortComparator()
+                    {
+                    public boolean lt(Object a, Object b)
+                        {
+                        Individual i1 = (Individual) a;
+                        Individual i2 = (Individual) b;
+                        return (((NSGA2MultiObjectiveFitness) i1.fitness).sparsity > ((NSGA2MultiObjectiveFitness) i2.fitness).sparsity);
+                        }
+
+                    public boolean gt(Object a, Object b)
+                        {
+                        Individual i1 = (Individual) a;
+                        Individual i2 = (Individual) b;
+                        return (((NSGA2MultiObjectiveFitness) i1.fitness).sparsity < ((NSGA2MultiObjectiveFitness) i2.fitness).sparsity);
+                        }
+                    });
+
+                // then put the m sparsest individuals in the new population
+                int m = originalPopSize[subpop] - newSubpopulation.size();
+                for(int j = 0 ; j < m; j++)
+                    newSubpopulation.add(rank[j]);
+                                
+                // and bail
+                break;
+                }
+            else
+                {
+                // dump in everyone
+                for(int j = 0 ; j < rank.length; j++)
+                    newSubpopulation.add(rank[j]);
+                }
+            }
+
+        Individual[] archive = (Individual[])(newSubpopulation.toArray(dummy));
+                
+        // maybe force reevaluation
+        NSGA2Breeder breeder = (NSGA2Breeder)(state.breeder);
+        if (breeder.reevaluateElites[subpop])
+            for(int i = 0 ; i < archive.length; i++)
+                archive[i].evaluated = false;
+
+        return archive;
+        }
+
+
+
+    /** Divides inds into ranks and assigns each individual's rank to be the rank it was placed into.
+        Each front is an ArrayList. */
+    public ArrayList assignFrontRanks(Subpopulation subpop)
+        {
+        Individual[] inds = subpop.individuals;
+        ArrayList frontsByRank = MultiObjectiveFitness.partitionIntoRanks(inds);
+
+        int numRanks = frontsByRank.size();
+        for(int rank = 0; rank < numRanks; rank++)
+            {
+            ArrayList front = (ArrayList)(frontsByRank.get(rank));
+            int numInds = front.size();
+            for(int ind = 0; ind < numInds; ind++)
+                ((NSGA2MultiObjectiveFitness)(((Individual)(front.get(ind))).fitness)).rank = rank;
+            }
+        return frontsByRank;
+        }
+
+
+
+    /**
+     * Computes and assigns the sparsity values of a given front.
+     */
+    public void assignSparsity(Individual[] front)
+        {
+        int numObjectives = ((NSGA2MultiObjectiveFitness) front[0].fitness).getObjectives().length;
+                
+        for (int i = 0; i < front.length; i++)
+            ((NSGA2MultiObjectiveFitness) front[i].fitness).sparsity = 0;
+
+        for (int i = 0; i < numObjectives; i++)
+            {
+            final int o = i;
+            // 1. Sort front by each objective.
+            // 2. Sum the manhattan distance of an individual's neighbours over
+            // each objective.
+            // NOTE: No matter which objectives objective you sort by, the
+            // first and last individuals will always be the same (they maybe
+            // interchanged though). This is because a Pareto front's
+            // objective values are strictly increasing/decreasing.
+            ec.util.QuickSort.qsort(front, new SortComparator()
+                {
+                public boolean lt(Object a, Object b)
+                    {
+                    Individual i1 = (Individual) a;
+                    Individual i2 = (Individual) b;
+                    return (((NSGA2MultiObjectiveFitness) i1.fitness).getObjective(o) < ((NSGA2MultiObjectiveFitness) i2.fitness).getObjective(o));
+                    }
+
+                public boolean gt(Object a, Object b)
+                    {
+                    Individual i1 = (Individual) a;
+                    Individual i2 = (Individual) b;
+                    return (((NSGA2MultiObjectiveFitness) i1.fitness).getObjective(o) > ((NSGA2MultiObjectiveFitness) i2.fitness).getObjective(o));
+                    }
+                });
+
+            // Compute and assign sparsity.
+            // the first and last individuals are the sparsest.
+            ((NSGA2MultiObjectiveFitness) front[0].fitness).sparsity = Double.POSITIVE_INFINITY;
+            ((NSGA2MultiObjectiveFitness) front[front.length - 1].fitness).sparsity = Double.POSITIVE_INFINITY;
+            for (int j = 1; j < front.length - 1; j++)
+                {
+                NSGA2MultiObjectiveFitness f_j = (NSGA2MultiObjectiveFitness) (front[j].fitness);
+                NSGA2MultiObjectiveFitness f_jplus1 = (NSGA2MultiObjectiveFitness) (front[j+1].fitness);
+                NSGA2MultiObjectiveFitness f_jminus1 = (NSGA2MultiObjectiveFitness) (front[j-1].fitness);
+                                
+                // store the NSGA2Sparsity in sparsity
+                f_j.sparsity += (f_jplus1.getObjective(o) - f_jminus1.getObjective(o)) / (f_j.maxObjective[o] - f_j.minObjective[o]);
+                }
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2MultiObjectiveFitness.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2MultiObjectiveFitness.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/NSGA2MultiObjectiveFitness.java	(revision 6152)
@@ -0,0 +1,98 @@
+/*
+  Copyright 2010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective.nsga2;
+
+import java.io.*;
+import ec.util.Code;
+import ec.multiobjective.MultiObjectiveFitness;
+import ec.EvolutionState;
+import ec.Fitness;
+
+/* 
+ * NSGA2MultiObjectiveFitness.java
+ * 
+ * Created: Thu Feb 04 2010
+ * By: Faisal Abidi and Sean Luke
+ */
+
+/**
+ * NSGA2MultiObjectiveFitness is a subclass of MultiObjeciveFitness which
+ * adds auxiliary fitness measures (sparsity, rank) largely used by MultiObjectiveStatistics.
+ * It also redefines the comparison measures to compare based on rank, and break ties
+ * based on sparsity. 
+ *
+ */
+
+public class NSGA2MultiObjectiveFitness extends MultiObjectiveFitness
+    {
+    public static final String NSGA2_RANK_PREAMBLE = "Rank: ";
+    public static final String NSGA2_SPARSITY_PREAMBLE = "Sparsity: ";
+
+    public String[] getAuxilliaryFitnessNames() { return new String[] { "Rank", "Sparsity" }; }
+    public double[] getAuxilliaryFitnessValues() { return new double[] { rank, sparsity }; }
+        
+    /** Pareto front rank measure (lower ranks are better) */
+    public int rank;
+
+    /** Sparsity along front rank measure (higher sparsity is better) */
+    public double sparsity;
+
+    public String fitnessToString()
+        {
+        return super.fitnessToString() + "\n" + NSGA2_RANK_PREAMBLE + Code.encode(rank) + "\n" + NSGA2_SPARSITY_PREAMBLE + Code.encode(sparsity);
+        }
+
+    public String fitnessToStringForHumans()
+        {
+        return super.fitnessToStringForHumans() + "\n" + "R=" + rank + " S=" + sparsity;
+        }
+
+    public void readFitness(final EvolutionState state, final LineNumberReader reader) throws IOException
+        {
+        super.readFitness(state, reader);
+        rank = Code.readIntegerWithPreamble(NSGA2_RANK_PREAMBLE, state, reader);
+        sparsity = Code.readDoubleWithPreamble(NSGA2_SPARSITY_PREAMBLE, state, reader);
+        }
+
+    public void writeFitness(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        super.writeFitness(state, dataOutput);
+        dataOutput.writeInt(rank);
+        dataOutput.writeDouble(sparsity);
+        }
+
+    public void readFitness(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        super.readFitness(state, dataInput);
+        rank = dataInput.readInt();
+        sparsity = dataInput.readDouble();
+        }
+
+    public boolean equivalentTo(Fitness _fitness)
+        {
+        NSGA2MultiObjectiveFitness other = (NSGA2MultiObjectiveFitness) _fitness;
+        return (rank == ((NSGA2MultiObjectiveFitness) _fitness).rank) &&
+            (sparsity == other.sparsity);
+        }
+
+    /**
+     * We specify the tournament selection criteria, Rank (lower
+     * values are better) and Sparsity (higher values are better)
+     */
+    public boolean betterThan(Fitness _fitness)
+        {
+        NSGA2MultiObjectiveFitness other = (NSGA2MultiObjectiveFitness) _fitness;
+        // Rank should always be minimized.
+        if (rank < ((NSGA2MultiObjectiveFitness) _fitness).rank)
+            return true;
+        else if (rank > ((NSGA2MultiObjectiveFitness) _fitness).rank)
+            return false;
+                
+        // otherwise try sparsity
+        return (sparsity > other.sparsity);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/README	(revision 6152)
@@ -0,0 +1,70 @@
+This package contains an implementation of the Non-Dominated Sorting 
+Genetic Algorithm 2 (NSGA-II).
+
+Details of this approach can be found in the following paper:
+
+Kalyanmoy Deb, Amrit Pratap, Sameer Agarwal, and T. Meyarivan. A Fast and 
+Elitist Multiobjective Genetic Algorithm: NSGA-II. In IEEE Transactions 
+On Evolutionary Computation.  6(2).  2002.
+
+The ec.app.moosuite package contains common multiobjective test cases
+to test NSGA-II against.
+
+
+
+How ECJ implements NSGA-II
+--------------------------
+
+NSGA-II is an "archive" elitist method which uses Pareto front ranks 
+instead of composite fitness, and sparsity along the front rank when 
+there is not enough remaining room to fill the archive.
+
+We extend SimpleBreeder merely to build the next-generation population 
+by breeding children from the previous population (the archive) and then
+appending the current archive to the newly-generated children.  This 
+is essentially a version of (mu+mu).
+
+Most of the actual work is done in a special version of SimpleEvaluator,
+where the Individuals are evaluated, then broken into Pareto Front Ranks,
+then loaded into the archive.  When there's not enough room left in the
+archive for another full rank, sparsity is used to decide who gets to be
+included.  The archive then forms the next-generation population.
+
+NSGA-II has fixed archive size (the population size), and so ignores the 'elites'
+declaration.  However it will adhere to the 'reevaluate-elites' parameter
+to determine whether to force fitness reevaluation.
+
+SPEA2 and NSGA-II have different approaches to building archives which impacts
+on how you need to set your population sizes in order to achieve the same number
+of evaluations.  In ECJ, NSGA-II does not include the archive as part of the basic 
+population size.  Rather, it builds the archive separately, then builds the
+population by breeding from the archive, then gloms the two together.  On the
+other hand, SPEA2 uses a (tunable) portion of its population as the archive, and
+breeds individuals into the remainder of the population.  This means that to have
+a "population size" for SPEA2 that's the same as NSGA-II, you need to increase
+SPEA2's population size to NSGA-II's population size plus SPEA2's archive (elites)
+size.  For example, if you have an NSGA-II population size of 100, and SPEA2 is using
+an archive size of 50, to be fair you should make SPEA2's population size be 150.
+
+If you set things so that SPEA2 and NSGA-II must reevaluate the fitness of 
+their archives (which is rare), things are different.  Now you should set SPEA2
+so that its archive size and population size is equal to twice NSGA-II's population
+size (because NSGA-II's archive size is the size of its population).
+
+The classes in question:
+
+
+ec.multiobjective.nsga2.NSGA2Breeder
+
+The SimpleBreeder subclass.
+
+
+ec.multiobjective.nsga2.NSGA2Evaluator
+
+The SimpleEvaluator subclass.
+
+
+ec.multiobjective.nsga2.NSGA2MultiObjectiveFitness
+
+A special subclass of MultiObjectiveFitness which adds auxillary fitness 
+measures special to NSGA-II (notably rank and sparsity).
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/nsga2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/nsga2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/nsga2/nsga2.params	(revision 6152)
@@ -0,0 +1,22 @@
+# Copyright 2010 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../multiobjective.params
+parent.1 = ../../simple/simple.params
+
+# Be sure to set the multiobjective fitness size as shown in ../multiobjective.params
+# Likewise note tht ../multiobjective.params sets the statistics
+
+# We also use a special version of MultiObjectiveFitness
+pop.subpop.0.species.fitness =				ec.multiobjective.nsga2.NSGA2MultiObjectiveFitness
+
+# We have our own evaluator and breeder
+eval =						ec.multiobjective.nsga2.NSGA2Evaluator
+breed =						ec.multiobjective.nsga2.NSGA2Breeder
+
+# Specify the breeding pipeline as follows
+# pop.subpop.0.species.pipe           	      = ec.vector.breed.VectorMutationPipeline
+# pop.subpop.0.species.pipe.source.0          = ec.vector.breed.VectorCrossoverPipeline
+# pop.subpop.0.species.pipe.source.0.source.0 = ec.multiobjective.nsga2.NSGA2TournamentSelection
+# pop.subpop.0.species.pipe.source.0.source.1 = same
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/README	(revision 6152)
@@ -0,0 +1,98 @@
+This package contains is an implementation of the Strength Pareto 
+Evolutionary Algorithm 2 (SPEA2).
+
+Details of this approach can be found in the following paper:
+
+E. Zitzler, M. Laumanns, and L. Thiele.SPEA2: Improving the Performance
+of the Strength Pareto Evolutionary Algorithm. Technical Report 103,
+Computer Engineering and Communication Networks Lab (TIK), Swiss Federal
+Institute of Technology (ETH) Zurich, Gloriastrasse 35, CH-8092 Zurich,
+May 2001. 
+
+ftp://ftp.tik.ee.ethz.ch/pub/people/zitzler/ZLT2001a.ps (Postscript),
+ftp://ftp.tik.ee.ethz.ch/pub/people/zitzler/ZLT2001a.pdf (PDF)
+
+
+ABSTRACT 
+
+The Strength Pareto Evolutionary Algorithm (SPEA) (Zitzler and Thiele
+1999) is a relatively recent technique for finding or approximating the
+Pareto-optimal set for multiobjective optimization problems. In
+different studies (Zitzler and Thiele 1999; Zitzler, Deb, and Thiele
+2000) SPEA has shown very good performance in comparison to other
+multiobjective evolutionary algorithms, and therefore it has been a
+point of reference in various recent investigations, e.g., (Corne,
+Knowles, and Oates 2000). Furthermore, it has been used in different
+applications, e.g., (La-hanas, Milickovic, Baltas, and Zamboglou 2001).
+In this paper, an improved ver-sion, namely SPEA2, is proposed, which
+incorporates in contrast to its predecessor a fine-grained fitness
+assignment strategy, a density estimation technique, and an enhanced
+archive truncation method. The comparison of SPEA2 with SPEA and two
+other modern elitist methods, PESA and NSGA-II, on different test
+problems yields promising results.
+
+This package has a significant history.  The early versions of the
+package were donated by Robert Hubley at the Institute for Systems
+Biology.  Major later modifications were made by Sean Luke, Gabriel Balan,
+and Keith Sullivan.  Then the SPEA2 package was almost entirely rewritten
+in 2010 by Faisal Abidi and Sean Luke.
+
+
+EXAMPLES
+--------
+
+The ec.app.moosuite package contains test cases against which to test SPEA2.
+
+
+How ECJ implements SPEA2
+------------------------
+
+SPEA2 is an elitist archive method which in some sense extends mu+lambda. 
+That is, SPEA2 maintains a pool (the "archive") of some N high quality
+individuals which more or less holds the present known pareto front of
+the population.  That archive is carried over from generation to generation.
+
+SPEA2 has an elaborate fitness setting procedure which involves the 
+computation of several measures of domination (known as "strength") and
+sparsity.  This computation is performed by a revised SimpleEvaluator subclass:
+
+	ec.multiobjective.spea2.SPEA2Evaluator
+
+New children are then bred and an archive is formed by loading the pareto
+front, trimmed by sparsity plus various other "highly fit" children (if there
+is space).  The breeding procedure is handled by a revised version of 
+SimpleBreeder:
+
+	ec.multiobjective.spea2.SPEA2Breeder
+
+Because it uses auxiliary fitness measures to perform breeding, SPEA2 requires
+a subclass of MultiObjectiveFitness which stores these auxiliary measures:
+
+	ec.multiobjective.spea2.SPEA2MultiObjectiveFitness
+
+When SPEA2 needs to do breeding, it does so solely from the archive, not from
+the full population.  This means that the selection operator 
+(TournamentSelection, which SPEA uses) needs to be modified to only 
+consider the archive when selecting an individual.  Our modified version is:
+
+	ec.multiobjecive.spea2.SPEA2TournamentSelection
+
+
+SPEA2 and NSGA-II have different approaches to building archives which impacts
+on how you need to set your population sizes in order to achieve the same number
+of evaluations.  In ECJ, NSGA-II does not include the archive as part of the basic
+population size.  Rather, it builds the archive separately, then builds the
+population by breeding from the archive, then gloms the two together.  On the
+other hand, SPEA2 uses a (tunable) portion of its population as the archive, and
+breeds individuals into the remainder of the population.  This means that to have
+a "population size" for SPEA2 that's the same as NSGA-II, you need to increase
+SPEA2's population size to NSGA-II's population size plus SPEA2's archive (elites)
+size.  For example, if you have an NSGA-II population size of 100, and SPEA2 is using
+an archive size of 50, to be fair you should make SPEA2's population size be 150.
+
+If you set things so that SPEA2 and NSGA-II must reevaluate the fitness of 
+their archives (which is rare), things are different.  Now you should set SPEA2
+so that its archive size and population size is equal to twice NSGA-II's population
+size (because NSGA-II's archive size is the size of its population).
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2Breeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2Breeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2Breeder.java	(revision 6152)
@@ -0,0 +1,122 @@
+/*
+  Portions copyright 2010 by Sean Luke, Robert Hubley, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective.spea2;
+
+import ec.*;
+import ec.util.*;
+import ec.multiobjective.*;
+import ec.simple.*;
+import java.util.*;
+
+/* 
+ * SPEA2Breeder.java
+ * 
+ * Created: Sat Oct 16 11:24:43 EDT 2010
+ * By: Faisal Abidi and Sean Luke
+ * Replaces earlier class by: Robert Hubley, with revisions by Gabriel Balan and Keith Sullivan
+ */
+
+/**
+ * This subclass of SimpleBreeder overrides the loadElites method to build an archive in the top elites[subpopnum]
+ * of each subpopulation.  It computes the sparsity metric, then constructs the archive.
+ */
+
+public class SPEA2Breeder extends SimpleBreeder
+    {
+    protected void loadElites(EvolutionState state, Population newpop)
+        {
+        // are our elites small enough?
+        for(int x=0;x<state.population.subpops.length;x++)
+            if (elite[x]>state.population.subpops[x].individuals.length)
+                state.output.error("The number of elites for subpopulation " + x + " exceeds the actual size of the subpopulation", new Parameter(EvolutionState.P_BREEDER).push(P_ELITE).push(""+x));
+        state.output.exitIfErrors();
+
+        // do it
+        for (int sub = 0; sub < state.population.subpops.length; sub++)
+            {
+            Individual[] newInds = newpop.subpops[sub].individuals;  // The new population after we are done picking the elites                 
+            Individual[] oldInds = state.population.subpops[sub].individuals;   // The old population from which to pick elites
+                        
+            buildArchive(state, oldInds, newInds, elite[sub]);
+            }
+
+        // optionally force reevaluation
+        unmarkElitesEvaluated(newpop);
+        }
+
+    public double[] calculateDistancesFromIndividual(Individual ind, Individual[] inds)
+        {
+        double[] d = new double[inds.length];
+        for(int i = 0; i < inds.length; i++)
+            d[i] = ((SPEA2MultiObjectiveFitness)ind.fitness).sumSquaredObjectiveDistance((SPEA2MultiObjectiveFitness)inds[i].fitness);
+        // now sort
+        Arrays.sort(d);
+        return d;
+        }
+
+
+    public void buildArchive(EvolutionState state, Individual[] oldInds, Individual[] newInds, int archiveSize)
+        {
+        Individual[] dummy = new Individual[0];
+                
+        // step 1: load the archive with the pareto-nondominated front
+        ArrayList archive = new ArrayList();
+        ArrayList nonFront = new ArrayList();
+        MultiObjectiveFitness.partitionIntoParetoFront(oldInds, archive, nonFront);
+        int currentArchiveSize = archive.size();
+                
+        // step 2: if the archive isn't full, load the remainder with the fittest individuals (using customFitnessMetric) that aren't in the archive yet
+        if (currentArchiveSize < archiveSize)
+            {
+            Collections.sort(nonFront);  // the fitter individuals will be earlier
+            int len = (archiveSize - currentArchiveSize);
+            for(int i = 0; i < len; i++)
+                {
+                archive.add(nonFront.get(i));
+                currentArchiveSize++;
+                }
+            }
+                        
+
+        // step 3: if the archive is OVERFULL, iterate as follows:
+        //              step 3a: remove the k-closest individual in the archive
+        SPEA2Evaluator evaluator = ((SPEA2Evaluator)(state.evaluator));
+        Individual[] inds = (Individual[])(archive.toArray(dummy));
+                
+        while(currentArchiveSize > archiveSize)
+            {
+            Individual closest = (Individual)(archive.get(0));
+            int closestIndex = 0;
+            double[] closestD = calculateDistancesFromIndividual(closest, oldInds);
+                        
+            for(int i = 1; i < currentArchiveSize; i++)
+                {
+                Individual competitor = (Individual)(archive.get(i));
+                double[] competitorD = calculateDistancesFromIndividual(competitor, oldInds);
+                                
+                for(int k = 0; k < oldInds.length; k++)
+                    {
+                    if (closestD[i] > competitorD[i])
+                        { closest = competitor ; closestD = competitorD;  closestIndex = k; break; }
+                    else if (closestD[i] < competitorD[i])
+                        { break; }
+                    }
+                }
+                        
+            // remove him destructively -- put the top guy in his place and remove the top guy.  This is O(1)
+            archive.set(closestIndex, archive.get(archive.size()-1));
+            archive.remove(archive.size()-1);
+                        
+            currentArchiveSize--;
+            }
+                                                
+        // step 4: put clones of the archive in the new individuals
+        Object[] obj = archive.toArray();
+        for(int i = 0; i < archiveSize; i++)
+            newInds[newInds.length - archiveSize + i] = (Individual)(((Individual)obj[i]).clone());
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2Evaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2Evaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2Evaluator.java	(revision 6152)
@@ -0,0 +1,166 @@
+/*
+  Portions copyright 2010 by Sean Luke, Robert Hubley, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective.spea2;
+
+import ec.*;
+import ec.util.*;
+import ec.multiobjective.*;
+import ec.simple.*; 
+
+/* 
+ * SPEA2Evaluator.java
+ * 
+ * Created: Sat Oct 16 11:24:43 EDT 2010
+ * By: Faisal Abidi and Sean Luke
+ * Replaces earlier class by: Robert Hubley, with revisions by Gabriel Balan and Keith Sullivan
+ */
+ 
+/**
+ * This subclass of SimpleEvaluator evaluates the population, then computes auxiliary fitness
+ * data of each subpopulation.
+ */
+
+public class SPEA2Evaluator extends SimpleEvaluator
+    {
+    public void evaluatePopulation(final EvolutionState state)
+        {
+        super.evaluatePopulation(state);
+                
+        // build SPEA2 fitness values
+        for(int x = 0;x<state.population.subpops.length;x++)
+            {
+            Individual[] inds = state.population.subpops[x].individuals;
+            computeAuxiliaryData(state, inds);
+            }
+        }
+
+    /** Computes the strength of individuals, then the raw fitness (wimpiness) and kth-closest sparsity
+        measure.  Finally, computes the final fitness of the individuals.  */
+    public void computeAuxiliaryData(EvolutionState state, Individual[] inds)
+        {
+        double[][] distances = calculateDistances(state, inds);
+                        
+        // For each individual calculate the strength
+        for(int y=0;y<inds.length;y++)
+            {
+            // Calculate the node strengths
+            int myStrength = 0;
+            for(int z=0;z<inds.length;z++)
+                if (((SPEA2MultiObjectiveFitness)inds[y].fitness).paretoDominates((MultiObjectiveFitness)inds[z].fitness)) 
+                    myStrength++;
+            ((SPEA2MultiObjectiveFitness)inds[y].fitness).strength = myStrength;
+            } //For each individual y calculate the strength
+                
+        // calculate k value
+        int kTH = (int) Math.sqrt(inds.length);  // note that the first element is k=1, not k=0 
+        
+        // For each individual calculate the Raw fitness and kth-distance
+        for(int y=0;y<inds.length;y++)
+            {
+            double fitness = 0;
+            for(int z=0;z<inds.length;z++)
+                {
+                // Raw fitness 
+                if ( ((SPEA2MultiObjectiveFitness)inds[z].fitness).paretoDominates((MultiObjectiveFitness)inds[y].fitness) )
+                    {
+                    fitness += ((SPEA2MultiObjectiveFitness)inds[z].fitness).strength;
+                    }
+                } // For each individual z calculate RAW fitness distances
+            // Set SPEA2 raw fitness value for each individual
+                                    
+            SPEA2MultiObjectiveFitness indYFitness = ((SPEA2MultiObjectiveFitness)inds[y].fitness);
+                        
+            // Density component
+                        
+            // calc k-th nearest neighbor distance.
+            // distances are squared, so we need to take the square root.
+            double kthDistance = Math.sqrt(orderStatistics(distances[y], kTH, state.random[0]));
+                        
+            // Set SPEA2 k-th NN distance value for each individual
+            indYFitness.kthNNDistance = 1.0 / ( 2 + kthDistance);
+                        
+            // Set SPEA2 fitness value for each individual
+            indYFitness.fitness = fitness + indYFitness.kthNNDistance;
+            }
+        }
+    
+        
+    /** Returns a matrix of sum squared distances from each individual to each other individual. */
+    public double[][] calculateDistances(EvolutionState state, Individual[] inds)
+        {
+        double[][] distances = new double[inds.length][inds.length];
+        for(int y=0;y<inds.length;y++)
+            {
+            distances[y][y] = 0;
+            for(int z=y+1;z<inds.length;z++)
+                {
+                distances[z][y] = distances[y][z] =
+                    ((SPEA2MultiObjectiveFitness)inds[y].fitness).
+                    sumSquaredObjectiveDistance( (SPEA2MultiObjectiveFitness)inds[z].fitness );
+                }
+            }
+        return distances;
+        }
+
+
+    /** Returns the kth smallest element in the array.  Note that here k=1 means the smallest element in the array (not k=0).
+        Uses a randomized sorting technique, hence the need for the random number generator. */
+    double orderStatistics(double[] array, int kth, MersenneTwisterFast rng)
+        {
+        return randomizedSelect(array, 0, array.length-1, kth, rng);
+        }
+                
+                
+    /* OrderStatistics [Cormen, p187]:
+     * find the ith smallest element of the array between indices p and r */
+    double randomizedSelect(double[] array, int p, int r, int i, MersenneTwisterFast rng)
+        {
+        if(p==r) return array[p];
+        int q = randomizedPartition(array, p, r, rng);
+        int k = q-p+1;
+        if(i<=k)
+            return randomizedSelect(array, p, q, i,rng);
+        else
+            return randomizedSelect(array, q+1, r, i-k,rng);
+        }
+                
+                
+    /* [Cormen, p162] */
+    int randomizedPartition(double[] array, int p, int r, MersenneTwisterFast rng)
+        {
+        int i = rng.nextInt(r-p+1)+p;
+                
+        //exchange array[p]<->array[i]
+        double tmp = array[i];
+        array[i]=array[p];
+        array[p]=tmp;
+        return partition(array,p,r);
+        }
+                
+                
+    /* [cormen p 154] */
+    int partition(double[] array, int p, int r)
+        {
+        double x = array[p];
+        int i = p-1;
+        int j = r+1;
+        while(true)
+            {
+            do j--; while(array[j]>x);
+            do i++; while(array[i]<x);
+            if ( i < j )
+                {
+                //exchange array[i]<->array[j]
+                double tmp = array[i];
+                array[i]=array[j];
+                array[j]=tmp;
+                }
+            else
+                return j;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2MultiObjectiveFitness.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2MultiObjectiveFitness.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2MultiObjectiveFitness.java	(revision 6152)
@@ -0,0 +1,102 @@
+/*
+  Portions copyright 2010 by Sean Luke, Robert Hubley, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.multiobjective.spea2;
+
+import java.io.*;
+import ec.util.*;
+import ec.multiobjective.*;
+import ec.*;
+
+/* 
+ * SPEA2MultiObjectiveFitness.java
+ * 
+ * Created: Sat Oct 16 11:24:43 EDT 2010
+ * By: Sean Luke
+ * Replaces earlier class by: Robert Hubley, with revisions by Gabriel Balan and Keith Sullivan
+ */
+
+/**
+ * SPEA2MultiObjectiveFitness is a subclass of MultiObjectiveFitness which adds three auxiliary fitness
+ * measures used in SPEA2: strength S(i), kthNNDistance D(i), and a final fitness value R(i) + D(i).  
+ * Note that so-called "raw fitness" (what Sean calls "Wimpiness" in Essentials of Metaheuristics) is 
+ * not retained.
+ * 
+ * <p>The fitness comparison operators solely use the 'fitness' value R(i) + D(i).
+ */
+
+public class SPEA2MultiObjectiveFitness extends MultiObjectiveFitness
+    {
+    public static final String SPEA2_FITNESS_PREAMBLE = "Fitness: ";
+    public static final String SPEA2_STRENGTH_PREAMBLE = "Strength: ";
+    public static final String SPEA2_DISTANCE_PREAMBLE = "Distance: ";
+
+    public String[] getAuxilliaryFitnessNames() { return new String[] { "Strength", "Raw Fitness", "Kth NN Distance" }; }
+    public double[] getAuxilliaryFitnessValues() { return new double[] { strength, fitness, kthNNDistance }; }
+        
+    /** SPEA2 strength (# of nodes it dominates) */
+    public double strength; // S(i)
+
+    /** SPEA2 NN distance */
+    public double kthNNDistance; // D(i)
+
+    /** Final SPEA2 fitness.  Equals the raw fitness R(i) plus the kthNNDistance D(i). */
+    public double fitness;
+
+    public String fitnessToString()
+        {
+        return super.fitnessToString() + "\n" + SPEA2_FITNESS_PREAMBLE + Code.encode(fitness) + "\n" + SPEA2_STRENGTH_PREAMBLE + Code.encode(strength) + "\n" + SPEA2_DISTANCE_PREAMBLE + Code.encode(kthNNDistance);
+        }
+
+    public String fitnessToStringForHumans()
+        {
+        return super.fitnessToStringForHumans() + "\n" + "S=" + strength + " D=" + kthNNDistance + " " + SPEA2_FITNESS_PREAMBLE + fitness;
+        }
+
+    public void readFitness(final EvolutionState state, final LineNumberReader reader) throws IOException
+        {
+        super.readFitness(state, reader);
+        fitness = Code.readDoubleWithPreamble(SPEA2_FITNESS_PREAMBLE, state, reader);
+        strength = Code.readDoubleWithPreamble(SPEA2_STRENGTH_PREAMBLE, state, reader);
+        kthNNDistance = Code.readDoubleWithPreamble(SPEA2_DISTANCE_PREAMBLE, state, reader);
+        }
+
+    public void writeFitness(final EvolutionState state, final DataOutput dataOutput) throws IOException
+        {
+        super.writeFitness(state, dataOutput);
+        dataOutput.writeDouble(fitness);
+        dataOutput.writeDouble(strength);
+        dataOutput.writeDouble(fitness);
+        dataOutput.writeDouble(kthNNDistance);
+        }
+
+    public void readFitness(final EvolutionState state, final DataInput dataInput) throws IOException
+        {
+        super.readFitness(state, dataInput);
+        fitness = dataInput.readDouble();
+        strength = dataInput.readDouble();
+        fitness = dataInput.readDouble();
+        kthNNDistance = dataInput.readDouble();
+        }
+
+    /**
+     * The selection criteria in SPEA2 uses the computed fitness, and not
+     * pareto dominance.
+     */
+    public boolean equivalentTo(Fitness _fitness)
+        {
+        return fitness == ((SPEA2MultiObjectiveFitness)_fitness).fitness;
+        }
+
+    /**
+     * The selection criteria in SPEA2 uses the computed fitness, and not
+     * pareto dominance.
+     */
+    public boolean betterThan(Fitness _fitness)
+        {
+        return fitness < ((SPEA2MultiObjectiveFitness)_fitness).fitness;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2TournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2TournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/SPEA2TournamentSelection.java	(revision 6152)
@@ -0,0 +1,37 @@
+/*
+  Portions copyright 2010 by Sean Luke, Robert Hubley, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.multiobjective.spea2;
+import ec.*;
+import ec.select.*;
+import ec.simple.*;
+
+/* 
+ * SPEA2TournamentSelection.java
+ * 
+ * Created: Sat Oct 16 11:24:43 EDT 2010
+ * By: Sean Luke
+ * Replaces earlier class by: Robert Hubley, with revisions by Gabriel Balan and Keith Sullivan
+ */
+
+/**
+ * This is a special version of TournamentSelection which restricts the selection to only
+ * the archive region (the top 'archiveSize' elements in the subpopulation).
+ */
+
+// This all assumes that the archive is the LAST N INDIVIDUALS in the individuals array
+public class SPEA2TournamentSelection extends TournamentSelection
+    {
+    public int getRandomIndividual(int number, int subpopulation, EvolutionState state, int thread)
+        {
+        Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+        int archiveSize = ((SimpleBreeder)(state.breeder)).elite[subpopulation];
+        int archiveStart = state.population.subpops[subpopulation].individuals.length - archiveSize;
+
+        return archiveStart + state.random[thread].nextInt(archiveSize);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/spea2.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/spea2.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/multiobjective/spea2/spea2.params	(revision 6152)
@@ -0,0 +1,32 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../multiobjective.params
+parent.1 = ../../simple/simple.params
+
+# Be sure to set the multiobjective fitness size as shown in ../multiobjective.params
+# Likewise note tht ../multiobjective.params sets the statistics
+
+# the size of the elitist archive.  This must not be larger
+# than the subpopulation size, and it generally could be roughly
+# the size of the number of solutions you expect.  If your subpopulation
+# was 1024 in size, maybe this might be a reasonable value...
+breed.elite.0 =			128
+
+# We also use a special version of MultiObjectiveFitness
+pop.subpop.0.species.fitness =				ec.multiobjective.spea2.SPEA2MultiObjectiveFitness
+
+# We have our own evaluator and breeder
+eval =						ec.multiobjective.spea2.SPEA2Evaluator
+breed =						ec.multiobjective.spea2.SPEA2Breeder
+
+# It's important that you use a modified version of TournamentSelection
+# for all selection functions in your breeding pipeline.  
+# This version is called ec.multiobjective.spea2.SPEA2TournamentSelection
+# For example:
+
+# pop.subpop.0.species.pipe           	      = ec.vector.breed.VectorMutationPipeline
+# pop.subpop.0.species.pipe.source.0          = ec.vector.breed.VectorCrossoverPipeline
+# pop.subpop.0.species.pipe.source.0.source.0 = ec.multiobjective.spea2.SPEA2TournamentSelection
+# pop.subpop.0.species.pipe.source.0.source.1 = same
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/BucketTournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/BucketTournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/BucketTournamentSelection.java	(revision 6152)
@@ -0,0 +1,267 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.parsimony;
+
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+import ec.select.*;
+
+/* 
+ * BucketTournamentSelection.java
+ * 
+ * Created: Mon Apr 09 17:02:30 2001
+ * By: Liviu Panait
+ */
+
+/**
+ *
+ * Does a tournament selection, limited to the subpopulation it's
+ * working in at the time.
+ *
+ * <p>Bucket Lexicographic Tournament selection works like as follows. There is a 
+ * number of buckets (<i>num-buckets</i>) specified beforehand, and each is
+ * assigned a rank from 1 to <i>num-buckets</i>.  The population, of size <i>pop-size</i>,
+ * is sorted by fitness.  The bottom <i>pop-size</i>/<i>num-buckets</i> individuals are
+ * placed in the worst ranked bucket, plus any individuals remaining in the population with
+ * the same fitness as the best individual in the bucket.  Then the second worst
+ * <i>pop-size</i>/<i>num-buckets</i> individuals are placed in the second worst ranked bucket,
+ * plus any individuals in the population equal in fitness to the best individual in that bucket.
+ * This continues until there are no individuals in the population.  Note that the topmost bucket
+ * with individuals can hold fewer than <i>pop-size</i>/<i>num-buckets</i> individuals, if
+ * <i>pop-size</i> is not a multiple of <i>num-buckets</i>. Depending on the number of
+ * equal-fitness individuals in the population, there can be some top buckets that are never
+ * filled. The fitness of each individual in a bucket is set to the rank of the bucket holding
+ * it.  Direct bucketing has the effect of trading off fitness differences for size. Thus the
+ * larger the bucket, the stronger the emphasis on size as a secondary objective.
+ *
+ * After ranking the individuals, <i>size</i> individuals are chosen at random from the
+ * population. Of those individuals, the one with the highest rank is selected. If the two
+ * individuals are in the same rank, meaning that they have similar fitness, the one
+ * with the smallest size is selected.
+ *
+ * <p>Bucket Lexicographic Tournament selection is so simple that it doesn't
+ * need to maintain a cache of any form, so many of the SelectionMethod methods
+ * just don't do anything at all.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>size</tt><br>
+ <font size=-1>int &gt;= 1 (default 7)</font></td>
+ <td valign=top>(the tournament size)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the tournament instead of the <i>best</i>?)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>num-buckets</tt><br>
+ <font size=-1>int &gt;= 1 (default 10)</font></td>
+ <td valign=top>(the number of buckets)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.bucket-tournament
+
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public class BucketTournamentSelection extends SelectionMethod implements SteadyStateBSourceForm
+    {
+    /** Default base */
+    public static final String P_TOURNAMENT = "bucket-tournament";
+
+    /** If the worst individual should be picked in the tournament */
+    public static final String P_PICKWORST = "pick-worst";
+
+    /** Tournament size parameter */
+    public static final String P_SIZE = "size";
+
+    /** Default size */
+    public static final int DEFAULT_SIZE = 7;
+
+    /** The number of buckets */
+    public static final String P_BUCKETS = "num-buckets";
+
+    /** Default number of buckets */
+    public static final int N_BUCKETS_DEFAULT = 10;
+
+    /** Size of the tournament*/
+    public int size;
+
+    /** Do we pick the worst instead of the best? */
+    public boolean pickWorst;
+
+    // the number of buckets
+    int nBuckets;
+
+    // the indexes of the buckets where the individuals should go (will be used instead of fitness)
+    int[] bucketValues;
+ 
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_TOURNAMENT);
+        }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        size = state.parameters.getInt(base.push(P_SIZE),def.push(P_SIZE),1);
+        if (size < 1)
+            state.output.fatal("Tournament size must be >= 1.",base.push(P_SIZE),def.push(P_SIZE));
+
+        if( state.parameters.exists( base.push(P_BUCKETS), def.push(P_BUCKETS)))
+            {
+            nBuckets = state.parameters.getInt(base.push(P_BUCKETS),def.push(P_BUCKETS),1);
+            if (nBuckets < 1)
+                {
+                state.output.fatal("The number of buckets size must be >= 1.",base.push(P_BUCKETS),def.push(P_BUCKETS));
+                }
+            }
+        else
+            {
+            nBuckets = N_BUCKETS_DEFAULT;
+            }
+
+        pickWorst = state.parameters.getBoolean(base.push(P_PICKWORST),def.push(P_PICKWORST),false);
+        }
+
+    /** Prepare to produce: create the buckets!!!! */
+    public void prepareToProduce(final EvolutionState state, final int subpopulation, final int thread) 
+        {
+        bucketValues = new int[ state.population.subpops[subpopulation].individuals.length ];
+
+        // correct?
+        java.util.Arrays.sort(state.population.subpops[subpopulation].individuals,
+            new java.util.Comparator()
+                {
+                public int compare(Object o1, Object o2)
+                    {
+                    Individual a = (Individual) o1;
+                    Individual b = (Individual) o2;
+                    if (a.fitness.betterThan(b.fitness))
+                        return 1;
+                    if (b.fitness.betterThan(a.fitness))
+                        return -1;
+                    return 0;
+                    }
+                });
+
+
+        // how many individuals in current bucket
+        int nInd;
+
+        float averageBuck = ((float)state.population.subpops[subpopulation].individuals.length)/
+            ((float)nBuckets);
+
+        // first individual goes into first bucket
+        bucketValues[0] = 0;
+
+        // now there is one individual in the first bucket
+        nInd = 1;
+
+        for( int i = 1 ; i < state.population.subpops[subpopulation].individuals.length ; i++ )
+            {
+            // if there is still some place left in the current bucket, throw the current individual there too
+            if( nInd < averageBuck )
+                {
+                bucketValues[i] = bucketValues[i-1];
+                nInd++;
+                }
+            else // check if it has the same fitness as last individual
+                {
+                if( ((Individual)state.population.subpops[subpopulation].individuals[i]).fitness.equivalentTo(
+                        ((Individual)state.population.subpops[subpopulation].individuals[i-1]).fitness ) )
+                    {
+                    // now the individual has exactly the same fitness as previous one,
+                    // so we just put it in the same bucket as the previous one(s)
+                    bucketValues[i] = bucketValues[i-1];
+                    nInd++;
+                    }
+                else
+                    {
+                    // if there are buckets left
+                    if( bucketValues[i-1]+1 < nBuckets )
+                        {
+                        // new bucket!!!!
+                        bucketValues[i] = bucketValues[i-1] - 1;
+                        // with only one individual
+                        nInd = 1;
+                        }
+                    else // no more buckets left, just stick everything in the last bucket
+                        {
+                        bucketValues[i] = bucketValues[i-1];
+                        nInd++;
+                        }
+                    }
+                }
+            }
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        // pick size random individuals, then pick the best.
+        Individual[] oldinds = (state.population.subpops[subpopulation].individuals);
+        int i = state.random[thread].nextInt(oldinds.length);
+        long si = 0;
+
+        for (int x=1;x<size;x++)
+            {
+            int j = state.random[thread].nextInt(oldinds.length);
+            if (pickWorst)
+                {
+                if( bucketValues[j]>bucketValues[i] ) { i = j; si = 0; }
+                else if( bucketValues[i]>bucketValues[j] ) { } // do nothing
+                else
+                    {
+                    if (si==0)
+                        si = oldinds[i].size();
+                    long sj = oldinds[j].size();
+
+                    if (sj >= si) // sj's got worse lookin' trees
+                        { i = j; si = sj; }
+                    }
+                }
+            else
+                { 
+                if( bucketValues[j]<bucketValues[i] ) { i = j; si = 0; }
+                else if( bucketValues[i]<bucketValues[j] ) { } // do nothing
+                else
+                    {
+                    if (si==0)
+                        si = oldinds[i].size();
+                    long sj = oldinds[j].size();
+
+                    if (sj < si) // sj's got better lookin' trees
+                        { i = j; si = sj; }
+                    }
+                }
+            }
+        return i;
+        }
+
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        { return; }
+    
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        { return; }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/DoubleTournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/DoubleTournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/DoubleTournamentSelection.java	(revision 6152)
@@ -0,0 +1,259 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.parsimony;
+import ec.select.*;
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+
+/**
+ *
+ * DoubleTournamentSelection.java
+ *
+ * There are 2 tournaments for each selection of an individual. In the first
+ * ("qualifying") tournament, <i>size</i> individuals
+ * are selected and the <i>best</i> one (based on individuals' length if <i>do-length-first</i>
+ * is true, or based on individual's fitness otherwise). This process repeat <i>size2</i> times,
+ * so we end up with <i>size2</i> winners on one criteria. Then, there is second "champion" tournament
+ * on the other criteria (fitness if <i>do-length-first</i> is true, size otherwise) among the
+ * <i>size2</i> individuals, and the best one is the one returned by this selection method.
+ *
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>size</tt><br>
+ <font size=-1>int &gt;= 1 (default 7)</font></td>
+ <td valign=top>(the tournament size for the initial ("qualifying") tournament)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>size2</tt><br>
+ <font size=-1>int &gt;= 1 (default 7)</font></td>
+ <td valign=top>(the tournament size for the final ("champion") tournament)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the initial ("qualifying") tournament instead of the <i>best</i>?)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst2</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the final ("champion") tournament instead of the <i>best</i>?)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>do-length-first</tt><br>
+ <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ <td valign=top>(should the initial ("qualifying") tournament be based on the length of the individual or (if false) the fitness of the individual?  The final ("champion") tournament will be based on the alternative option)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.double-tournament
+
+ *
+ */
+
+/**
+ *
+ *
+ * @author Sean Luke & Liviu Panait
+ * @version 1.0 
+ *
+ */
+
+public class DoubleTournamentSelection extends SelectionMethod implements SteadyStateBSourceForm
+    {
+    /** default base */
+    public static final String P_TOURNAMENT = "double-tournament";
+
+    public static final String P_PICKWORST = "pick-worst";
+    public static final String P_PICKWORST2 = "pick-worst2";
+
+    public static final String P_DOLENGTHFIRST = "do-length-first";
+    
+    /** size parameter */
+    public static final String P_SIZE = "size";
+    public static final String P_SIZE2 = "size2";
+
+    /* Default size */
+    public static final int DEFAULT_SIZE = 7;
+
+    /** Size of the tournament*/
+    public int size;
+    public int size2;
+
+    /** What's our probability of selection? If 1.0, we always pick the "good" individual. */
+    public double probabilityOfSelection;
+    public double probabilityOfSelection2;
+
+    /** Do we pick the worst instead of the best? */
+    public boolean pickWorst;
+    public boolean pickWorst2;
+    public boolean doLengthFirst;
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_TOURNAMENT);
+        }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        double val = state.parameters.getDouble(base.push(P_SIZE),def.push(P_SIZE),1.0);
+        if (val < 1.0)
+            state.output.fatal("Tournament size must be >= 1.",base.push(P_SIZE),def.push(P_SIZE));
+        else if (val > 1 && val < 2) // pick with probability
+            {
+            size = 2;
+            probabilityOfSelection = (val/2);
+            }
+        else if (val != (int)val)  // it's not an integer
+            state.output.fatal("If >= 2, Tournament size must be an integer.", base.push(P_SIZE), def.push(P_SIZE));
+        else
+            {
+            size = (int)val;
+            probabilityOfSelection = 1.0;
+            }
+
+        val = state.parameters.getDouble(base.push(P_SIZE2),def.push(P_SIZE2),1.0);
+        if (val < 1.0)
+            state.output.fatal("Tournament size2 must be >= 1.",base.push(P_SIZE2),def.push(P_SIZE2));
+        else if (val > 1 && val < 2) // pick with probability
+            {
+            size2 = 2;
+            probabilityOfSelection2 = (val/2);
+            }
+        else if (val != (int)val)  // it's not an integer
+            state.output.fatal("If >= 2, Tournament size2 must be an integer.", base.push(P_SIZE2), def.push(P_SIZE2));
+        else
+            {
+            size2 = (int)val;
+            probabilityOfSelection2 = 1.0;
+            }
+
+        doLengthFirst = state.parameters.getBoolean(base.push(P_DOLENGTHFIRST),def.push(P_DOLENGTHFIRST),true);
+        pickWorst = state.parameters.getBoolean(base.push(P_PICKWORST),def.push(P_PICKWORST),false);
+        pickWorst2 = state.parameters.getBoolean(base.push(P_PICKWORST2),def.push(P_PICKWORST2),false);
+        }
+
+    /**
+       Produces the index of a person selected from among several by a tournament.
+       The tournament's criteria is fitness of individuals if doLengthFirst is true,
+       otherwise the size of the individuals.
+    */
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        int[] inds = new int[size2];
+        for(int x=0;x<size2;x++) inds[x] = make(subpopulation,state,thread);
+
+        if (!doLengthFirst)
+            {
+            // pick size random individuals, then pick the best.
+            Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+            int i = inds[0];
+            int bad = i;
+            
+            for (int x=1;x<size2;x++)
+                {
+                int j = inds[x];
+                if (pickWorst2)
+                    { if (oldinds[j].size() > oldinds[i].size()) { bad = i; i = j; } else bad = j; }
+                else
+                    { if (oldinds[j].size() < oldinds[i].size()) { bad = i; i = j;} else bad = j; }
+                }
+            
+            if (probabilityOfSelection2 != 1.0 && !state.random[thread].nextBoolean(probabilityOfSelection2))
+                i = bad;
+            return i;
+            }
+        else 
+            {
+            // pick size random individuals, then pick the best.
+            Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+            int i = inds[0];
+            int bad = i;
+            
+            for (int x=1;x<size2;x++)
+                {
+                int j = inds[x];
+                if (pickWorst2)
+                    { if (!(oldinds[j].fitness.betterThan(oldinds[i].fitness))) { bad = i; i = j; } else bad = j; }
+                else
+                    { if (oldinds[j].fitness.betterThan(oldinds[i].fitness)) { bad = i; i = j;} else bad = j; }
+                }
+            
+            if (probabilityOfSelection2 != 1.0 && !state.random[thread].nextBoolean(probabilityOfSelection2))
+                i = bad;
+            return i;
+            }
+        }
+
+    /**
+       Produces the index of a person selected from among several by a tournament.
+       The tournament's criteria is size of individuals if doLengthFirst is true,
+       otherwise the fitness of the individuals.
+    */
+    public int make(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        if (doLengthFirst) // if length first, the first tournament is based on size
+            {
+            // pick size random individuals, then pick the best.
+            Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+            int i = state.random[thread].nextInt(oldinds.length) ;
+            int bad = i;
+            
+            for (int x=1;x<size;x++)
+                {
+                int j = state.random[thread].nextInt(oldinds.length);
+                if (pickWorst)
+                    { if (oldinds[j].size() > oldinds[i].size()) { bad = i; i = j; } else bad = j; }
+                else
+                    { if (oldinds[j].size() < oldinds[i].size()) { bad = i; i = j;} else bad = j; }
+                }
+            
+            if (probabilityOfSelection != 1.0 && !state.random[thread].nextBoolean(probabilityOfSelection))
+                i = bad;
+            return i;
+            }
+        else
+            {
+            // pick size random individuals, then pick the best.
+            Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+            int i = state.random[thread].nextInt(oldinds.length) ;
+            int bad = i;
+            
+            for (int x=1;x<size;x++)
+                {
+                int j = state.random[thread].nextInt(oldinds.length);
+                if (pickWorst)
+                    { if (!(oldinds[j].fitness.betterThan(oldinds[i].fitness))) { bad = i; i = j; } else bad = j; }
+                else
+                    { if (oldinds[j].fitness.betterThan(oldinds[i].fitness)) { bad = i; i = j;} else bad = j; }
+                }
+            
+            if (probabilityOfSelection != 1.0 && !state.random[thread].nextBoolean(probabilityOfSelection))
+                i = bad;
+            return i;
+            }
+        }
+
+
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        { return; }
+    
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        { return; }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/LexicographicTournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/LexicographicTournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/LexicographicTournamentSelection.java	(revision 6152)
@@ -0,0 +1,74 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.parsimony;
+
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+import ec.select.*;
+
+/* 
+ * LexicographicTournamentSelection.java
+ * 
+ * Created: Mon Aug 30 19:27:15 1999
+ * By: Liviu Panait & Sean Luke
+ */
+
+/**
+ * Does a simple tournament selection, limited to the subpopulation it's
+ * working in at the time.
+ *
+ * <p>Tournament selection works like this: first, <i>size</i> individuals
+ * are chosen at random from the population.  Then of those individuals,
+ * the one with the best fitness is selected.  If two individuals have the
+ * same fitness, the one with smaller size is prefered.
+ *
+ * The default tournament size is 7.
+ *
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the tournament size)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the tournament instead of the <i>best</i>?)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.lexicographic-tournament
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class LexicographicTournamentSelection extends TournamentSelection
+    {
+    /** default base */
+    public static final String P_TOURNAMENT = "lexicographic-tournament";
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_TOURNAMENT);
+        }
+    
+    public boolean betterThan(Individual first, Individual second, int subpopulation, EvolutionState state, int thread)
+        {
+        return (first.fitness.betterThan(second.fitness) ||
+            (first.fitness.equivalentTo(second.fitness) && first.size() < second.size()));
+        }
+                
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/ProportionalTournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/ProportionalTournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/ProportionalTournamentSelection.java	(revision 6152)
@@ -0,0 +1,90 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.parsimony;
+
+import ec.select.*;
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+
+/* 
+ * ProportionalTournamentSelection.java
+ * 
+ * Created: Fri Feb 01 2002
+ * By: Liviu Panait
+ */
+
+/**
+ * This selection method adds parsimony pressure to the regular tournament selection.  The comparison of
+ * individuals is based on fitness with probability <i>prob</i>, and it is based on size with probability
+ * <i>1-prob</i>.  For each pairwise comparsion of individuals, the ProportionalTournamentSelection randomly decides
+ * whether to compare based on fitness or size. 
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the tournament size)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the tournament instead of the <i>best</i>?)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>fitness-prob</tt><br>
+ <font size=-1> double &gt;= 0 and &lt;= 1</font></td>
+ <td valign=top>(the probability of comparing individuals based on fitness, rather than size)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.proportional-tournament
+
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public class ProportionalTournamentSelection extends TournamentSelection
+    {
+    /** default base */
+    public static final String P_PROPORTIONAL_TOURNAMENT = "proportional-tournament";
+
+    /** The parameter for the probability of having the tournament based on fitness */
+    public static final String P_PROBABILITY = "fitness-prob";
+
+    /** The probability of having the tournament based on fitness */
+    public double fitnessPressureProb;
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_PROPORTIONAL_TOURNAMENT);
+        }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        fitnessPressureProb = state.parameters.getDouble(base.push(P_PROBABILITY),def.push(P_PROBABILITY),0.0);
+        if( fitnessPressureProb<0.0 || fitnessPressureProb>1.0 )
+            state.output.fatal( "Probability must be between 0.0 and 1.0",
+                base.push(P_PROBABILITY),def.push(P_PROBABILITY));
+        }
+
+    public boolean betterThan(Individual first, Individual second, int subpopulation, EvolutionState state, int thread)
+        {
+        if (state.random[thread].nextBoolean(fitnessPressureProb))
+            return first.fitness.betterThan(second.fitness);
+        else
+            return first.size() < second.size();
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/README	(revision 6152)
@@ -0,0 +1,206 @@
+ECJ supports several bloat control techniques.  Many of these techniques
+are compared in detail in "A Comparison of bloat Control Methods for
+Genetic Programming" by Sean Luke and Liviu Panait.  In this directory
+we have implementations of several of them.
+
+There are several methods in the article which aren't here.  The two you
+should be aware of are BIASED MULTIOBJECTIVE, where we do multiobjective
+optimization with fitness as one objective and size as another; and
+plain-old LINEAR parsimony pressure, where the "fitness" F of an
+individual is actually his real fitness R and his size S, combined in a
+linear function, that is, F = A*R + S for some value of R.  We mention
+these two because, like many of the techniques below, they perform well
+over many different problem domains.  And importantly, LINEAR performed
+the best in our tests!  Closely followed by RATIO TOURNAMENT SELECTION
+(see below).  Double Tournament was pretty good too.  The problem with
+linear parsimony pressure is that it could need to be tuned carefully --
+though a setting of A = 32 seemed to work well in many problems.  Thus
+you may wish to try out doing a simple linear parsimony pressure before
+going to a more exotic method.  You can implement linear parsimony
+pressure in your evaluation function: compute the fitness, then call the
+size() method on the individual, then set the fitness of the individual
+to the linear combination of the two.
+
+Another technique commonly used to control bloat in GP is depth
+limiting.  ECJ implements depth limiting Koza-style with a maximum depth
+set to 17.  You can often get better results with a smaller depth limit. 
+Interestingly, when the depth limit is set to 17, you can use depth
+limiting in COMBINATION with ANY of the parsimony pressure techniques
+discussed here, (including linear and biased multiobjective) and the
+result is typically better than using them separately.
+
+
+
+DOUBLE TOURNAMENT
+
+Double tournament is a two-layer hierarchy of tournament selection
+operators. Some N tournament selections are performed on some criterion;
+and then the winners of those tournaments become contestants in a final
+tournament.  The winner of the final tournament becomes the selected
+individual.  You can have fitness as the first criterion and size as the
+second criterion, or the other way around.
+
+Here are good settings we've found for typical GP experiments.
+
+[BASE] = ec.parsimony.DoubleTournamentSelection
+# Do length as the initial tournaments, and fitness as the final tournament
+[BASE].do-length-first = true
+# The initial tournaments are of size 1.4
+[BASE].size = 1.4
+# The final tournament is of size 7
+[BASE].size2 = 7
+
+The default base is
+	select.double-tournament
+
+
+PROPORTIONAL TOURNAMENT
+
+Proportional tournament is a single tournament selection; but some
+percentage of the time the tournament is according to size rather than
+according to fitness.
+
+Here are good settings we've found for typical GP experiments.
+
+[BASE] = ec.parsimony.ProportionalTournamentSelection
+# The size of the tournament
+[BASE].size = 7
+# The probability that the tournament is by fitness (1.0 is equivalent
+# to "regular" tournament selection).
+[BASE].fitness-prob = 0.8
+
+The default base is
+	select.proportional-tournament
+
+
+
+LEXICOGRAPHIC TOURNAMENT
+
+Lexicographic tournament selection is simple.  We do a tournament
+selection by fitness, breaking ties by choosing the smaller individual. 
+Thus size is a secondary consideration: for example, if all your fitness
+values are likely to be different, then size will never have an effect. 
+Thus plain lexicographic tournament selection works best when there are
+a limited number of possible fitness values.
+
+Lexicographic tournament has no special settings -- it's basically the
+same as plain tournament selection.  Here's how we'd set it up for GP
+problems:
+
+[BASE] = ec.parsimony.LexicographicTournament
+# The size of the tournament
+[BASE].size = 7
+
+The default base is
+	select.lexicographic-tournament
+
+
+
+[DIRECT] BUCKETED TOURNAMENT SELECTION
+
+Bucketed tournament selection is an improvement of sorts over plain
+Lexicographic tournament selection.  The idea is to create an artificial
+equivalency of fitness values, even when none exists in reality, for
+purposes of lexicographic selection.  This allows size to become a
+significant factor.  to create a set of N buckets.  The population, of
+size S, is then sorted and divided into these buckets.  It's not divided
+quite equally.  Instead, the bottom S/N individuals are placed in the
+first bucket.  Then any individuals left in the population whose fitness
+equals the fittest individual in that bucket are *also* put in that
+bucket.  Then the bottom S/N of the remaining individuals in the
+population are put in the second bucket, plus any individuals whose
+fitness equals the fittest individual in the second bucket. And so on. 
+This continues until we've run out of individuals to put into buckets. 
+The idea is to make sure that individuals with the same fitness are all
+placed into the same bucket.  The "fitness" of an individual, for
+purposes of lexicographic selection, is now his bucket number.
+
+We did not find a direct bucketing number-of-buckets parameter which was
+good across several problem domains.  We found 100 was good for
+artificial ant, 250 for 11-bit Multiplexer and 5-bit Parity, and 25 for
+Symbolic Regression.  You'll need to experiment a bit.  Here's the
+settings for Multiplexer:
+
+[BASE] = ec.parsimony.BucketTournamentSelection
+# The size of the tournament
+[BASE].size = 7
+# The number of buckets
+[BASE].num-buckets = 250
+
+The default base is
+	select.bucket-tournament
+
+
+
+RATIO BUCKETED TOURNAMENT SELECTION
+
+Ratio Bucketing improves a bit over direct bucketing.  Here, the idea is
+to push low-fitness individuals in to large buckets and place
+high-fitness individuals into smaller buckets, even as small as the
+individual itself.  This allows more fitness-based distinction among the
+"important" individuals in the search (the fitter ones) and puts more
+parsimony pressure in the "less important" individuals.  We do this by
+defining a ratio of remaining individuals in the population to put in
+the next bucket.  Let's say this ratio is 1/R.  We put the 1/R worst
+individuals of the population in lowest bucket, plus all remaining
+individuals in the population whose fitness is equal to the fittest
+individual in the bucket.  We then put the 1/4 next worst remaining
+individuals in the next bucket, plus all remaining individuals in the
+population whose fitness is equal to the fittest individual in the
+second bucket.  And so on, until all individuals have been placed into
+buckets.  The "fitness" of an individual, for purposes of lexicographic
+selection, is now his bucket number.
+
+Like direct bucketing, we did not find a value of R which was good
+across several problem domains.  2 was good for artificial ant, 11-bit
+mutiplexer, and regression.  but 6 ws good for 5-bit parity.  So you'll
+need to experiment.  Here's the settings for Multiplexer:
+
+[BASE] = ec.parsimony.RatioBucketTournamentSelection
+# The size of the tournament
+[BASE].size = 7
+# The number of buckets
+[BASE].ratio = 2
+
+The default base is
+        select.ratio-bucket-tournament
+
+
+
+TARPEIAN SELECTION
+
+Tarpeian is fairly simple but clever.  PRIOR to evaluation, we sort the
+population by size, then identify the M individuals which have
+above-average size. From those M individuals we "kill" some N percent. 
+Notice that M may vary from population to population depending on the
+variance of size among the individuals.
+
+By "kill" we mean that we set the fitness of those individuals to a very
+bad value, and also mark them as evaluated so the Evaluator doesn't
+bother evaluating them.
+
+Not evaluating the individuals is really important: if every individual
+is evaluated, Tarpeian is actually pretty costly compared to other
+methods.  But if we prematurely "kill" the individuals, then Tarpeian is
+pretty competitive if you count total number of evaluations.
+
+Because Tarpeian must do its work prior to evaluation, it can't operate
+as a selection operator in ECJ's framework.  Instead, we've arranged for
+Tarpeian to be a Statistics subclass which plugs into the
+preEvaluationStatistics hook.  To use it, you just hang it off of your
+statistics chain.  Assuming you only have one existing Statistics
+object, here's how you'd add Tarpeian in a manner which has proven good
+across several problem domains:
+
+stat.num-children = 1
+stat.child.0 = ec.parsimony.TarpeianStatistics
+stat.child.0.kill-proportion = 0.3
+
+Note that our implementation of Tarpeian will operate over *all* of your
+subpopuations, even if you don't want that.  You may need to hack it to
+operate differently if you have more than one subpopulation and don't
+want Tarpeian parsimony on one or more of them.
+
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/RatioBucketTournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/RatioBucketTournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/RatioBucketTournamentSelection.java	(revision 6152)
@@ -0,0 +1,257 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.parsimony;
+
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+import ec.select.*;
+
+/* 
+ * RatioBucketTournamentSelection.java
+ * 
+ * Created: Mon Apr 09 17:02:30 2001
+ * By: Liviu Panait
+ */
+
+/**
+ *
+ * Does a tournament selection, limited to the subpopulation it's
+ * working in at the time.
+ *
+ * <p>Ratio Bucket Lexicographic Tournament selection works like as follows. The sizes of buckets are
+ * proportioned so that low-fitness individuals are placed into much larger buckets than high-fitness
+ * individuals.  A bucket ratio <i>1/ratio</i> is specified beforehand.  The bottom <i>1/ratio</i> individuals
+ * of the population are placed into the bottom bucket. If any individuals remain in the population
+ * with the same fitness as the best individual in the bottom bucket, they too are placed in that bucket.
+ * Of the remaining population, the next <i>1/ratio</i> individuals are placed into the next bucket, plus any
+ * individuals remaining in the population with the same fitness as the best individual now in that bucket,
+ * and so on.  This continues until every member of the population has been placed in a bucket. Once again,
+ * the fitness of every individual in a bucket is set to the rank of the bucket relative to other buckets.
+ * Ratio bucketing thus allows parsimony to have more of an effect on average when two similar low-fitness
+ * individuals are considered than when two high-fitness individuals are considered.
+ *
+ * After ranking the individuals, <i>size</i> individuals are chosen at random from the
+ * population. Of those individuals, the one with the highest rank is selected. If the two
+ * individuals are in the same rank, meaning that they have similar fitness, the one
+ * with the smallest size is selected.
+ *
+ * <p>Bucket Lexicographic Tournament selection is so simple that it doesn't
+ * need to maintain a cache of any form, so many of the SelectionMethod methods
+ * just don't do anything at all.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>size</tt><br>
+ <font size=-1>int &gt;= 1 (default 7)</font></td>
+ <td valign=top>(the tournament size)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the tournament instead of the <i>best</i>?)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>ratio</tt><br>
+ <font size=-1>float &gt;= 2 (default)</font></td>
+ <td valign=top>(the ratio of worst out of remaining individuals that go in the next bucket)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.ratio-bucket-tournament
+
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public class RatioBucketTournamentSelection extends SelectionMethod implements SteadyStateBSourceForm
+    {
+    /** default base */
+    public static final String P_RATIO_BUCKET_TOURNAMENT = "ratio-bucket-tournament";
+
+    /** size parameter */
+    public static final String P_SIZE = "size";
+
+    /** Default size */
+    public static final int DEFAULT_SIZE = 7;
+
+    /** Size of the tournament*/
+    public int size;
+
+    /** if the worst individual should be picked in the tournament */
+    public static final String P_PICKWORST = "pick-worst";
+
+    /** Do we pick the worst instead of the best? */
+    public boolean pickWorst;
+
+    /** The value of RATIO: each step, the worse 1/RATIO individuals are assigned the same fitness */
+    public static final String P_RATIO = "ratio";
+
+    /** The default value for RATIO */
+    static float defaultRATIO = 2;
+
+    /** The value of RATIO */
+    public float ratio;
+
+    // the indexes of the buckets where the individuals should go (will be used instead of fitness)
+    int[] bucketValues;
+ 
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_RATIO_BUCKET_TOURNAMENT);
+        }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        size = state.parameters.getInt(base.push(P_SIZE),def.push(P_SIZE),1);
+        if (size < 1)
+            state.output.fatal("Tournament size must be >= 1.",base.push(P_SIZE),def.push(P_SIZE));
+
+        if( state.parameters.exists( base.push(P_RATIO), def.push(P_RATIO)))
+            {
+            ratio = state.parameters.getFloat(base.push(P_RATIO),def.push(P_RATIO),2.0f);
+            if( ratio<2 )
+                {
+                state.output.fatal("The value of b must be >= 2.",base.push(P_RATIO),def.push(P_RATIO));
+                }
+            }
+        else
+            {
+            ratio = defaultRATIO;
+            }
+
+        pickWorst = state.parameters.getBoolean(base.push(P_PICKWORST),def.push(P_PICKWORST),false);
+        }
+
+    /** Prepare to produce: create the buckets!!!! */
+    public void prepareToProduce(final EvolutionState state, final int subpopulation, final int thread) 
+        {
+        bucketValues = new int[ state.population.subpops[subpopulation].individuals.length ];
+        
+        // correct?
+        java.util.Arrays.sort(state.population.subpops[subpopulation].individuals,
+            new java.util.Comparator()
+                {
+                public int compare(Object o1, Object o2)
+                    {
+                    Individual a = (Individual) o1;
+                    Individual b = (Individual) o2;
+                    if (a.fitness.betterThan(b.fitness))
+                        return 1;
+                    if (b.fitness.betterThan(a.fitness))
+                        return -1;
+                    return 0;
+                    }
+                });
+
+        // how many individuals in current bucket
+        int nInd;
+
+        float totalInds = ((float)state.population.subpops[subpopulation].individuals.length);
+        float averageBuck = Math.max( totalInds/ratio, 1 );
+
+        // first individual goes into first bucket
+        bucketValues[0] = 0;
+
+        // now there is one individual in the first bucket
+        nInd = 1;
+        totalInds--;
+
+        for( int i = 1 ; i < state.population.subpops[subpopulation].individuals.length ; i++ )
+            {
+            // if there is still some place left in the current bucket, throw the current individual there too
+            if( nInd < averageBuck )
+                {
+                bucketValues[i] = bucketValues[i-1];
+                nInd++;
+                }
+            else // check if it has the same fitness as last individual
+                {
+                if( ((Individual)state.population.subpops[subpopulation].individuals[i]).fitness.equivalentTo(
+                        ((Individual)state.population.subpops[subpopulation].individuals[i-1]).fitness ) )
+                    {
+                    // now the individual has exactly the same fitness as previous one,
+                    // so we just put it in the same bucket as the previous one(s)
+                    bucketValues[i] = bucketValues[i-1];
+                    nInd++;
+                    }
+                else
+                    {
+                    // new bucket!!!!
+                    averageBuck = Math.max( totalInds/ratio, 1 );
+                    bucketValues[i] = bucketValues[i-1] - 1; // decrease the fitness, so that high fit individuals have lower bucket values
+                    // with only one individual
+                    nInd = 1;
+                    }
+                }
+            totalInds--;
+            }
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        // pick size random individuals, then pick the best.
+        Individual[] oldinds = (state.population.subpops[subpopulation].individuals);
+        int i = state.random[thread].nextInt(oldinds.length);
+        long si = 0;
+
+        for (int x=1;x<size;x++)
+            {
+            int j = state.random[thread].nextInt(oldinds.length);
+            if (pickWorst)
+                {
+                if( bucketValues[j]>bucketValues[i] ) { i = j; si = 0; }
+                else if( bucketValues[i]>bucketValues[j] ) { } // do nothing
+                else
+                    {
+                    if (si==0)
+                        si = oldinds[i].size();
+                    long sj = oldinds[j].size();
+
+                    if (sj >= si) // sj's got worse lookin' trees
+                        { i = j; si = sj; }
+                    }
+                }
+            else
+                { 
+                if( bucketValues[j]<bucketValues[i] ) { i = j; si = 0; }
+                else if( bucketValues[i]<bucketValues[j] ) { } // do nothing
+                else
+                    {
+                    if (si==0)
+                        si = oldinds[i].size();
+                    long sj = oldinds[j].size();
+
+                    if (sj < si) // sj's got better lookin' trees
+                        { i = j; si = sj; }
+                    }
+                }
+            }
+        return i;
+        }
+
+    // included for SteadyState
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        { return; }
+    
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        { return; }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/parsimony/TarpeianStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/parsimony/TarpeianStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/parsimony/TarpeianStatistics.java	(revision 6152)
@@ -0,0 +1,108 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.parsimony;
+
+import ec.*;
+import ec.util.*;
+
+/**
+   This Statistics subclass implements Poli's "Tarpeian" method of parsimony control, whereby some
+   <i>kill-proportion</i> of above-average-sized individuals in each subpopulation have their fitnesses
+   set to a very bad value, and marks them as already evaluated (so the Evaluator can skip them).  
+   The specific individuals in this proportion is determined at random.
+        
+   <p>Different Fitnesses have different meanings of the word "bad".  At present, we set the fitness
+   to -Float.MAX_VALUE if it's a SimpleFitness, and set it to Float.MAX_VALUE if it's a KozaFitnesss.
+   If it's any other kind of Fitness, an error is reported.  You can override the "bad-setter" function
+   setMinimumFitness(...) to make other kinds of fitness bad in different ways.  In the future we may
+   revisit how to set Fitnesses to "bad" in a more general way if this becomes an issue.
+        
+   <p>Tarpeian is implemented as a Statistics.  Why?  Because we need to mark individuals as evaluated
+   prior to the Evaluator getting to them, and also need to keep track of the total proportion marked
+   as such.  We considered doing this as a SelectionMethod, as a BreedingPipeline, as a Breeder, and
+   as an Evaluator.  None are good options really -- Evaluator is the best approach but it means we
+   have special Tarpeian Evaluators, so it's no longer orthogonal with other Evaluators.  Eventually
+   we settled on the one object which has the right hooks and can be easily stuck onto the system without
+   modifying anything in a special-purpose way: a Statistics object.
+        
+   <p>All you need to do is add TarpeianStatistics as a child to your existing Statistics chain.  If you
+   have one existing Statistics, then you just add the parameters <tt>stat.num-children=1</tt> and
+   <tt>stat.child.0=ec.parsimony.TarpeianStatistics</tt>  You'll also need to specify the kill proportion
+   (for example, <tt>stat.child.0.kill-proportion=0.2</tt> )
+        
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>kill-proportion</tt><br>
+   <font size=-1>0 &lt; int &lt; 1</font></td>
+   <td valign=top>(proportion of above-average-sized individuals killed)</td></tr>
+   </table>
+
+*/
+ 
+public class TarpeianStatistics extends Statistics
+    {
+    /** one in n individuals are killed */
+    public static final String P_KILL_PROPORTION = "kill-proportion";
+    float killProportion;
+
+    public void setup( final EvolutionState state, final Parameter base )
+        {
+        super.setup (state, base);
+
+        killProportion = state.parameters.getFloat( base.push(P_KILL_PROPORTION), null, 0.0 );
+        if( killProportion < 0 || killProportion > 1 )
+            state.output.fatal( "Parameter not found, or it has an invalid value (<0 or >1).", base.push(P_KILL_PROPORTION) );
+        }
+
+    /**
+       Marks a proportion (killProportion) of individuals with above-average size (within their own subpopulation) to a minimum value.
+    */
+    public void preEvaluationStatistics(final EvolutionState state)
+        {
+        for( int subpopulation = 0 ; subpopulation < state.population.subpops.length ; subpopulation++ )
+            {
+            double averageSize = 0;
+
+            for( int i = 0 ; i < state.population.subpops[subpopulation].individuals.length ; i++ )
+                averageSize += state.population.subpops[subpopulation].individuals[i].size();
+
+            averageSize /= state.population.subpops[subpopulation].individuals.length;
+
+            for( int i = 0 ; i < state.population.subpops[subpopulation].individuals.length ; i++ )
+                {
+                if( ( state.population.subpops[subpopulation].individuals[i].size() > averageSize ) &&
+                    ( state.random[0].nextFloat() < killProportion ) )
+                    {
+                    Individual ind = state.population.subpops[subpopulation].individuals[i];
+                    setMinimumFitness( state, subpopulation, ind );
+                    ind.evaluated = true;
+                    }
+                }
+            }
+        }
+
+    /**
+       Sets the fitness of an individual to the minimum fitness possible.
+       If the fitness is of type ec.simple.SimpleFitness, that minimum value is -Float.MAX_VALUE;
+       If the fitness is of type ec.gp.koza.KozaFitness, that minimum value is Float.MAX_VALUE;
+       Else, a fatal error is reported.
+
+       You need to override this method if you're using any other type of fitness.
+    */
+    public void setMinimumFitness( final EvolutionState state, int subpopulation, Individual ind )
+        {
+        Fitness fitness = ind.fitness;
+        if( fitness instanceof ec.gp.koza.KozaFitness )
+            ((ec.gp.koza.KozaFitness)fitness).setStandardizedFitness( state, Float.MAX_VALUE );
+        else if( fitness instanceof ec.simple.SimpleFitness )
+            ((ec.simple.SimpleFitness)fitness).setFitness(state,-Float.MAX_VALUE,false);
+        else
+            state.output.fatal( "TarpeianStatistics only accepts individuals with fitness of type ec.simple.SimpleFitness or ec.gp.koza.KozaFitness." );
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/pso/PSOBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/pso/PSOBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/pso/PSOBreeder.java	(revision 6152)
@@ -0,0 +1,132 @@
+/*
+  Copyright 2006 by Ankur Desai, Sean Luke, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.pso;
+
+import ec.Breeder;
+import ec.EvolutionState;
+import ec.Population;
+import ec.util.Parameter;
+import ec.vector.DoubleVectorIndividual;
+/**
+ * PSOBreeder.java
+ *
+ 
+ <p>The PSOBreeder performs the calculations to determine new particle locations
+ and performs the bookkeeping to keep track of personal, neighborhood, and global
+ best solutions.
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>debug-info</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether the system should display information useful for debugging purposes)<br>
+ </td></tr>
+
+ </table>
+
+ * @author Joey Harrison, Ankur Desai
+ * @version 1.0 
+ */
+public class PSOBreeder extends Breeder
+    {
+    public void setup(EvolutionState state, Parameter base) 
+        {
+        // intentionally empty
+        }
+                
+    public Population breedPopulation(EvolutionState state)
+        {
+        PSOSubpopulation subpop = (PSOSubpopulation) state.population.subpops[0];
+                
+        // update bests
+        assignPersonalBests(subpop);
+        assignNeighborhoodBests(subpop);
+        assignGlobalBest(subpop);
+
+        // make a temporary copy of locations so we can modify the current location on the fly
+        DoubleVectorIndividual[] tempClone = new DoubleVectorIndividual[subpop.individuals.length];
+        System.arraycopy(subpop.individuals, 0, tempClone, 0, subpop.individuals.length);
+                
+        // update particles             
+        for (int i = 0; i < subpop.individuals.length; i++)
+            {
+            DoubleVectorIndividual ind = (DoubleVectorIndividual)subpop.individuals[i];
+            DoubleVectorIndividual prevInd = (DoubleVectorIndividual)subpop.previousIndividuals[i];
+            // the individual's personal best
+            DoubleVectorIndividual pBest = (DoubleVectorIndividual)subpop.personalBests[i];
+            // the individual's neighborhood best
+            DoubleVectorIndividual nBest = (DoubleVectorIndividual)subpop.neighborhoodBests[i];
+            // the individuals's global best
+            DoubleVectorIndividual gBest = (DoubleVectorIndividual)subpop.globalBest;
+                        
+            // calculate update for each dimension in the genome
+            for (int j = 0; j < ind.genomeLength(); j++)
+                { 
+                double velocity = ind.genome[j] - prevInd.genome[j];
+                double pDelta = pBest.genome[j] - ind.genome[j];                        // difference to personal best
+                double nDelta = nBest.genome[j] - ind.genome[j];                        // difference to neighborhood best
+                double gDelta = gBest.genome[j] - ind.genome[j];                        // difference to global best
+                double pWeight = state.random[0].nextDouble();                          // weight for personal best
+                double nWeight = state.random[0].nextDouble();                          // weight for neighborhood best
+                double gWeight = state.random[0].nextDouble();                          // weight for global best
+                double newDelta = (velocity + pWeight*pDelta + nWeight*nDelta + gWeight*gDelta) / (1+pWeight+nWeight+gWeight);
+                        
+                // update this individual's genome for this dimension
+                ind.genome[j] += newDelta * subpop.velocityMultiplier;     // it's obvious if you think about it
+                }
+            
+            if (subpop.clampRange)
+                ind.clamp();                 
+            }               
+                
+        // update previous locations
+        subpop.previousIndividuals = tempClone;
+                                
+        return state.population;
+        }
+
+    public void assignPersonalBests(PSOSubpopulation subpop)
+        {
+        for (int i = 0; i < subpop.personalBests.length; i++)                   
+            if ((subpop.personalBests[i] == null) || subpop.individuals[i].fitness.betterThan(subpop.personalBests[i].fitness))
+                subpop.personalBests[i] = (DoubleVectorIndividual)subpop.individuals[i].clone();
+        }
+
+    public void assignNeighborhoodBests(PSOSubpopulation subpop)
+        {
+        for (int j = 0; j < subpop.individuals.length; j++)
+            {
+            DoubleVectorIndividual hoodBest = subpop.neighborhoodBests[j];
+            int start = (j - subpop.neighborhoodSize / 2);
+            if (start < 0)
+                start += subpop.individuals.length;
+                        
+            for (int i = 0; i < subpop.neighborhoodSize; i++)
+                {
+                DoubleVectorIndividual ind = (DoubleVectorIndividual)subpop.individuals[(start + i) % subpop.individuals.length];
+                if((hoodBest == null) || ind.fitness.betterThan(hoodBest.fitness))
+                    hoodBest = ind;
+                }
+                        
+            if (hoodBest != subpop.neighborhoodBests[j])
+                subpop.neighborhoodBests[j] = (DoubleVectorIndividual)hoodBest.clone();
+            }
+        }
+        
+    public void assignGlobalBest(PSOSubpopulation subpop)
+        {
+        DoubleVectorIndividual globalBest = subpop.globalBest;
+        for (int i = 0; i < subpop.individuals.length; i++)
+            {
+            DoubleVectorIndividual ind = (DoubleVectorIndividual)subpop.individuals[i];
+            if ((globalBest == null) || ind.fitness.betterThan(globalBest.fitness))
+                globalBest = ind;
+            }
+        if (globalBest != subpop.globalBest)
+            subpop.globalBest = (DoubleVectorIndividual)globalBest.clone();
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/pso/PSOSubpopulation.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/pso/PSOSubpopulation.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/pso/PSOSubpopulation.java	(revision 6152)
@@ -0,0 +1,402 @@
+/*
+  Copyright 2006 by Ankur Desai, Sean Luke, and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.pso;
+
+import ec.*;
+import ec.util.*;
+import ec.vector.*;
+import java.io.*;
+
+/**
+ * PSOSubpopulation.java
+ *
+ 
+ <p>Particle Swarm Optimization (PSO) is a population-oriented stochastic search 
+ technique similar to genetic algorithms, evolutionary strategies, and other evolutionary
+ computation algorithms. The technique discovers solutions for N-dimensional 
+ parameterized problems: basically it discovers the point in N-dimensional space which
+ maximizes some quality function. 
+   
+ <p>PSOSubpopulation handles initialization and input/output of the swarm.   
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ 
+ <tr><td valign=top><i>base</i>.<tt>neighborhood-size</tt><br>
+ <font size=-1>integer</font></td>
+ <td valign=top>(the number of individuals per neighborhood)<br></td></tr>
+ 
+ <tr><td valign=top><i>base</i>.<tt>clamp</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(clamp the individual to stay within the bounds or not)<br></td></tr>
+ 
+ <tr><td valign=top><i>base</i>.<tt>initial-velocity-scale</tt><br>
+ <font size=-1>double</font></td>
+ <td valign=top>(particles are initialized with a random velocity and this value provides bounds. 
+ A value of 1.0 means that the velocity will be within +/- the range of the genotype.)<br></td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>velocity-multiplier</tt><br>
+ <font size=-1>double</font></td>
+ <td valign=top>(particle velocities are multiplied by this value before the particle is updated. 
+ Increasing this value helps particles to escape local optima, but slows convergence. The default 
+ value of 1.5 is geared toward multi-modal landscapes.)<br></td></tr>
+ 
+ </table>
+ 
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>data</tt></td>
+ <td>Subpopulation</td></tr>
+ </table>
+ 
+ * @author Joey Harrison, Ankur Desai
+ * @version 1.0 
+ */
+public class PSOSubpopulation extends Subpopulation
+    {
+    public int neighborhoodSize;       
+    public static final String P_NEIGHBORHOOD_SIZE = "neighborhood-size";
+        
+    public boolean clampRange;
+    public static final String P_CLAMP_RANGE = "clamp";
+        
+    public double initialVelocityScale;
+    public static final String P_INITIAL_VELOCITY_SCALE = "initial-velocity-scale";
+    
+    public double velocityMultiplier;
+    public static final String P_VELOCITY_MULTIPLIER = "velocity-multiplier";
+        
+    public DoubleVectorIndividual globalBest;
+    public DoubleVectorIndividual[] neighborhoodBests;
+    public DoubleVectorIndividual[] personalBests;
+    public DoubleVectorIndividual[] previousIndividuals;
+    
+    public static final String GLOBAL_BEST_PREAMBLE = "Global-Best Individual: ";
+    public static final String NEIGHBORHOOD_BEST_PREAMBLE = "Neighborhood Best Individuals: ";
+    public static final String PERSONAL_BEST_PREAMBLE = "Personal Best Individuals ";
+    public static final String PREVIOUS_INDIVIDUAL_PREAMBLE = "Previous Individuals ";
+    public static final String INDIVIDUAL_EXISTS_PREAMBLE = "Exists: ";
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+        
+        if (!(species instanceof FloatVectorSpecies))
+            state.output.error("PSOSubpopulation requires that its species is ec.vector.FloatVectorSpecies or a subclass.  Yours is: " + species.getClass(),
+                null,null);
+        if (!(species.i_prototype instanceof DoubleVectorIndividual))
+            state.output.error("PSOSubpopulation requires that its species' prototypical individual be is ec.vector.DoubleVectorSpecies or a subclass.  Yours is: " + species.getClass(),
+                null,null);
+        
+        neighborhoodBests = new DoubleVectorIndividual[individuals.length];
+        personalBests = new DoubleVectorIndividual[individuals.length];
+        previousIndividuals = new DoubleVectorIndividual[individuals.length];
+        
+        neighborhoodSize = state.parameters.getInt(base.push(P_NEIGHBORHOOD_SIZE), null);
+        clampRange = state.parameters.getBoolean(base.push(P_CLAMP_RANGE), null, false);
+        initialVelocityScale = state.parameters.getDouble(base.push(P_INITIAL_VELOCITY_SCALE), null,0);
+        velocityMultiplier = state.parameters.getDouble(base.push(P_VELOCITY_MULTIPLIER), null,0.1);
+        }
+    
+    void clear(DoubleVectorIndividual[] inds)
+        {
+        for(int x=0;x<inds.length;x++) { inds[x] = null; }
+        }
+        
+    public void populate(EvolutionState state, int thread)
+        {
+        super.populate(state, thread);
+        
+        if (loadInds == null)  // we're generating new individuals, not reading them from a file
+            {
+            clear(neighborhoodBests);
+            clear(personalBests);
+        
+            FloatVectorSpecies fvSpecies = (FloatVectorSpecies)species;
+            /* double range = fvSpecies.maxGene - fvSpecies.minGene; */
+                    
+            for (int i = 0; i < individuals.length; i++)
+                {
+                DoubleVectorIndividual prevInd = (DoubleVectorIndividual)individuals[i].clone();
+                                    
+                // pick a genome near prevInd but not outside the box
+                for(int j = 0; j < prevInd.genomeLength(); j++)
+                    {
+                    double val = prevInd.genome[j];
+                    double range = fvSpecies.maxGene(j) - fvSpecies.minGene(j);
+                    do 
+                        prevInd.genome[j] = val + (range * initialVelocityScale) * (state.random[thread].nextDouble()*2.0 - 1.0);
+                    while (prevInd.genome[j] < fvSpecies.minGene(j) || prevInd.genome[j] > fvSpecies.maxGene(j));
+                    }
+                previousIndividuals[i] = prevInd;
+                }
+            }
+        }
+
+    /** Overridden to include the global best, neighborhood bests, personal bests, and previous individuals in the stream.
+        The neighborhood size, clamp range, and initial velocity scale are not included -- it's assumed you're using the
+        same values for them on reading, or understand that the values are revised. */
+    public void printSubpopulationForHumans(final EvolutionState state,
+        final int log)
+        {
+        // global best
+        state.output.println(GLOBAL_BEST_PREAMBLE, log);
+        if (globalBest == null) 
+            state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "false", log);
+        else 
+            {
+            state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "true", log);
+            globalBest.printIndividualForHumans(state, log);
+            }
+        
+        // neighborhoodBests
+        state.output.println(NEIGHBORHOOD_BEST_PREAMBLE, log);
+        for(int i = 0; i < individuals.length; i++)
+            if (neighborhoodBests[i] == null)
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "false", log);
+            else 
+                {
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "true", log);
+                neighborhoodBests[i].printIndividualForHumans(state, log);
+                }
+            
+        // personalBests
+        state.output.println(PERSONAL_BEST_PREAMBLE, log);
+        for(int i = 0; i < individuals.length; i++)
+            if (personalBests[i] == null)
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "false", log);
+            else 
+                {
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "true", log);
+                personalBests[i].printIndividualForHumans(state, log);
+                }
+
+        // neighborhoodBests
+        state.output.println(PREVIOUS_INDIVIDUAL_PREAMBLE, log);
+        for(int i = 0; i < individuals.length; i++)
+            if (previousIndividuals[i] == null)
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "false", log);
+            else 
+                {
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + "true", log);
+                previousIndividuals[i].printIndividualForHumans(state, log);
+                }
+
+        super.printSubpopulationForHumans(state, log);
+        }
+        
+    /** Overridden to include the global best, neighborhood bests, personal bests, and previous individuals in the stream.
+        The neighborhood size, clamp range, and initial velocity scale are not included -- it's assumed you're using the
+        same values for them on reading, or understand that the values are revised. */
+    public void printSubpopulation(final EvolutionState state,
+        final int log)
+        {
+        // global best
+        state.output.println(GLOBAL_BEST_PREAMBLE, log);
+        if (globalBest == null) 
+            state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false), log);
+        else 
+            {
+            state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true), log);
+            globalBest.printIndividual(state, log);
+            }
+        
+        // neighborhoodBests
+        state.output.println(NEIGHBORHOOD_BEST_PREAMBLE, log);
+        for(int i = 0; i < individuals.length; i++)
+            if (neighborhoodBests[i] == null)
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false), log);
+            else 
+                {
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true), log);
+                neighborhoodBests[i].printIndividual(state, log);
+                }
+            
+        // personalBests
+        state.output.println(PERSONAL_BEST_PREAMBLE, log);
+        for(int i = 0; i < individuals.length; i++)
+            if (personalBests[i] == null)
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false), log);
+            else 
+                {
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true), log);
+                personalBests[i].printIndividual(state, log);
+                }
+
+        // neighborhoodBests
+        state.output.println(PREVIOUS_INDIVIDUAL_PREAMBLE, log);
+        for(int i = 0; i < individuals.length; i++)
+            if (previousIndividuals[i] == null)
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false), log);
+            else 
+                {
+                state.output.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true), log);
+                previousIndividuals[i].printIndividual(state, log);
+                }
+
+        super.printSubpopulation(state, log);
+        }
+        
+    /** Overridden to include the global best, neighborhood bests, personal bests, and previous individuals in the stream.
+        The neighborhood size, clamp range, and initial velocity scale are not included -- it's assumed you're using the
+        same values for them on reading, or understand that the values are revised. */
+    public void printSubpopulation(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        // global best
+        writer.println(GLOBAL_BEST_PREAMBLE);
+        if (globalBest == null) 
+            writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false));
+        else 
+            {
+            writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true));
+            globalBest.printIndividual(state, writer);
+            }
+        
+        // neighborhoodBests
+        writer.println(NEIGHBORHOOD_BEST_PREAMBLE);
+        for(int i = 0; i < individuals.length; i++)
+            if (neighborhoodBests[i] == null)
+                writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false));
+            else 
+                {
+                writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true));
+                neighborhoodBests[i].printIndividual(state, writer);
+                }
+            
+        // personalBests
+        writer.println(PERSONAL_BEST_PREAMBLE);
+        for(int i = 0; i < individuals.length; i++)
+            if (personalBests[i] == null)
+                writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false));
+            else 
+                {
+                writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true));
+                personalBests[i].printIndividual(state, writer);
+                }
+
+        // neighborhoodBests
+        writer.println(PREVIOUS_INDIVIDUAL_PREAMBLE);
+        for(int i = 0; i < individuals.length; i++)
+            if (previousIndividuals[i] == null)
+                writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(false));
+            else 
+                {
+                writer.println(INDIVIDUAL_EXISTS_PREAMBLE + Code.encode(true));
+                previousIndividuals[i].printIndividual(state, writer);
+                }
+
+        super.printSubpopulation(state, writer);
+        }
+    
+    DoubleVectorIndividual possiblyReadIndividual(final EvolutionState state, final LineNumberReader reader) throws IOException
+        {
+        if (Code.readBooleanWithPreamble(INDIVIDUAL_EXISTS_PREAMBLE, state, reader))
+            return (DoubleVectorIndividual)species.newIndividual(state, reader);
+        else return null;
+        }
+    
+    /** Overridden to include the global best, neighborhood bests, personal bests, and previous individuals in the stream.
+        The neighborhood size, clamp range, and initial velocity scale are not included -- it's assumed you're using the
+        same values for them on reading, or understand that the values are revised. */
+    public void readSubpopulation(final EvolutionState state, 
+        final LineNumberReader reader) throws IOException
+        {
+        // global best
+        Code.checkPreamble(GLOBAL_BEST_PREAMBLE, state, reader);
+        globalBest = possiblyReadIndividual(state, reader);
+        
+        // neighborhoodBests
+        Code.checkPreamble(NEIGHBORHOOD_BEST_PREAMBLE, state, reader);
+        for(int i = 0; i < individuals.length; i++)
+            neighborhoodBests[i] = possiblyReadIndividual(state, reader); 
+            
+        // personalBests
+        Code.checkPreamble(PERSONAL_BEST_PREAMBLE, state, reader);
+        for(int i = 0; i < individuals.length; i++)
+            personalBests[i] = possiblyReadIndividual(state, reader); 
+
+        // neighborhoodBests
+        Code.checkPreamble(PREVIOUS_INDIVIDUAL_PREAMBLE, state, reader);
+        for(int i = 0; i < individuals.length; i++)
+            previousIndividuals[i] = possiblyReadIndividual(state, reader); 
+        
+        super.readSubpopulation(state, reader);
+        }
+        
+    /** Overridden to include the global best, neighborhood bests, personal bests, and previous individuals in the stream.
+        The neighborhood size, clamp range, and initial velocity scale are not included -- it's assumed you're using the
+        same values for them on reading, or understand that the values are revised. */
+    public void writeSubpopulation(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        // global best
+        if (globalBest == null) 
+            dataOutput.writeBoolean(false);
+        else
+            {
+            dataOutput.writeBoolean(true);
+            globalBest.writeIndividual(state, dataOutput);
+            }
+        
+        // neighborhoodBests
+        for(int i = 0; i < individuals.length; i++)
+            if (neighborhoodBests[i] == null)
+                dataOutput.writeBoolean(false);
+            else 
+                {
+                dataOutput.writeBoolean(true);
+                neighborhoodBests[i].writeIndividual(state, dataOutput);
+                }
+            
+        // personalBests
+        for(int i = 0; i < individuals.length; i++)
+            if (personalBests[i] == null)
+                dataOutput.writeBoolean(false);
+            else 
+                {
+                dataOutput.writeBoolean(true);
+                personalBests[i].writeIndividual(state, dataOutput);
+                }
+
+        // previous Individuals
+        for(int i = 0; i < individuals.length; i++)
+            if (previousIndividuals[i] == null)
+                dataOutput.writeBoolean(false);
+            else 
+                {
+                dataOutput.writeBoolean(true);
+                previousIndividuals[i].writeIndividual(state, dataOutput);
+                }
+
+        super.writeSubpopulation(state, dataOutput);
+        }
+    
+    /** Overridden to include the global best, neighborhood bests, personal bests, and previous individuals in the stream.
+        The neighborhood size, clamp range, and initial velocity scale are not included -- it's assumed you're using the
+        same values for them on reading, or understand that the values are revised. */
+    public void readSubpopulation(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        // global best
+        globalBest = (dataInput.readBoolean() ? (DoubleVectorIndividual)species.newIndividual(state, dataInput) : null);
+        
+        // neighborhoodBests
+        for(int i = 0; i < individuals.length; i++)
+            neighborhoodBests[i] = (dataInput.readBoolean() ? (DoubleVectorIndividual)species.newIndividual(state, dataInput): null); 
+            
+        // personalBests
+        for(int i = 0; i < individuals.length; i++)
+            personalBests[i] = (dataInput.readBoolean() ? (DoubleVectorIndividual)species.newIndividual(state, dataInput): null); 
+
+        // previous Individuals
+        for(int i = 0; i < individuals.length; i++)
+            previousIndividuals[i] = (dataInput.readBoolean() ? (DoubleVectorIndividual)species.newIndividual(state, dataInput): null); 
+
+        super.readSubpopulation(state, dataInput);
+        }       
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/pso/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/pso/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/pso/README	(revision 6152)
@@ -0,0 +1,4 @@
+This package contains (or will contain) particle swarm optimization code.
+
+NOTE: this package contains bugs (we believe) and is expected to change 
+significantly very soon.  Do not rely on it.
Index: branches/OKBJavaConnector/ECJClient/src/ec/pso/pso.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/pso/pso.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/pso/pso.params	(revision 6152)
@@ -0,0 +1,59 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../ec.params
+
+eval.problem = ec.app.ecsuite.ECSuite
+eval.problem.type = rosenbrock
+#eval.problem.type = rastrigin
+#eval.problem.type = griewangk
+#eval.problem.type = booth
+
+#
+# optionally your type could be: rosenbrock, sphere, step, noisy-quartic, 
+# or kdj-f1, kdj-f2, kdj-f3, or kdj-f4		(the kdj-foo names
+# are just aliases for other problems, useful for people who might
+# know them as specific problems in the DeJong test suite)
+#
+
+seed.0 = 						time
+
+state = 						ec.simple.SimpleEvolutionState
+init = 							ec.simple.SimpleInitializer
+finish = 	        				ec.simple.SimpleFinisher
+exch = 							ec.simple.SimpleExchanger
+breed =							ec.pso.PSOBreeder
+eval =							ec.simple.SimpleEvaluator
+stat =							ec.simple.SimpleStatistics
+generations =						200
+quit-on-run-complete =					true
+pop = 							ec.Population
+pop.subpops =						1
+pop.subpop.0 = 						ec.pso.PSOSubpopulation
+pop.subpop.0.duplicate-retries =			2
+pop.subpop.0.species =                  		ec.vector.FloatVectorSpecies
+pop.subpop.0.species.fitness 	= 			ec.simple.SimpleFitness
+pop.subpop.0.species.pipe = 				ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0 = 			ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0 = 		ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1 = 		same
+
+pop.subpop.0.species.ind =				ec.vector.DoubleVectorIndividual
+
+# you can change these to whatever tickles your fancy
+pop.subpop.0.species.min-gene =				-5.12
+pop.subpop.0.species.max-gene =				5.12
+pop.subpop.0.species.genome-size = 			2
+
+select.tournament.size = 				2
+pop.subpop.0.species.mutation-prob = 			0.005
+pop.subpop.0.species.crossover-type = 			one
+
+pop.subpop.0.size =					50
+pop.subpop.0.neighborhood-size = 			20
+pop.subpop.0.clamp = 					false
+pop.subpop.0.initial-velocity-scale = 			1.0
+pop.subpop.0.velocity-multiplier = 			1.5
+
+stat.file						$out.stat
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/README	(revision 6152)
@@ -0,0 +1,54 @@
+This package contains classes for representations of the form of arbitrary
+collections of objects.  One common use of such collections would be as
+bags of "rules", hence the name.  However there's no reason you couldn't use
+any kind of object here.  Also don't be put off by the name "ruleset" -- it's
+not a set of rules, it's a collection (a bag, a multiset) of objects, that is,
+there's no reason the object can't appear more than one time.
+
+The package is very straightforward.  A RuleIndividual contains a fixed-length
+array of RuleSets.  Each RuleSet is an arbitrary-length array of Rules.
+A Rule is the superclass of your basic object.
+
+RuleIndividuals must belong to RuleSpecies (or a subclass), which does trivial
+checks.  Various RuleSets are associated with a RuleSetConstraints object
+in which they can store common information.  Presently RuleSetConstraints
+specify:
+
+	- the minimum number of rules allowed in the RuleSet upon initialization
+	- the maximum number of rules allowed in the RuleSet upon initialization
+or
+	- a distribution from which the number of rules is drawn
+
+Additionally:
+
+	- The probability that new rules will be added upon mutation
+	- The probability that new rules will be deleted upon mutation
+	- The probability the rules will be randomized in order upon mutation
+
+You're welcome to modify this as you see fit of course.  Rules are likewise
+associated with RuleConstraints in which they can store common information
+(presently nothing is stored).
+
+To set up the constraints objects, the rule package requires that your
+initializer be a subclass of RuleInitializer.
+
+The 'breed' directory contains two breeding pipelines which might be of use.
+RuleCrossover trades rules among rulesets using the following algorithm:
+
+	For i from 1 to the number of rulesets
+		r1 = ruleset i in individual A
+		r2 = ruleset i in individual B
+		For each rule in r1
+			With a given probability,
+				mark that rule to go to r2
+		For each rule in r2
+			With a given probability,
+				mark that rule to go to r1
+		Exchange marked rules between r1 and r2
+
+You specify the rule exchange probability.  The RuleMutation operator simply
+calls mutateRules() on all the rulesets.  The default mutateRules() function
+first calls mutate() on al the rules in the ruleset.  It then deletes rules from
+the ruleset with a certain probability.  It then adds new rules to the ruleset
+with a certain probability.  Finally it randomizes the rule order of the ruleset
+with a certain probability.
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/Rule.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/Rule.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/Rule.java	(revision 6152)
@@ -0,0 +1,251 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * Rule.java
+ * 
+ * Created: Tue Feb 20 13:19:00 2001
+ * By: Liviu Panait and Sean Luke
+ */
+
+/**
+ * Rule is an abstract class for describing rules. It is abstract
+ * because it is supposed to be extended by different classes
+ * modelling different kinds of rules.
+ * It provides the reset abstract method for randomizing the individual. 
+ * It also provides the mutate function for mutating an individual rule
+ * It also provides the clone function for cloning the rule.
+ *
+ * <p>You will need to implement some kind of artificial ordering between
+ * rules in a ruleset using the Comparable interface,
+ * so the ruleset can be sorted in such a way that it can be compared with
+ * another ruleset for equality.  You should also implement hashCode
+ * and equals 
+ * in such a way that they aren't based on pointer information, but on actual
+ * internal features. 
+ *
+ * <p>Every rule points to a RuleConstraints which handles information that
+ * Rule shares with all the other Rules in a RuleSet.
+
+ * <p>In addition to serialization for checkpointing, Rules may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeRule(...,DataOutput)/readRule(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives a Rule in binary.  It is the most efficient approach to sending
+ * Rules over networks, etc.  The default versions of writeRule/readRule throw errors.
+ * You don't need to implement them if you don't plan on using read/writeRule.
+ *
+ * <li><b>printRule(...,PrintWriter)/readRule(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives a Rule in text encoded such that the Rule is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readRule</b>
+ * reads in a line, then calls <b>readRuleFromString</b> on that line.
+ * You are responsible for implementing readRuleFromString: the Code class is there to help you.
+ * The default version throws an error if called.
+ * <b>printRule</b> calls <b>printRuleToString<b>
+ * and printlns the resultant string. You are responsible for implementing the printRuleToString method in such
+ * a way that readRuleFromString can read back in the Rule println'd with printRuleToString.  The default form
+ * of printRuleToString() simply calls <b>toString()</b> 
+ * by default.  You might override <b>printRuleToString()</b> to provide better information.   You are not required to implement these methods, but without
+ * them you will not be able to write Rules to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printRuleForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints a Rule in a fashion intended for human consumption only.
+ * <b>printRuleForHumans</b> calls <b>printRuleToStringForHumans()<b> 
+ * and printlns the resultant string.  The default form of this method just returns the value of
+ * <b>toString()</b>. You may wish to override this to provide more information instead. 
+ * You should handle one of these methods properly
+ * to ensure Rules can be printed by ECJ.
+ * </ul>
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>constraints</tt><br>
+ <font size=-1>string</font></td>
+ <td valign=top>(name of the rule constraint)</td></tr>
+ </table>
+ 
+ <p><b>Default Base</b><br>
+ rule.rule
+
+
+ * @author Liviu Panait and Sean luke
+ * @version 1.0 
+ */
+public abstract class Rule implements Prototype, Comparable
+    {
+    public static final String P_RULE = "rule";
+    public static final String P_CONSTRAINTS = "constraints";
+    /**
+       An index to a RuleConstraints
+    */
+    public byte constraints;
+
+    /* Returns the Rule's constraints.  A good JIT compiler should inline this. */
+    public final RuleConstraints constraints(final RuleInitializer initializer) 
+        { 
+        return initializer.ruleConstraints[constraints]; 
+        }
+
+    /** Rulerates a hash code for this rule -- the rule for this is that the hash code
+        must be the same for two rules that are equal to each other genetically. */
+    public abstract int hashCode();
+    
+    /** Unlike the standard form for Java, this function should return true if this
+        rule is "genetically identical" to the other rule.  The default calls compareTo() */
+    public boolean equals( final Object other )
+        {
+        return compareTo(other) == 0;
+        }
+
+    /**
+       The reset method randomly reinitializes the rule.
+    */
+    public abstract void reset(final EvolutionState state, final int thread);
+
+    /**
+       Mutate the rule.  The default form just resets the rule.
+    */
+    public void mutate(final EvolutionState state, final int thread)
+        {
+        reset(state,thread);
+        }
+
+    /**
+       Nice printing.  The default form simply calls printRuleToStringForHumans and prints the result,
+       but you might want to override this.
+    */
+    public void printRuleForHumans( final EvolutionState state, final int log )
+        { printRuleForHumans(state, log, Output.V_VERBOSE); }
+                
+    /**
+       Nice printing.  The default form simply calls printRuleToStringForHumans and prints the result,
+       but you might want to override this.
+       @deprecated Verbosity no longer has an effect
+    */
+    public void printRuleForHumans( final EvolutionState state, final int log, final int verbosity )
+        { state.output.println(printRuleToStringForHumans(),log);}
+
+    /** Nice printing to a string. The default form calls toString().  */
+    public String printRuleToStringForHumans()
+        { return toString(); }
+        
+    /** Prints the rule to a string in a fashion readable by readRuleFromString.
+        The default form calls printRuleToString().
+        @deprecated */
+    public String printRuleToString(final EvolutionState state)
+        { return printRuleToString(); }
+        
+    /** Prints the rule to a string in a fashion readable by readRuleFromString.
+        The default form simply calls toString() -- you should just override toString() 
+        if you don't need the EvolutionState. */
+    public String printRuleToString()
+        { return toString(); }
+        
+
+    /** Reads a rule from a string, which may contain a final '\n'.
+        Override this method.  The default form generates an error. */
+    public void readRuleFromString(final String string, final EvolutionState state)
+        { state.output.error("readRuleFromString(string,state) unimplemented in " + this.getClass()); }
+
+    /**
+       Prints the rule in a way that can be read by readRule().  The default form simply
+       calls printRuleToString(state).   Override this rule to do custom writing to the log,
+       or just override printRuleToString(...), which is probably easier to do.
+    */
+    public void printRule( final EvolutionState state, final int log )
+        { printRule(state, log, Output.V_VERBOSE); }
+
+    /**
+       Prints the rule in a way that can be read by readRule().  The default form simply
+       calls printRuleToString(state).   Override this rule to do custom writing to the log,
+       or just override printRuleToString(...), which is probably easier to do.
+       @deprecated Verbosity no longer has an effect
+    */
+    public void printRule( final EvolutionState state, final int log, final int verbosity )
+        { state.output.println(printRuleToString(state),log); }
+
+    /**
+       Prints the rule in a way that can be read by readRule().  The default form simply
+       calls printRuleToString(state).   Override this rule to do custom writing,
+       or just override printRuleToString(...), which is probably easier to do.
+    */
+    public void printRule( final EvolutionState state, final PrintWriter writer )
+        { writer.println(printRuleToString(state)); }
+
+    /**
+       Reads a rule printed by printRule(...).  The default form simply reads a line into
+       a string, and then calls readRuleFromString() on that line.  Override this rule to do
+       custom reading, or just override readRuleFromString(...), which is probably easier to do.
+    */
+    public void readRule(final EvolutionState state,
+        final LineNumberReader reader)
+        throws IOException
+        { readRuleFromString(reader.readLine(),state); }
+
+
+    /** Override this if you need to write rules out to a binary stream */
+    public void writeRule(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        state.output.fatal("writeRule(EvolutionState, DataOutput) not implemented in " + this.getClass());
+        }
+
+    /** Override this if you need to read rules in from a binary stream */
+    public void readRule(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        state.output.fatal("readRule(EvolutionState, DataInput) not implemented in " + this.getClass());
+        }
+
+
+    public Parameter defaultBase()
+        {
+        return RuleDefaults.base().push(P_RULE);
+        }
+
+    public Object clone()
+        {
+        try { return super.clone(); }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+
+
+    public void setup(EvolutionState state, Parameter base)
+        {
+        String constraintname = state.parameters.getString(
+            base.push( P_CONSTRAINTS ),defaultBase().push(P_CONSTRAINTS));
+        if (constraintname == null)
+            state.output.fatal("No RuleConstraints name given",
+                base.push( P_CONSTRAINTS ),defaultBase().push(P_CONSTRAINTS));
+
+        constraints = RuleConstraints.constraintsFor(constraintname,state).constraintNumber;
+        state.output.exitIfErrors();
+        }
+    
+    /** This function replaces the old gt and lt functions that Rule used to require
+        as it implemented the SortComparator interface.  If you had implemented those
+        old functions, you can simply implement this function as:
+        
+        <tt><pre>
+        public abstract int compareTo(Object o)
+        {
+        if (gt(this,o)) return 1;
+        if (lt(this,o)) return -1;
+        return 0;
+        }
+        </pre></tt>
+    */
+    public abstract int compareTo(Object o);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleConstraints.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleConstraints.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleConstraints.java	(revision 6152)
@@ -0,0 +1,80 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * RuleConstraints.java
+ * 
+ * Created: Tue Feb 20 13:16:00 2001
+ * By: Liviu Panait and Sean Luke
+ */
+
+/**
+ * RuleConstraints is a class for constraints applicable to rules.
+ * You can subclass this to add additional constraints information
+ * for different kinds of rules.
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 1.0 
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of rule constraints)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of rule constraint <i>n</i>)</td></tr>
+ </table>
+
+*/
+public class RuleConstraints implements Clique
+    {
+//    public static final int SIZE_OF_BYTE = 256;
+    public final static String P_NAME = "name";
+//    public final static String P_SIZE = "size";
+
+    /** The byte value of the constraints -- we can only have 256 of them */
+    public byte constraintNumber;
+
+    /** The name of the RuleConstraints object */
+    public String name;
+
+    /** Converting the rule to a string ( the name ) */
+    public String toString() { return name; }
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // What's my name?
+        name = state.parameters.getString(base.push(P_NAME),null);
+        if (name==null)
+            state.output.fatal("No name was given for this Rule Constraints.",
+                base.push(P_NAME));
+
+        // Register me
+        RuleConstraints old_constraints = (RuleConstraints)(((RuleInitializer)state.initializer).ruleConstraintRepository.put(name,this));
+        if (old_constraints != null)
+            state.output.fatal("The rule constraints \"" + name + "\" has been defined multiple times.", base.push(P_NAME));
+        }
+
+    /** You must guarantee that after calling constraintsFor(...) one or
+        several times, you call state.output.exitIfErrors() once. */
+
+    public static RuleConstraints constraintsFor(final String constraintsName,
+        final EvolutionState state)
+        {
+        RuleConstraints myConstraints = (RuleConstraints)(((RuleInitializer)state.initializer).ruleConstraintRepository.get(constraintsName));
+        if (myConstraints==null)
+            state.output.error("The rule constraints \"" + constraintsName + "\" could not be found.");
+        return myConstraints;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleDefaults.java	(revision 6152)
@@ -0,0 +1,37 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * RuleDefaults.java
+ * 
+ * Created: Tue Feb 20 1258:00 2001
+ * By: Liviu Panait
+ */
+
+/**
+ * A static class that returns the base for "default values" which rule-style
+ * operators use, rather than making the user specify them all on a per-
+ * species basis.
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public final class RuleDefaults implements DefaultsForm
+    {
+    public static final String P_RULE = "rule";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_RULE);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleIndividual.java	(revision 6152)
@@ -0,0 +1,269 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * RuleIndividual.java
+ * 
+ * Created: Tue May 29 18:20:20 EDT 2001
+ * By: Sean Luke
+ */
+
+/**
+ * RuleIndividual is an Individual with an array of RuleSets, each of which
+ * is a set of Rules.  RuleIndividuals belong to some subclass of RuleSpecies
+ * (or just RuleSpecies itself).
+ *
+ * <p>RuleIndividuals really have basically one parameter: the number
+ * of RuleSets to use.  This is determined by the <tt>num-rulesets</tt>
+ * parameter.
+
+ * <P><b>From ec.Individual:</b>  
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b>reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString<b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans<b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the Rulesets.  If you add instance variables to
+ * a RuleIndividual or subclass, you'll need to read/write those variables as well.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>num-rulesets</tt><br>
+ <font size=-1>int >= 1</font></td>
+ <td valign=top>(number of rulesets used)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>ruleset</tt>.<i>n</i><br>
+ <font size=-1>Classname, subclass of or = ec.rule.RuleSet</font></td>
+ <td valign=top>(class of ruleset <i>n</i>)</td></tr>
+ </table>
+ 
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>ruleset</tt>.<i>n</i><br>
+ <td>RuleSet <i>n</i></td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ rule.individual
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+public class RuleIndividual extends Individual
+    {
+    public static final String P_RULESET = "ruleset";
+    public static final String P_NUMRULESETS = "num-rulesets";
+    
+    /** The individual's rulesets. */
+    public RuleSet[] rulesets;
+    
+    public Parameter defaultBase()
+        {
+        return RuleDefaults.base().push(P_INDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        RuleIndividual myobj = (RuleIndividual) (super.clone());   
+        myobj.rulesets = new RuleSet[rulesets.length];
+        for(int x=0;x<rulesets.length;x++) 
+            myobj.rulesets[x] = (RuleSet)(rulesets[x].clone());
+        return myobj;
+        } 
+
+    /** Called by pipelines before they've modified the individual and
+        it might need to be "fixed"  -- basically a hook for you to override.
+        By default, calls validateRules on each ruleset. */
+    public void preprocessIndividual(final EvolutionState state, final int thread)
+        {
+        for (int x=0;x<rulesets.length;x++)
+            rulesets[x].preprocessRules(state,thread);
+        }
+
+    /** Called by pipelines after they've modified the individual and
+        it might need to be "fixed"  -- basically a hook for you to override.
+        By default, calls validateRules on each ruleset. */
+    public void postprocessIndividual(final EvolutionState state, final int thread)
+        {
+        for (int x=0;x<rulesets.length;x++)
+            rulesets[x].postprocessRules(state,thread);
+        }
+        
+    public boolean equals(Object ind)
+        {
+        // My loose definition: ind must be a 
+        if (!getClass().equals(ind.getClass()))  // not the same class, I'm conservative that way
+            return false;
+
+        RuleIndividual other = (RuleIndividual)ind;
+        if (rulesets.length != other.rulesets.length) return false;
+        for(int x=0;x<rulesets.length;x++)
+            if (!rulesets[x].equals(other.rulesets[x])) return false;
+        return true;
+        }
+
+    public int hashCode()
+        {
+        int hash = this.getClass().hashCode();
+        for(int x=0;x<rulesets.length;x++)
+            // rotate hash and XOR
+            hash =
+                (hash << 1 | hash >>> 31 ) ^ rulesets[x].hashCode();
+        return hash;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+
+        // I'm the top-level setup, I guess
+        int numrulesets = state.parameters.getInt(
+            base.push(P_NUMRULESETS), defaultBase().push(P_NUMRULESETS),
+            1);  // need at least 1 ruleset!
+        if (numrulesets == 0)
+            state.output.fatal("RuleIndividual needs at least one RuleSet!",
+                base.push(P_NUMRULESETS), defaultBase().push(P_NUMRULESETS));
+
+        rulesets  = new RuleSet[numrulesets];
+
+        for(int x=0;x<numrulesets;x++)
+            {
+            rulesets[x] = (RuleSet)(state.parameters.getInstanceForParameterEq(
+                    base.push(P_RULESET).push(""+x),defaultBase().push(P_RULESET),
+                    RuleSet.class));
+            rulesets[x].setup(state,base.push(P_RULESET).push(""+x));
+            }
+        }
+
+    public void printIndividualForHumans(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(EVALUATED_PREAMBLE + (evaluated ? "true" : "false"), log);
+        fitness.printFitnessForHumans(state,log);
+        for(int x=0;x<rulesets.length;x++)
+            {
+            state.output.println("Ruleset " + x + ":", log);
+            rulesets[x].printRuleSetForHumans(state, log);
+            }
+        }
+
+    public void printIndividual(final EvolutionState state,
+        final int log)
+        {
+        state.output.println(EVALUATED_PREAMBLE + Code.encode(evaluated), log);
+        fitness.printFitness(state, log);
+        for(int x=0;x<rulesets.length;x++)
+            {
+            state.output.println("Ruleset " + x + ":", log);
+            rulesets[x].printRuleSet(state,log);
+            }
+        }
+
+    /** Overridden for the RuleIndividual genotype, writing each ruleset in turn. */
+    public void printIndividual(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println(EVALUATED_PREAMBLE + Code.encode(evaluated));
+        fitness.printFitness(state,writer);
+        for(int x=0;x<rulesets.length;x++)
+            {
+            writer.println("Ruleset " + x + ":");
+            rulesets[x].printRuleSet(state,writer);
+            }
+        }
+    
+    /** Overridden for the RuleIndividual genotype, writing each ruleset in turn. */
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(rulesets.length);
+        for(int x=0;x<rulesets.length;x++)
+            rulesets[x].writeRuleSet(state,dataOutput);
+        }
+
+    /** Overridden for the RuleIndividual genotype. */
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (rulesets==null || rulesets.length != len)
+            state.output.fatal("Number of RuleSets differ in RuleIndividual when reading from readGenotype(EvolutionState, DataInput).");
+        for(int x=0;x<rulesets.length;x++)
+            rulesets[x].readRuleSet(state,dataInput);
+        }
+
+
+    /** Overridden for the RuleIndividual genotype. */
+    public void parseGenotype(final EvolutionState state, 
+        final LineNumberReader reader)
+        throws IOException
+        {
+        // read my ruleset
+        for(int x=0;x<rulesets.length;x++)
+            {
+            reader.readLine();  // throw it away -- it's the ruleset# indicator
+            rulesets[x].readRuleSet(state,reader);
+            }
+        }
+
+    public long size() 
+        { 
+        long size=0;
+        for(int x=0;x<rulesets.length;x++) 
+            size+= rulesets[x].numRules();
+        return size;
+        }
+    
+    public void reset(EvolutionState state, int thread)
+        {
+        for(int x=0;x<rulesets.length;x++) 
+            rulesets[x].reset(state,thread);
+        }
+
+    /** Mutates the Individual.  The default implementation simply calls mutate(...) on each of
+        the RuleSets. */
+    public void mutate(EvolutionState state, int thread)
+        {
+        for(int x=0;x<rulesets.length;x++) 
+            rulesets[x].mutate(state,thread);
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleInitializer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleInitializer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleInitializer.java	(revision 6152)
@@ -0,0 +1,145 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import ec.simple.SimpleInitializer;
+import ec.util.Parameter;
+import ec.EvolutionState;
+
+/* 
+ * RuleInitializer.java
+ * 
+ * Created: Fri Sep 14 14:00:02 2001
+ * By: Liviu Panait
+ *
+ */
+ 
+/** A SimpleInitializer subclass designed to be used with rules.  Basically,
+    the RuleInitializer sets up the RuleConstraints and RuleSetConstraints cliques
+    at setup() time, and does nothing else different from SimpleInitializer. 
+    The RuleInitializer also specifies the parameter bases for the RuleSetConstraints
+    and RuleConstraints objects.  
+ 
+    <p><b>Parameter bases</b><br>
+    <table>
+    <tr><td valign=top><tt>rule.rsc</tt></td>
+    <td>RuleSetConstraints</td></tr>
+    <tr><td valign=top><tt>rule.rc</tt></td>
+    <td>RuleConstraints</td></tr>
+    </table>
+*/
+
+public class RuleInitializer extends SimpleInitializer
+    {
+    // used just here, so far as I know :-)
+    public static final int SIZE_OF_BYTE = 256;
+    public final static String P_RULESETCONSTRAINTS = "rsc";
+    public final static String P_RULECONSTRAINTS = "rc";
+    public final static String P_SIZE = "size";
+
+    public Hashtable ruleConstraintRepository;
+    public RuleConstraints[] ruleConstraints;
+    public byte numRuleConstraints;
+    
+    public Hashtable ruleSetConstraintRepository;
+    public RuleSetConstraints[] ruleSetConstraints;
+    public byte numRuleSetConstraints;
+    
+    /** Sets up the RuleConstraints and RuleSetConstraints cliques. */
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        ruleConstraintRepository = new Hashtable();
+        ruleConstraints = new RuleConstraints[SIZE_OF_BYTE];
+        numRuleConstraints = 0;
+        
+        ruleSetConstraintRepository = new Hashtable();
+        ruleSetConstraints = new RuleSetConstraints[SIZE_OF_BYTE];
+        numRuleSetConstraints = 0;
+        
+        // Now let's load our constraints and function sets also.
+        // This is done in a very specific order, don't change it or things
+        // will break.
+        setupConstraints(
+            state, RuleDefaults.base().push( P_RULECONSTRAINTS ) );
+        setupRuleSetConstraints(
+            state, RuleDefaults.base().push( P_RULESETCONSTRAINTS ) );
+        }
+
+    /** Sets up all the RuleConstraints, loading them from the parameter
+        file.  This must be called before anything is called which refers
+        to a type by name. */
+    
+    public void setupConstraints(final EvolutionState state,
+        final Parameter base)
+        {
+        state.output.message("Processing Rule Constraints");
+        
+        // How many RuleConstraints do we have?
+        int x = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (x<=0) 
+            state.output.fatal("The number of rule constraints must be at least 1.",base.push(P_SIZE));
+        
+        // Load our constraints
+        for (int y=0;y<x;y++)
+            {
+            RuleConstraints c;
+            // Figure the constraints class
+            if (state.parameters.exists(base.push(""+y), null))
+                c = (RuleConstraints)(state.parameters.getInstanceForParameterEq(
+                        base.push(""+y),null,RuleConstraints.class));
+            else
+                {
+                state.output.message("No Rule Constraints specified, assuming the default class: ec.rule.RuleConstraints for " + base.push(""+y));
+                c = new RuleConstraints();
+                }
+            c.setup(state,base.push(""+y));
+            }
+        
+        // set our constraints array up
+        Enumeration e = ruleConstraintRepository.elements();
+        while(e.hasMoreElements())
+            {
+            RuleConstraints c = (RuleConstraints)(e.nextElement());
+            c.constraintNumber = numRuleConstraints;
+            ruleConstraints[numRuleConstraints] = c;
+            numRuleConstraints++;
+            }
+        }
+    
+    public void setupRuleSetConstraints(final EvolutionState state,
+        final Parameter base)
+        {
+        state.output.message("Processing Ruleset Constraints");
+        // How many RuleSetConstraints do we have?
+        int x = state.parameters.getInt(base.push(P_SIZE),null,1);
+        if (x<=0) 
+            state.output.fatal("The number of RuleSetConstraints must be at least 1.",base.push(P_SIZE));
+        
+        // Load our RuleSetConstraints
+        for (int y=0;y<x;y++)
+            {
+            RuleSetConstraints c;
+            // Figure the RuleSetConstraints class
+            if (state.parameters.exists(base.push(""+y), null))
+                c = (RuleSetConstraints)(state.parameters.getInstanceForParameterEq(
+                        base.push(""+y),null,RuleSetConstraints.class));
+            else
+                {
+                state.output.message("No RuleSetConstraints specified, assuming the default class: ec.gp.RuleSetConstraints for " + base.push(""+y));
+                c = new RuleSetConstraints();
+                }
+            c.setup(state,base.push(""+y));
+            ruleSetConstraints[y] = c;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSet.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSet.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSet.java	(revision 6152)
@@ -0,0 +1,521 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * RuleSet.java
+ * 
+ * Created: Tue Feb 20 13:19:00 2001
+ * By: Liviu Panait and Sean Luke
+ */
+
+/**
+ * RuleSet is a set of Rules, implemented straightforwardly as an arbitrary-length array of Rules.
+ * A RuleIndividual is simply a list of RuleSets.  Most typically, a RuleIndividual contains a
+ * single RuleSet, containing a variety of Rules.
+ * RuleSets contain many useful subsetting and modification functions which you can use
+ * in breeding operators which modify RuleSets and Rules.
+ *
+ * <p> Besides the Rules themselves, the only thing else a RuleSet contains is a pointer to a
+ * corresponding RuleSetConstraints object, which holds all of its modification parameters.
+ * See RuleSetConstraints for a description of these parameters.
+
+ * <p>In addition to serialization for checkpointing, RuleSets may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeRuleSet(...,DataOutput)/readRuleSet(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives a RuleSet in binary.  It is the most efficient approach to sending
+ * RuleSets over networks, etc.  The default versions of writeRuleSet/readRuleSet reads/writes out the number
+ * of rules, then calls read/writeRule(...) on each Rule.  Override this if you need more functionality.
+ *
+ * <li><b>printRuleSet(...,PrintWriter)/readRuleSet(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives a RuleSet in text encoded such that the RuleSet is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readRuleSet</b>
+ * reads in the number of rules, then calls readRule(...) on each new Rule.  <b>printRuleSet</b> writes
+ * out the number of rules, then calls printrule(...) on each new Rule.  Again, override this if you need more
+ * functionality.
+ * 
+ * <li><b>printRuleSetForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints a RuleSet in a fashion intended for human consumption only.
+ * <b>printRuleSetForHumans</b> prints out the number of rules, then calles <b>printRuleForHumans</b>
+ * on each Rule in turn.  You may wish to override this to provide more information instead. 
+ * You should handle one of these methods properly
+ * to ensure RuleSets can be printed by ECJ.
+ * </ul>
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>constraints</tt><br>
+ <font size=-1>string</font></td>
+ <td valign=top>(name of the rule set constraints)</td></tr>
+ </table>
+ 
+ <p><b>Default Base</b><br>
+ rule.ruleset
+
+
+ * @author Liviu Panait and Sean Luke
+ * @version 1.0 
+ */
+public class RuleSet implements Prototype
+    {
+
+    /**
+       The message to appear when printing the rule set
+    */
+    public final static String N_RULES = "Num: ";
+    public final static String P_RULESET = "ruleset";
+    /**
+       The constraint for the rule set
+    */
+    public static final String P_CONSTRAINTS = "constraints";
+    /**
+       An index to a RuleSetConstraints
+    */
+    public byte constraints;
+
+    /* Returns the RuleSet's constraints.  A good JIT compiler should inline this. */
+    public final RuleSetConstraints constraints(RuleInitializer initializer) 
+        {
+        return initializer.ruleSetConstraints[constraints];
+        }
+
+    /**
+       The rules in the rule set
+    */
+    public Rule[] rules = new Rule[0];
+    /**
+       How many rules are there used in the rules array
+    */
+    public int numRules = 0;
+
+
+    public Object clone()
+        {
+        try
+            {
+            RuleSet newRuleSet = (RuleSet)(super.clone());
+            // copy the rules over
+            if( rules != null )
+                {
+                newRuleSet.rules = (Rule[])(rules.clone());
+                }
+            else
+                {
+                newRuleSet.rules = null;
+                }
+            for(int x=0;x<numRules;x++)
+                newRuleSet.rules[x] = (Rule)(rules[x].clone());
+            return newRuleSet;
+            }
+        catch (CloneNotSupportedException e)
+            { throw new InternalError(); } // never happens
+        }
+
+
+
+    /**
+       How many rules are there used in the rules array
+    */
+    
+    public int numRules() { return numRules; }
+    /**
+       A reset method for randomly reinitializing the RuleSet
+    */
+    public void reset(final EvolutionState state, final int thread)
+        {
+        // reinitialize the array of rules
+        RuleInitializer initializer = ((RuleInitializer)state.initializer);
+        numRules = constraints(initializer).numRulesForReset(this,state,thread);
+
+        rules = new Rule[ numRules ];
+
+        for( int i = 0 ; i < rules.length ; i++ )
+            {
+            rules[i] = (Rule)(constraints(initializer).rulePrototype.clone());
+            rules[i].reset(state,thread);
+            }
+        }
+
+    /**
+       Mutates rules in the RuleSet independently with the given probability.
+    */
+    public void mutate( final EvolutionState state, final int thread)
+        {
+        RuleInitializer initializer = ((RuleInitializer)state.initializer);
+        
+        for( int i = 0 ; i < numRules ; i++ )
+            {
+            rules[i].mutate(state,thread);
+            }
+        while( state.random[thread].nextBoolean( constraints(initializer).p_del ) && numRules > constraints(initializer).minSize )
+            {
+            removeRandomRule( state, thread );
+            }
+        while( state.random[thread].nextBoolean( constraints(initializer).p_add ) && numRules < constraints(initializer).maxSize )
+            {
+            addRandomRule( state, thread );
+            }
+        if( state.random[thread].nextBoolean( constraints(initializer).p_randorder ) )
+            {
+            randomizeRulesOrder( state, thread );
+            }
+        }
+        
+    /**
+       Should be called by pipelines to "fix up" the rulesets before they have been
+       mutated or crossed over.  Override this method to do so.
+    */
+    public void preprocessRules(final EvolutionState state, final int thread)
+        {
+        }
+
+    /**
+       Should be called by pipelines to "fix up" the rulesets after they have been
+       mutated or crossed over.  Override this method to do so.
+    */
+    public void postprocessRules(final EvolutionState state, final int thread)
+        {
+        }
+        
+    /**
+       Randomizes the order of the rules in the rule set. It is helpful when the
+       order of rule is important for the conflict resolution.
+    */
+    public void randomizeRulesOrder(final EvolutionState state, final int thread)
+        {
+        Rule temp;
+        for( int i = numRules-1 ; i > 0 ; i-- )
+            {
+            int j = state.random[thread].nextInt( i+1 );
+            temp = rules[i];
+            rules[i] = rules[j];
+            rules[j] = temp;
+            }
+        }
+
+    /**
+       Add a random rule to the rule set
+    */
+    public void addRandomRule(final EvolutionState state, final int thread)
+        {
+        Rule newRule = (Rule)(constraints(((RuleInitializer)state.initializer)).rulePrototype.clone());
+        newRule.reset(state,thread);
+        addRule(newRule);
+        }
+
+    /**
+       Add a rule directly to the rule set.  Does not copy the rule.
+    */
+    public void addRule( Rule rule )
+        {
+        if( ( rules == null && numRules == 0 ) || ( numRules == rules.length ) )
+            {
+            Rule[] tempRules;
+            if( rules == null )
+                {
+                tempRules = new Rule[2];
+                }
+            else
+                {
+                tempRules = new Rule[ (rules.length + 1 ) * 2 ];
+                }
+            if( rules != null )
+                System.arraycopy( rules, 0, tempRules, 0, rules.length );
+            rules = tempRules;
+            }
+
+        // add the rule and increase the counter
+        rules[ numRules++ ] = rule;
+        }
+
+    /**
+       Removes a rule from the rule set and returns it.  If index is out of bounds, then
+       this method returns null.  The rules are shifted down --- thus this is O(n).
+    */
+    public Rule removeRule( int index )
+        {
+        if (index >= numRules || index < 0 ) return null;
+        Rule myrule = rules[index];
+        System.arraycopy(rules, index + 1, rules, index, numRules - index + 1);
+                
+        /*
+        // swap to the top
+        Rule myrule = rules[index];
+        rules[index] = rules[numRules-1];
+        */
+
+        numRules--;
+        return myrule; 
+        }
+
+    /**
+       Removes a randomly-chosen rule from the rule set and returns it.  If there are no rules to remove,
+       this method returns null.
+    */
+    public Rule removeRandomRule( final EvolutionState state, final int thread )
+        {
+        if (numRules <= 0) return null;
+        else return removeRule(state.random[thread].nextInt(numRules));
+        }
+
+    /**
+       Makes a copy of the rules in another RuleSet and adds the rule copies.
+    */
+    public void join( final RuleSet other )
+        {
+        // if there's not enough place to store the new rules, increase space
+        if( rules.length <= numRules + other.numRules )
+            {
+            Rule[] tempRules = new Rule[ rules.length + other.rules.length ];
+            System.arraycopy( rules, 0, tempRules, 0, numRules );
+            rules = tempRules;
+            }
+        // copy in the new rules
+        System.arraycopy( other.rules, 0, rules, numRules, other.numRules );
+        // clone the rules
+        for(int x=numRules;x<numRules+other.numRules;x++)
+            rules[x] = (Rule)(rules[x].clone());
+        numRules += other.numRules;
+        }
+        
+    /**
+       Clears out existing rules, and loads the rules from the other ruleset without cloning them.
+       Mostly for use if you create temporary rulesets (see for example RuleCrossoverPipeline)
+    */
+    public void copyNoClone( final RuleSet other )
+        {
+        // if there's not enough place to store the new rules, increase space
+        if( rules.length <= other.numRules )
+            {
+            rules = new Rule[ other.numRules ];
+            }
+        // copy in the new rules
+        // System.out.println(other.rules);
+        System.arraycopy( other.rules, 0, rules, 0, other.numRules );
+        numRules = other.numRules;
+        }
+        
+    /**
+       Splits the rule set into n pieces, according to points, which *must* be sorted.
+       The rules in each piece are cloned and added to the equivalent set.  Sets must be already allocated.
+       sets.length must be 1+ points.length.  
+       Comment: This function appends the split rulesets to the existing rulesets already in <i>sets</i>.
+    */
+    public RuleSet[] split( int[] points, RuleSet[] sets )
+        {
+        // Do the first chunk or the whole thing
+        for(int i=0; i < (points.length > 0 ? points[0] : rules.length); i++)
+            sets[0].addRule((Rule)(rules[i].clone()) );
+                
+        if (points.length > 0)
+            {
+            // do the in-between chunks
+            for(int p = 1; p < points.length; p++)
+                for(int i= points[p-1]; i < points[p]; i++)
+                    sets[p].addRule((Rule)(rules[i].clone()) );
+                
+            // do the final chunk
+            for(int i=points[points.length - 1]; i < rules.length; i++)
+                sets[points.length].addRule((Rule)(rules[i].clone()) );
+            }
+        return sets;
+        }
+    
+    /**
+       Splits the rule set into a number of disjoint rule sets, copying the rules and adding
+       them to the sets as appropriate.  Each rule independently
+       throws a die to determine which ruleset it will go into.  Sets must be already allocated.
+       Comment: This function appends the split rulesets to the existing rulesets already in <i>sets</i>.
+    */
+    public RuleSet[] split( final EvolutionState state, final int thread, RuleSet[] sets )
+        {
+        for( int i = 0 ; i < numRules ; i++ )
+            sets[ state.random[ thread ].nextInt( sets.length ) ].addRule(
+                (Rule)(rules[i].clone()) );
+        return sets;
+        }
+    
+    /**
+       Splits the rule set into a two disjoint rule sets, copying the rules and adding
+       them to the sets as appropriate.  The value <i>prob</i> is the probability that an element will
+       land in the first set.  Sets must be already allocated.
+       Comment: This function appends the split rulesets to the existing rulesets already in <i>sets</i>.
+    */
+    public RuleSet[] splitIntoTwo( final EvolutionState state, final int thread, RuleSet[] sets, float prob )
+        {
+        for( int i = 0 ; i < numRules ; i++ )
+            if (state.random[thread].nextBoolean(prob))
+                sets[0].addRule((Rule)(rules[i].clone()) );
+            else
+                sets[1].addRule((Rule)(rules[i].clone()) );
+        return sets;
+        }
+    
+    /**
+       Prints out the rule set in a readable fashion.
+    */
+    public void printRuleSetForHumans(final EvolutionState state, final int log)
+        {
+        printRuleSetForHumans(state, log, Output.V_VERBOSE);
+        }
+                
+    /**
+       Prints out the rule set in a readable fashion.
+       @deprecated Verbosity no longer has an effect
+    */
+    public void printRuleSetForHumans(final EvolutionState state, final int log,
+        final int verbosity)
+        {
+        state.output.println( "Ruleset contains " + numRules + " rules",
+            log );
+        for( int i = 0 ; i < numRules ; i ++ )
+            {
+            state.output.println( "Rule " + i + ":", log );
+            rules[i].printRuleForHumans( state, log );
+            }
+        }
+
+    /**
+       Prints the rule set such that the computer can read it later
+    */
+    public void printRuleSet(final EvolutionState state, final int log)
+        {
+        printRuleSet(state, log, Output.V_VERBOSE);
+        }
+                
+    /**
+       Prints the rule set such that the computer can read it later
+       @deprecated Verbosity no longer has an effect
+    */
+    public void printRuleSet(final EvolutionState state,
+        final int log, final int verbosity)
+        {
+        state.output.println(N_RULES + Code.encode(numRules), log);
+        for( int i = 0 ; i < numRules ; i ++ )
+            rules[i].printRule(state,log);
+        }
+
+    /**
+       Prints the rule set such that the computer can read it later
+    */
+    public void printRuleSet(final EvolutionState state,
+        final PrintWriter writer)
+        {
+        writer.println( N_RULES + Code.encode(numRules) );
+        for( int i = 0 ; i < numRules ; i ++ )
+            rules[i].printRule(state,writer);
+        }
+
+    /**
+       Reads the rule set
+    */
+    public void readRuleSet(final EvolutionState state,
+        final LineNumberReader reader)
+        throws IOException
+        {
+        numRules = Code.readIntegerWithPreamble(N_RULES, state, reader);
+
+        rules = new Rule[ numRules ];
+        for(int x=0;x<numRules;x++)
+            {
+            rules[x] = (Rule)(constraints(((RuleInitializer)state.initializer)).rulePrototype.clone());
+            rules[x].readRule(state,reader);
+            }
+        }
+
+    /** Writes RuleSets out to a binary stream */
+    public void writeRuleSet(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(numRules);
+        for(int x=0;x<numRules;x++)
+            rules[x].writeRule(state,dataOutput);
+        }
+
+    /** Reads RuleSets in from a binary stream */
+    public void readRuleSet(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int ruleCount = dataInput.readInt();
+        if (rules==null || rules.length != ruleCount)
+            rules = new Rule[ruleCount];
+        for(int x=0;x<ruleCount;x++)
+            {
+            rules[x] = (Rule)(constraints((RuleInitializer)state.initializer).rulePrototype.clone());
+            rules[x].readRule(state,dataInput);
+            }
+        }
+
+
+    public Parameter defaultBase()
+        {
+        return RuleDefaults.base().push(P_RULESET);
+        }
+
+    public void setup(EvolutionState state, Parameter base)
+        {        
+        String constraintname = state.parameters.getString(
+            base.push( P_CONSTRAINTS ),defaultBase().push(P_CONSTRAINTS));
+        if (constraintname == null)
+            state.output.fatal("No RuleSetConstraints name given",
+                base.push( P_CONSTRAINTS ),defaultBase().push(P_CONSTRAINTS));
+
+        constraints = RuleSetConstraints.constraintsFor(constraintname,state).constraintNumber;
+        state.output.exitIfErrors();
+        }
+
+    /**
+       The hash code for the rule set.  This isn't a very good hash code,
+       but it has the benefit of not being O(n lg n) -- otherwise, we'd have
+       to do something like sort the rules in the individual first and then
+       do an ordered hash code of some sort, ick.
+    */
+    public int hashCode()
+        {
+        int hash = this.getClass().hashCode();
+        for(int x=0;x<rules.length;x++)
+            if (rules[x] !=null) 
+                hash += rules[x].hashCode();
+        return hash;
+        }
+
+    public boolean equals( final Object _other )
+        {
+        if (!getClass().equals(_other.getClass()))  // not the same class, I'm conservative that way
+            return false;
+            
+        RuleSet other = (RuleSet)_other;
+        if( numRules != other.numRules )
+            return false;  // quick and dirty
+        if (numRules == 0 && other.numRules==0)
+            return true;  // quick and dirty
+            
+        // we need to sort the rulesets.  First, let's clone
+        // the rule arrays
+
+        Rule[] srules = (Rule[])(rules.clone());
+        Rule[] orules = (Rule[])(other.rules.clone());
+
+        java.util.Arrays.sort(srules);
+        java.util.Arrays.sort(orules);
+        
+        // Now march down and see if the rules are the same
+        for(int x=0;x<numRules;x++)
+            if (!(srules[x].equals(orules[x])))
+                return false;
+
+        return true;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSetConstraints.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSetConstraints.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSetConstraints.java	(revision 6152)
@@ -0,0 +1,327 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * RuleSetConstraints.java
+ * 
+ * Created: Tue Feb 20 13:26:00 2001
+ * By: Liviu Panait and Sean Luke
+ */
+
+/**
+ * RuleSetConstraints is an basic class for constraints applicable to rulesets.
+ * There are two categories of parameters associated with this class.  First, there are parameters
+ * which guide the initial number of rules to be created when a ruleset is initialized for
+ * the first time, or totally reset.  Second, there are parameters which indicate how rulesets
+ * are to be mutated under the "default" rule mutation operator.
+ *
+ * <p>First the initialization parameters.  You need to specify a distribution from which
+ * the system will pick random integer values X.  When a ruleset is to be initialized, a
+ * random value X is picked from this distribution, and the ruleset will be created with X initial rules.
+ * You can specify the distribution in one of two ways.  First, you can specify a minimum and maximum
+ * number of rules; the system will then pick an X uniformly from between the min and the max. 
+ * Second, you can specify a full distribution of size probabilities for more control.  For example,
+ * to specify that the system should make individuals with 0 rules 0.1 of the time, 1 rule 0.2 of the time,
+ * and 2 rules 0.7 of the time, you set <i>reset-num-sizes</i> to 3 (for rule sizes up to but not including 3),
+ * and then set  reset-size.0 to 0.1, reset-size.1 to 0.2, and reset-size.2 to 0.7.
+ *
+ * <p>Next the mutation parameters.  The default mutation procedure works as follows.  First, every rule
+ * in the ruleset is mutated.  It is up to the rule to determine by how much or whether it will be mutated
+ * (perhaps by flipping a coin) when its mutate function is called.  Second, the system repeatedly flips
+ * a coin with "p-del" probability of being true, until it comes up false.  The number of times it came up
+ * true is the number of rules to remove from the ruleset; rules to be removed are chosen at random.
+ * Third, the system repeatedly flips
+ * a coin with "p-add" probability of being true, until it comes up false.  The number of times it came up
+ * true is the number of new randomly-generated rules to add to the ruleset; rules are added to the end of the array.
+ * Fourth, with "p-rand-order" probability, the order of rules in the ruleset array is randomized; this last
+ * item might or might not matter to you depending on whether or not your rule interpreter differs depending on rule order.  
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 1.0 
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(number of rule set constraints)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>name</tt><br>
+ <font size=-1>String</font></td>
+ <td valign=top>(name of rule set constraint <i>n</i>)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>reset-min-size</tt><br>
+ <font size=-1>int >= 0 (default=0)</font></td>
+ <td valign=top>(for rule set constraint <i>n</i>, the minimum number of rules that rulesets may contain upon initialization (resetting), see discussion above)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>reset-max-size</tt><br>
+ <font size=-1>int >= <i>base.n</i>.<tt>reset-min-size</tt> (default=0)</font></td>
+ <td valign=top>(for rule set constraint <i>n</i>, the maximum number of rules that rulesets may contain upon initialization (resetting), see discussion above)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>reset-num-sizes</tt><br>
+ <font size=-1>int >= 0</font> (default=unset)</td>
+ <td valign=top>(for rule set constraint <i>n</i>, the number of sizes in the size distribution for initializtion, see discussion above)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>reset-size</tt>.<i>i</i><br>
+ <font size=-1>0.0 <= float <= 1.0</font></td>
+ <td valign=top>(for rule set constraint <i>n</i>, the probability that <i>i</i> will be chosen as the number of rules upon initialization, see discussion above)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>p-add</tt><br>
+ <font size=-1>0.0 <= float <= 1.0</font></td>
+ <td valign=top>(the probability that a new rule will be added, see discussion)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>p-del</tt><br>
+ <font size=-1>0.0 <= float <= 1.0</font></td>
+ <td valign=top>(the probability that a rule will be deleted, see discussion)</td></tr>
+
+ <tr><td valign=top><i>base.n</i>.<tt>p-rand-order</tt><br>
+ <font size=-1>0.0 <= float <= 1.0</font></td>
+ <td valign=top>(the probability that the rules' order will be randomized, see discussion)</td></tr>
+ </table>
+
+*/
+public class RuleSetConstraints implements Clique
+    {
+    /** The size of a byte */
+//    public static final int SIZE_OF_BYTE = 256;
+    public final static String P_NAME = "name";
+    /** num rulesets */
+//    public final static String P_SIZE = "size";
+    public final static String P_RULE = "rule";  // our prototype
+//    public static final int CHECK_BOUNDARY = 8;
+    public static final String P_RESETMINSIZE = "reset-min-size";
+    public static final String P_RESETMAXSIZE = "reset-max-size";
+    public static final String P_NUMSIZES = "reset-num-sizes";
+    public static final String P_RESETSIZE = "reset-size";
+
+    public static final String P_MINSIZE = "min-size";
+    public static final String P_MAXSIZE = "max-size";
+
+    public int minSize;   // the minimum legal size
+    public int maxSize;   // the maximum legal size
+
+    public int resetMinSize;  // the minium possible size -- if unused, it's 0, but 0 is also a valid number, so check sizeDistribution==null
+    public int resetMaxSize;  // the maximum possible size -- if unused, it's 0, but 0 is also a valid number, so check sizeDistribution==null
+    public float[] sizeDistribution;
+
+    // probability of adding a random rule to the rule set
+    public static final String P_ADD_PROB = "p-add";
+    public float p_add;
+
+    // probability of removing a random rule from the rule set
+    public static final String P_DEL_PROB = "p-del";
+    public float p_del;
+
+    // probability of randomizing the rule order in the rule set
+    public static final String P_RAND_ORDER_PROB = "p-rand-order";
+    public float p_randorder;
+
+    /** Assuming that either resetMinSize and resetMaxSize, or sizeDistribution, is defined,
+        picks a random size from resetMinSize...resetMaxSize inclusive, or randomly
+        from sizeDistribution. */ 
+    public int pickSize(final EvolutionState state, final int thread)
+        {
+        if (sizeDistribution!=null)
+            // pick from distribution
+            return RandomChoice.pickFromDistribution(
+                sizeDistribution,
+                state.random[thread].nextFloat());
+        else
+            // pick from resetMinSize...resetMaxSize
+            return state.random[thread].nextInt(resetMaxSize-resetMinSize+1) + resetMinSize;
+        }
+
+    /**
+       The prototype of the Rule that will be used in the RuleSet
+       (the RuleSet contains only rules with the specified prototype).
+    */
+    public Rule rulePrototype;
+
+    /**
+       Returns a stochastic value picked to specify the number of rules
+       to generate when calling reset() on this kind of Rule.  The default
+       version picks from the min/max or distribution, but you can override
+       this to do whatever kind of thing you like here.
+    */
+    public int numRulesForReset(final RuleSet ruleset, 
+        final EvolutionState state, final int thread)
+        {
+        // the default just uses pickSize
+        return pickSize(state,thread);
+        }
+        
+    /** The byte value of the constraints -- we can only have 256 of them */
+    public byte constraintNumber;
+
+    /** The name of the RuleSetConstraints object */
+    public String name;
+
+    /** Converting the rule to a string ( the name ) */
+    public String toString() { return name; }
+    
+    /** Sets up all the RuleSetConstraints, loading them from the parameter
+        file.  This must be called before anything is called which refers
+        to a type by name. */
+
+    /** You must guarantee that after calling constraintsFor(...) one or
+        several times, you call state.output.exitIfErrors() once. */
+
+    public static RuleSetConstraints constraintsFor(final String constraintsName,
+        final EvolutionState state)
+        {
+        RuleSetConstraints myConstraints = (RuleSetConstraints)(((RuleInitializer)state.initializer).ruleSetConstraintRepository.get(constraintsName));
+        if (myConstraints==null)
+            state.output.error("The rule constraints \"" + constraintsName + "\" could not be found.");
+        return myConstraints;
+        }
+
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // What's my name?
+        name = state.parameters.getString(base.push(P_NAME),null);
+        if (name==null)
+            state.output.fatal("No name was given for this RuleSetConstraints.",
+                base.push(P_NAME));
+
+        // Register me
+        RuleSetConstraints old_constraints = (RuleSetConstraints)(((RuleInitializer)state.initializer).ruleSetConstraintRepository.put(name,this));
+        if (old_constraints != null)
+            state.output.fatal("The rule constraints \"" + name + "\" has been defined multiple times.", base.push(P_NAME));
+        
+        // load my prototypical Rule
+        rulePrototype = (Rule)(state.parameters.getInstanceForParameter(base.push(P_RULE),null,Rule.class));
+        rulePrototype.setup(state,base.push(P_RULE));
+
+        p_add = state.parameters.getFloat( base.push( P_ADD_PROB ), null, 0 );
+        if( p_add < 0 || p_add > 1 )
+            {
+            state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].",
+                base.push( P_ADD_PROB ) );
+            }
+        p_del = state.parameters.getFloat( base.push( P_DEL_PROB ), null, 0 );
+        if( p_del < 0 || p_del > 1 )
+            {
+            state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].",
+                base.push( P_DEL_PROB ) );
+            }
+
+        p_randorder = state.parameters.getFloat( base.push( P_RAND_ORDER_PROB ), null, 0 );
+        if( p_randorder < 0 || p_randorder > 1 )
+            {
+            state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].",
+                base.push( P_RAND_ORDER_PROB ) );
+            }
+
+        // now, we are going to load EITHER min/max size OR a size distribution, or both
+        // (the size distribution takes precedence)
+
+        // reset min and max size
+
+        if (state.parameters.exists(base.push(P_RESETMINSIZE), null) || 
+            state.parameters.exists(base.push(P_RESETMAXSIZE), null))
+            {
+            if (!(state.parameters.exists(base.push(P_RESETMAXSIZE), null)))
+                state.output.error("This RuleSetConstraints has a " + 
+                    P_RESETMINSIZE + " but not a " + P_RESETMAXSIZE + ".");
+           
+            resetMinSize = state.parameters.getInt(
+                base.push(P_RESETMINSIZE), null,0);
+            if (resetMinSize==-1) 
+                state.output.error("If min&max are defined, RuleSetConstraints must have a min size >= 0.",
+                    base.push(P_RESETMINSIZE), null);
+            
+            resetMaxSize = state.parameters.getInt(
+                base.push(P_RESETMAXSIZE), null,0);
+            if (resetMaxSize==-1) 
+                state.output.error("If min&max are defined, RuleSetConstraints must have a max size >= 0.",
+                    base.push(P_RESETMAXSIZE), null);
+
+            if (resetMinSize > resetMaxSize)
+                state.output.error(
+                    "If min&max are defined, RuleSetConstraints must have min size <= max size.",
+                    base.push(P_RESETMINSIZE), null);
+            state.output.exitIfErrors();
+            }
+
+        // load sizeDistribution
+
+        if (state.parameters.exists(base.push(P_NUMSIZES),
+                null))
+            {
+            int siz = state.parameters.getInt(
+                base.push(P_NUMSIZES), null,1);
+            if (siz==0)
+                state.output.fatal("The number of sizes in the RuleSetConstraints's distribution must be >= 1. ");
+            sizeDistribution = new float[siz];
+            
+            float sum = 0.0f;
+            for(int x=0;x<siz;x++)
+                {
+                sizeDistribution[x] = state.parameters.getFloat(
+                    base.push(P_RESETSIZE).push(""+x),null, 0.0f);
+                if (sizeDistribution[x]<0.0)
+                    {
+                    state.output.warning(
+                        "Distribution value #" + x + " negative or not defined, assumed to be 0.0",
+                        base.push(P_RESETSIZE).push(""+x),null);
+                    sizeDistribution[x] = 0.0f;
+                    }
+                sum += sizeDistribution[x];
+                }
+            if (sum>1.0)
+                state.output.warning(
+                    "Distribution sums to greater than 1.0",
+                    base.push(P_RESETSIZE),
+                    null);
+            if (sum==0.0)
+                state.output.fatal(
+                    "Distribution is all 0's",
+                    base.push(P_RESETSIZE),
+                    null);
+
+            // normalize and prepare
+            RandomChoice.organizeDistribution(sizeDistribution);
+            }
+        
+        if (state.parameters.exists(base.push(P_MINSIZE), null))
+            minSize = state.parameters.getInt( base.push( P_MINSIZE ), null, 0 );
+        else minSize = 0;
+        
+        if (state.parameters.exists(base.push(P_MAXSIZE), null))
+            maxSize = state.parameters.getInt( base.push( P_MAXSIZE ), null, 0 );
+        else maxSize = Integer.MAX_VALUE;
+
+        // sanity checks
+        if (minSize > maxSize)
+            {
+            state.output.fatal("Cannot have min size greater than max size : (" + minSize + " > " + maxSize + ")",base.push(P_MINSIZE), null);
+            }
+        
+        if (sizeDistribution != null)
+            {
+            if (minSize!=0)
+                state.output.fatal("Using size distribution, but min size is not 0",
+                    base.push(P_MINSIZE), null);
+            if (sizeDistribution.length - 1 > maxSize)
+                state.output.fatal("Using size distribution whose maximum size is higher than max size",
+                    base.push(P_MAXSIZE), null);
+            }
+        else
+            {
+            if (resetMinSize < minSize)
+                state.output.fatal("Cannot have min size greater than reset min size : (" + minSize + " > " + resetMinSize + ")",base.push(P_MINSIZE), null);
+            if (resetMaxSize > maxSize)
+                state.output.fatal("Cannot have max size less than reset max size : (" + maxSize + " > " + resetMaxSize + ")",base.push(P_MAXSIZE), null);                
+            }
+
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/RuleSpecies.java	(revision 6152)
@@ -0,0 +1,60 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule;
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/* 
+ * RuleSpecies.java
+ * 
+ * Created: Wed Feb 31 17:42:10 2001
+ * By: Liviu Panait
+ */
+
+/**
+ * RuleSpecies is a simple individual which is suitable as a species
+ * for rule sets subpopulations.  RuleSpecies' individuals must be RuleIndividuals,
+ * and often their pipelines are RuleBreedingPipelines (at any rate,
+ * the pipelines will have to return members of RuleSpecies!).
+ *
+ <p><b>Default Base</b><br>
+ rule.species
+
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public class RuleSpecies extends Species
+    {
+    public static final String P_RULESPECIES = "species";
+
+    public Parameter defaultBase()
+        {
+        return RuleDefaults.base().push(P_RULESPECIES);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        // check to make sure that our individual prototype is a RuleIndividual
+        if (!(i_prototype instanceof RuleIndividual))
+            state.output.fatal("The Individual class for the Species " + getClass().getName() + " is must be a subclass of ec.rule.RuleIndividual.", base );
+        }    
+
+    public Individual newIndividual(EvolutionState state, int thread) 
+        {
+        RuleIndividual newind = (RuleIndividual)(super.newIndividual(state, thread));
+        
+        newind.reset( state, thread);
+
+        return newind;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/README	(revision 6152)
@@ -0,0 +1,1 @@
+See the README in the parent directory.
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/RuleCrossoverPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/RuleCrossoverPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/RuleCrossoverPipeline.java	(revision 6152)
@@ -0,0 +1,218 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule.breed;
+
+import ec.rule.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * RuleCrossoverPipeline.java
+ * 
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ * By: Sean Luke
+ */
+
+
+/**
+ *
+ RuleCrossoverPipeline is a BreedingPipeline which implements a simple default crossover
+ for RuleIndividuals.  Normally it takes two individuals and returns two crossed-over 
+ child individuals.  Optionally, it can take two individuals, cross them over, but throw
+ away the second child (a one-child crossover).  RuleCrossoverPipeline works by iteratively taking rulesets
+ from each individual, and migrating rules from either to the other with a certain
+ per-rule probability.  Rule crossover preserves the min and max rule restrictions.
+  
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ 1 or 2
+
+ <p><b>Number of Sources</b><br>
+ 2
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>toss</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font>/td>
+ <td valign=top>(after crossing over with the first new individual, should its second sibling individual be thrown away instead of adding it to the population?)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>prob</tt><br>
+ <font size=-1>0.0 &lt;= float &lt; 1.0, or 0.5 (default)</font>/td>
+ <td valign=top>(probability that a rule will cross over from one individual to the other)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ rule.xover
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class RuleCrossoverPipeline extends BreedingPipeline
+    {
+    public static final String P_TOSS = "toss";
+    public static final String P_CROSSOVER = "xover";
+    public static final String P_CROSSOVERPROB = "crossover-prob";
+    public static final int INDS_PRODUCED = 2;
+    public static final int NUM_SOURCES = 2;
+
+    /** Should the pipeline discard the second parent after crossing over? */
+    public boolean tossSecondParent;
+    
+    /** What is the probability of a rule migrating? */
+    public float ruleCrossProbability;
+
+    /** Temporary holding place for parents */
+    RuleIndividual parents[];
+
+    public RuleCrossoverPipeline() { parents = new RuleIndividual[2]; }
+    public Parameter defaultBase() { return RuleDefaults.base().push(P_CROSSOVER); }
+
+    /** Returns 2 */
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        RuleCrossoverPipeline c = (RuleCrossoverPipeline)(super.clone());
+
+        // deep-cloned stuff
+        c.parents = (RuleIndividual[]) parents.clone();
+
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        Parameter def = defaultBase();
+        tossSecondParent = state.parameters.getBoolean(base.push(P_TOSS),
+            def.push(P_TOSS),false);
+        ruleCrossProbability = state.parameters.getFloatWithDefault(base.push(P_CROSSOVERPROB),
+            def.push(P_CROSSOVERPROB),0.5f);
+        if (ruleCrossProbability > 1.0 || ruleCrossProbability < 0.0) 
+            state.output.fatal("Rule cross probability must be between 0 and 1",base.push(P_CROSSOVERPROB),
+                def.push(P_CROSSOVERPROB));
+        }
+        
+    /** Returns 2 (unless tossing the second sibling, in which case it returns 1) */
+    public int typicalIndsProduced() { return (tossSecondParent? 1: INDS_PRODUCED); }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        // how many individuals should we make?
+        int n = (tossSecondParent? 1 : INDS_PRODUCED);
+        if (n < min) n = min;
+        if (n > max) n = max;
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, true);  // DO produce children from source -- we've not done so already
+
+
+        RuleInitializer initializer = ((RuleInitializer)state.initializer);
+    
+        for(int q=start;q<n+start; /* no increment */)  // keep on going until we're filled up
+            {
+            // grab two individuals from our sources
+            if (sources[0]==sources[1])  // grab from the same source
+                {
+                sources[0].produce(2,2,0,subpopulation,parents,state,thread);
+                if (!(sources[0] instanceof BreedingPipeline))  // it's a selection method probably
+                    { 
+                    parents[0] = (RuleIndividual)(parents[0].clone());
+                    parents[1] = (RuleIndividual)(parents[1].clone());
+                    }
+                }
+            else // grab from different sources
+                {
+                sources[0].produce(1,1,0,subpopulation,parents,state,thread);
+                sources[1].produce(1,1,1,subpopulation,parents,state,thread);
+                if (!(sources[0] instanceof BreedingPipeline))  // it's a selection method probably
+                    parents[0] = (RuleIndividual)(parents[0].clone());
+                if (!(sources[1] instanceof BreedingPipeline)) // it's a selection method probably
+                    parents[1] = (RuleIndividual)(parents[1].clone());
+                }
+
+            // at this point, parents[] contains our two selected individuals,
+            // AND they're copied so we own them and can make whatever modifications
+            // we like on them.
+
+            // so we'll cross them over now.
+
+            parents[0].preprocessIndividual(state,thread);
+            parents[1].preprocessIndividual(state,thread);
+
+            if( parents[0].rulesets.length != parents[1].rulesets.length )
+                {
+                state.output.fatal( "The number of rule sets should be identical in both parents ( " +
+                    parents[0].rulesets.length + " : " +
+                    parents[1].rulesets.length + " )." );
+                }
+
+            // for each set of rules (assume both individuals have the same number of rule sets)
+            for( int x = 0 ; x < parents[0].rulesets.length ; x++ )
+                {
+                RuleSet[] temp = new RuleSet[2];
+                while(true)
+                    {
+                    // create two new rulesets (initially empty)
+                    for( int i = 0 ; i < 2 ; i++ )
+                        temp[i] = new RuleSet();
+                    // split the ruleset indexed x in parent 1
+                    temp = parents[0].rulesets[x].splitIntoTwo( state, thread, temp,ruleCrossProbability);
+                    // now temp[0] contains rules to that must go to parent[1]
+                                        
+                    // split the ruleset indexed x in parent 2 (append after the split results from previous operation)
+                    temp = parents[1].rulesets[x].splitIntoTwo( state, thread, temp, 1 - ruleCrossProbability);
+                    // now temp[1] contains rules that must go to parent[0]
+                    
+                    // ensure that there are enough rules
+                    if (temp[0].numRules >= parents[0].rulesets[x].constraints(initializer).minSize &&
+                        temp[0].numRules <= parents[0].rulesets[x].constraints(initializer).maxSize &&
+                        temp[1].numRules >= parents[1].rulesets[x].constraints(initializer).minSize &&
+                        temp[1].numRules <= parents[1].rulesets[x].constraints(initializer).maxSize)
+                        break;
+                        
+                    temp = new RuleSet[2];
+                    }
+                    
+                // copy the results in the rulesets of the parents
+                parents[0].rulesets[x].copyNoClone(temp[1]);
+                parents[1].rulesets[x].copyNoClone(temp[0]);
+                }
+            
+            parents[0].postprocessIndividual(state,thread);
+            parents[1].postprocessIndividual(state,thread);
+    
+            parents[0].evaluated=false;
+            parents[1].evaluated=false;
+            
+            // add 'em to the population
+            inds[q] = parents[0];
+            q++;
+            if (q<n+start && !tossSecondParent)
+                {
+                inds[q] = parents[1];
+                q++;
+                }
+            }
+        return n;
+        }
+    }
+    
+    
+    
+    
+    
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/RuleMutationPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/RuleMutationPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/rule/breed/RuleMutationPipeline.java	(revision 6152)
@@ -0,0 +1,102 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.rule.breed;
+
+import ec.rule.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * RuleMutationPipeline.java
+ * 
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ * By: Sean Luke
+ */
+
+
+/**
+ *
+ RuleMutationPipeline is a BreedingPipeline which implements a simple default Mutation
+ for RuleIndividuals.  Normally it takes an individual and returns a mutated 
+ child individual. RuleMutationPipeline works by calling mutateRules(...) on each RuleSet in the 
+ parent individual.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ 1
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Default Base</b><br>
+ rule.mutate (not that it matters)
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class RuleMutationPipeline extends BreedingPipeline
+    {
+    public static final String P_MUTATION = "mutate";
+    public static final int INDS_PRODUCED = 1;
+    public static final int NUM_SOURCES = 1;
+
+    public Parameter defaultBase() { return RuleDefaults.base().push(P_MUTATION); }
+    
+    /** Returns 1 */
+    public int numSources() { return NUM_SOURCES; }
+
+    /** Returns 1 */
+    // DO I need to change this?
+    public int typicalIndsProduced() { return (INDS_PRODUCED); }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab n individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+        // clone the individuals if necessary
+        if (!(sources[0] instanceof BreedingPipeline))
+            for(int q=start;q<n+start;q++)
+                inds[q] = (Individual)(inds[q].clone());
+
+        // mutate 'em
+        for(int q=start;q<n+start;q++)
+            {
+
+            ((RuleIndividual)inds[q]).preprocessIndividual(state,thread);
+
+            /*
+              int len = ((RuleIndividual)inds[q]).rulesets.length;
+              for( int x = 0 ; x < len ; x++ )
+              {
+              ((RuleIndividual)inds[q]).rulesets[x].mutateRules( state, thread );
+              }
+            */
+            ((RuleIndividual)inds[q]).mutate(state, thread);
+            ((RuleIndividual)inds[q]).postprocessIndividual(state,thread);
+
+            ((RuleIndividual)inds[q]).evaluated=false;
+            }
+
+        return n;
+        }
+
+    }
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/BestSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/BestSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/BestSelection.java	(revision 6152)
@@ -0,0 +1,162 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.util.*;
+import ec.*;
+/* 
+ * BestSelection.java
+ * 
+ * Created: Thu Feb 10 18:52:09 2000
+ * By: Sean Luke
+ */
+
+/**
+ * Picks among the best <i>n</i> individuals in a population in 
+ * direct proportion to their absolute
+ * fitnesses as returned by their fitness() methods relative to the
+ * fitnesses of the other "best" individuals in that <i>n</i>.  This is expensive to
+ * set up and bring down, so it's not appropriate for steady-state evolution.
+ * If you're not familiar with the relative advantages of 
+ * selection methods and just want a good one,
+ * use TournamentSelection instead.   Not appropriate for
+ * multiobjective fitnesses.
+ *
+ * <p><b><font color=red>
+ * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
+ * </font></b>
+ *
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick from among the <i>worst n</i> individuals in the tournament instead of the <i>best n</i>?)</td></tr>
+ <tr><td valign=top><i>base.</i><tt>n</tt><br>
+ <font size=-1> int > 0 (default is 1)</font></td>
+ <td valign=top>(the number of best-individuals to select from)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.best
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class BestSelection extends SelectionMethod 
+    {
+    /** Default base */
+    public static final String P_BEST = "best";
+    public static final String P_N = "n";
+    public static final String P_PICKWORST = "pick-worst";
+    /** Sorted, normalized, totalized fitnesses for the population */
+    public float[] sortedFit;
+    /** Sorted population -- since I *have* to use an int-sized
+        individual (short gives me only 16K), 
+        I might as well just have pointers to the
+        population itself.  :-( */
+    public int[] sortedPop;
+
+    /** Do we pick the worst instead of the best? */
+    public boolean pickWorst;
+
+    public int bestn;
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_BEST);
+        }
+
+    // don't need clone etc. 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+        
+        bestn =
+            state.parameters.getInt(base.push(P_N),def.push(P_N),1);
+        if (bestn == 0 )
+            state.output.fatal("n must be an integer greater than 0", base.push(P_N),def.push(P_N));
+        
+        pickWorst = state.parameters.getBoolean(base.push(P_PICKWORST),def.push(P_PICKWORST),false);
+        }
+
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // load sortedPop integers
+        final Individual[] i = s.population.subpops[subpopulation].individuals;
+
+        sortedPop = new int[i.length];
+        for(int x=0;x<sortedPop.length;x++) sortedPop[x] = x;
+
+        // sort sortedPop in increasing fitness order
+        QuickSort.qsort(sortedPop, 
+            new SortComparatorL()
+                {
+                public boolean lt(long a, long b)
+                    {
+                    return ((Individual)(i[(int)b])).fitness.betterThan(
+                        ((Individual)(i[(int)a])).fitness);
+                    }
+
+                public boolean gt(long a, long b)
+                    {
+                    return ((Individual)(i[(int)a])).fitness.betterThan(
+                        ((Individual)(i[(int)b])).fitness);
+                    }
+                });
+
+        // load sortedFit
+        sortedFit = new float[Math.min(sortedPop.length,bestn)];
+        if (pickWorst)
+            for(int x=0;x<sortedFit.length;x++)
+                sortedFit[x] = ((Individual)(i[sortedPop[x]])).fitness.fitness();
+        else
+            for(int x=0;x<sortedFit.length;x++)
+                sortedFit[x] = ((Individual)(i[sortedPop[sortedPop.length-x-1]])).fitness.fitness();
+
+        for(int x=0;x<sortedFit.length;x++)
+            {
+            if (sortedFit[x] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  BestSelection requires that all fitness values be non-negative(offending subpopulation #" + subpopulation + ")");
+            }
+
+
+        // organize the distributions.  All zeros in fitness is fine
+        RandomChoice.organizeDistribution(sortedFit, true);
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        // Pick and return an individual from the population
+        if (pickWorst)
+            return sortedPop[RandomChoice.pickFromDistribution(
+                    sortedFit,state.random[thread].nextFloat())];
+        else
+            return sortedPop[sortedPop.length - RandomChoice.pickFromDistribution(
+                    sortedFit,state.random[thread].nextFloat()) - 1];            
+        }
+    
+    public void finishProducing(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // release the distributions so we can quickly 
+        // garbage-collect them if necessary
+        sortedFit = null;
+        sortedPop = null;
+        }    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/BoltzmannSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/BoltzmannSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/BoltzmannSelection.java	(revision 6152)
@@ -0,0 +1,145 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.util.*;
+import ec.*;
+
+/* 
+ * BoltzmannSelection.java
+ * 
+ * Created: Thu May 14 2009
+ * By: Jack Compton
+ */
+
+/**
+ * Similar to FitProportionateSelection, but with a Simulated Annealing style twist. BoltzmannSelection picks individuals of a population in 
+ * proportion to an adjusted version of their fitnesses instead of their actual fitnesses as returned by fitness(). The adjusted fitness is 
+ * calculated by e^(fitness/current_temperature) where current_temperature is a temperature value that decreases by a constant cooling rate as 
+ * generations of evolution pass. The current_temperature is calculated by starting-temperature - (cooling-rate * the_current_generation_number). 
+ * When the temperature dips below 1.0, annealing ceases and BoltzmannSelection reverts to normal FitProportionateSelection behavior.
+ *
+ * <p>
+ * Like FitProportionateSelection this is not appropriate for steady-state evolution.
+ * If you're not familiar with the relative advantages of 
+ * selection methods and just want a good one,
+ * use TournamentSelection instead. Not appropriate for
+ * multiobjective fitnesses.
+ *
+ * <p><b><font color=red>
+ * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
+ * </font></b>
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>starting-temperature</tt><br>
+ <font size=-1>double = some large number (defaults to 1.0)</font></td>
+ <td valign=top>(the starting temperature for our simulated annealing style adjusted fitness proportions)</td></tr>
+ 
+ <tr><td valign=top><i>base.</i><tt>cooling-rate</tt><br>
+ <font size=-1> double = some smaller number (defaults to 0.0 which causes BoltzmannSelection to behave just as FitProportionateSelection would)</font></td>
+ <td valign=top>(how slow, or fast, do you want to cool the annealing fitness proportions?)</td></tr>
+ 
+ </table> 
+
+ <p><b>Default Base</b><br>
+ select.boltzmann
+
+ *
+ * @author Jack Compton
+ * @version 1.0 
+ */
+
+public class BoltzmannSelection extends FitProportionateSelection
+    {
+    /** Default base */
+    public static final String P_BOLTZMANN = "boltzmann";
+                
+    /** Starting temperature parameter */
+    public static final String P_STARTING_TEMPERATURE = "starting-temperature";
+                
+    /** Cooling rate parameter */
+    public static final String P_COOLING_RATE = "cooling-rate";
+                
+    /** Starting temperature **/
+    private double startingTemperature;
+                
+    /** Cooling rate */
+    private double coolingRate;
+                
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_BOLTZMANN);
+        }
+                
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+                        
+        Parameter def = defaultBase();
+                        
+        coolingRate = state.parameters.getDouble(base.push(P_COOLING_RATE),def.push(P_COOLING_RATE)); // default cooling rate of 1.0 per generation
+        startingTemperature = state.parameters.getDouble(base.push(P_STARTING_TEMPERATURE),def.push(P_STARTING_TEMPERATURE)); // default starting temp is 0.0/completely cooled - will act as normal fit proportionate selection
+                        
+        if (coolingRate <= 0)
+            {
+            //Hey! you gotta cool! Set your cooling rate to a positive value!
+            state.output.fatal("Cooling rate should be a positive value.",base.push(P_COOLING_RATE),def.push(P_COOLING_RATE));
+            }
+                        
+        if ((startingTemperature - coolingRate) <= 0) {
+            // C'mon, you should cool slowly if you want boltzmann selection to be effective.
+            state.output.fatal("For best results, try to set your temperature to cool to 0 a more slowly. This can be acheived by increasing your starting-temperature and/or decreasing your cooling rate.\nstarting-temperatire/cooling-rate: " + startingTemperature + " / " + coolingRate);                             
+            }
+                        
+        int total_generations = state.numGenerations;
+        if (total_generations == 0)
+            {
+            //Load from parameter database!!
+            state.output.fatal("Hey now, we gotta load the total_generations from the param DB");
+            }
+                        
+        if ((startingTemperature - (coolingRate * total_generations)) > 0)
+            {
+            //Either your cooling rate is to low, or your starting temp is too high, because at this rate you will never cool to 0! (kind of essential to reaping the benefits of boltzmann selection)
+            state.output.warning("If you want BoltzmannnSelection to be effective, your temperature should cool to 0 before all generations have passed. Make sure that (starting-temperature - (cooling-rate * generations)) <= 0.");
+            }
+        
+        }
+
+    // completely override FitProportionateSelection.prepareToProduce
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // load fitnesses
+        fitnesses = new float[s.population.subpops[subpopulation].individuals.length];
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            fitnesses[x] = (float) boltzmannExpectedValue(
+                ((Individual)(s.population.subpops[subpopulation].individuals[x])).fitness.fitness(), 
+                s); // adjust the fitness proportion according to current temperature.
+            if (fitnesses[x] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  BoltzmannnSelection requires that all fitness values be non-negative(offending subpopulation #" + subpopulation + ")");
+            }
+        
+        // organize the distribution.  All zeros in fitness is fine
+        RandomChoice.organizeDistribution(fitnesses, true);
+        }
+
+    private double boltzmannExpectedValue(double fitness, final EvolutionState s)
+        {
+        double current_temperature = startingTemperature - (coolingRate * s.generation);
+        if (current_temperature < 1.0)
+            return fitness;
+        return Math.exp(fitness/current_temperature);
+        }
+        
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/FirstSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/FirstSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/FirstSelection.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+
+/* 
+ * FirstSelection.java
+ * 
+ * Created: Mon Aug 30 19:27:15 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Always picks the first individual in the subpopulation.  This is mostly
+ * for testing purposes.
+ *
+
+ <p><b>Default Base</b><br>
+ select.first
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class FirstSelection extends SelectionMethod implements SteadyStateBSourceForm
+    {
+    /** default base */
+    public static final String P_FIRST = "first";
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_FIRST);
+        }
+    
+    // I hard-code both produce(...) methods for efficiency's sake
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        return 0;
+        }
+
+
+    // I hard-code both produce(...) methods for efficiency's sake
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        int n = 1;
+        if (n>max) n = max;
+        if (n<min) n = min;
+
+        for(int q = 0; q < n; q++)
+            {
+            // pick size random individuals, then pick the best.
+            Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+            inds[start+q] = oldinds[0];  // note it's a pointer transfer, not a copy!
+            }
+        return n;
+        }
+
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        { return; }
+    
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        { return; }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/FitProportionateSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/FitProportionateSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/FitProportionateSelection.java	(revision 6152)
@@ -0,0 +1,91 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.util.*;
+import ec.*;
+
+/* 
+ * FitProportionateSelection.java
+ * 
+ * Created: Thu Feb 10 16:31:24 2000
+ * By: Sean Luke
+ */
+
+/**
+ * Picks individuals in a population in direct proportion to their
+ * fitnesses as returned by their fitness() methods.  This is expensive to
+ * set up and bring down, so it's not appropriate for steady-state evolution.
+ * If you're not familiar with the relative advantages of 
+ * selection methods and just want a good one,
+ * use TournamentSelection instead.   Not appropriate for
+ * multiobjective fitnesses.
+ *
+ * <p><b><font color=red>
+ * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
+ * </font></b>
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Default Base</b><br>
+ select.fitness-proportionate
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class FitProportionateSelection extends SelectionMethod
+    {
+    /** Default base */
+    public static final String P_FITNESSPROPORTIONATE = "fitness-proportionate";
+    /** Normalized, totalized fitnesses for the population */
+    public float[] fitnesses;
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_FITNESSPROPORTIONATE);
+        }
+
+    // don't need clone etc. 
+
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // load fitnesses
+        fitnesses = new float[s.population.subpops[subpopulation].individuals.length];
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            fitnesses[x] = ((Individual)(s.population.subpops[subpopulation].individuals[x])).fitness.fitness();
+            if (fitnesses[x] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  FitProportionateSelection requires that all fitness values be non-negative(offending subpopulation #" + subpopulation + ")");
+            }
+        
+        // organize the distribution.  All zeros in fitness is fine
+        RandomChoice.organizeDistribution(fitnesses, true);
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        // Pick and return an individual from the population
+        return RandomChoice.pickFromDistribution(
+            fitnesses,state.random[thread].nextFloat());
+        }
+    
+    public void finishProducing(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // release the distributions so we can quickly 
+        // garbage-collect them if necessary
+        fitnesses = null;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/GreedyOverselection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/GreedyOverselection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/GreedyOverselection.java	(revision 6152)
@@ -0,0 +1,195 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GreedyOverselection.java
+ * 
+ * Created: Thu Feb 10 17:39:03 2000
+ * By: Sean Luke
+ */
+
+/**
+ * GreedyOverselection is a SelectionMethod which implements Koza-style
+ * fitness-proportionate greedy overselection.  Not appropriate for
+ * multiobjective fitnesses.
+ *
+ * <p> This selection method first 
+ * divides individuals in a population into two groups: the "good" 
+ * ("top") group, and the "bad" ("bottom") group.  The best <i>top</i>
+ * percent of individuals in the population go into the good group.
+ * The rest go into the "bad" group.  With a certain probability (determined
+ * by the <i>gets</i> setting), an individual will be picked out of the
+ * "good" group.  Once we have determined which group the individual
+ * will be selected from, the individual is picked using fitness proportionate
+ * selection in that group, that is, the likelihood he is picked is 
+ * proportionate to his fitness relative to the fitnesses of others in his
+ * group.
+ *
+ * <p> All this is expensive to
+ * set up and bring down, so it's not appropriate for steady-state evolution.
+ * If you're not familiar with the relative advantages of 
+ * selection methods and just want a good one,
+ * use TournamentSelection instead. 
+ *
+ * <p><b><font color=red>
+ * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
+ * </font></b>
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>top</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0</font></td>
+ <td valign=top>(the percentage of the population going into the "good" (top) group)</td></tr>
+ <tr><td valign=top><i>base.</i><tt>gets</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0</font></td>
+ <td valign=top>(the likelihood that an individual will be picked from the "good" group)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.greedy
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class GreedyOverselection extends SelectionMethod
+    {
+    public float[] sortedFitOver;
+    public float[] sortedFitUnder;
+    /** Sorted population -- since I *have* to use an int-sized
+        individual (short gives me only 16K), 
+        I might as well just have pointers to the
+        population itself.  :-( */
+    public int[] sortedPop;
+
+    public static final String P_GREEDY = "greedy";
+    public static final String P_TOP = "top";
+    public static final String P_GETS = "gets";
+
+    public float top_n_percent;
+    public float gets_n_percent;
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_GREEDY);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+        
+        top_n_percent =
+            state.parameters.getFloatWithMax(base.push(P_TOP),def.push(P_TOP),0.0,1.0);
+        if (top_n_percent < 0.0)
+            state.output.fatal("Top-n-percent must be between 0.0 and 1.0", base.push(P_TOP),def.push(P_TOP));
+        
+        gets_n_percent =
+            state.parameters.getFloatWithMax(base.push(P_GETS),def.push(P_GETS),0.0,1.0);
+        if (gets_n_percent < 0.0)
+            state.output.fatal("Gets-n-percent must be between 0.0 and 1.0", base.push(P_GETS),def.push(P_GETS));
+        
+        }
+    
+    
+    // don't need clone etc. -- I'll never clone with my arrays intact
+    
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // load sortedPop integers
+        final Individual[] i = s.population.subpops[subpopulation].individuals;
+
+        sortedPop = new int[i.length];
+        for(int x=0;x<sortedPop.length;x++) sortedPop[x] = x;
+        
+        // sort sortedPop in increasing fitness order
+        QuickSort.qsort(sortedPop, 
+            new SortComparatorL()
+                {
+                public boolean lt(long a, long b)
+                    {
+                    return ((Individual)(i[(int)b])).fitness.betterThan(
+                        ((Individual)(i[(int)a])).fitness);
+                    }
+
+                public boolean gt(long a, long b)
+                    {
+                    return ((Individual)(i[(int)a])).fitness.betterThan(
+                        ((Individual)(i[(int)b])).fitness);
+                    }
+                });
+        
+        // determine my boundary -- must be at least 1 and must leave 1 over
+        int boundary = (int)(sortedPop.length * top_n_percent);
+        if (boundary == 0) boundary = 1;
+        if (boundary == sortedPop.length) boundary = sortedPop.length-1;
+        if (boundary == 0) // uh oh
+            s.output.fatal("Greedy Overselection can only be done with a population of size 2 or more (offending subpopulation #" + subpopulation + ")");
+        
+        // load sortedFitOver
+        sortedFitOver = new float[boundary];
+        int y=0;
+        for(int x=sortedPop.length-boundary;x<sortedPop.length;x++)
+            {
+            sortedFitOver[y] = (i[sortedPop[x]]).fitness.fitness();
+            if (sortedFitOver[y] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  Greedy Overselection requires that all fitness values be non-negative (offending subpopulation #" + subpopulation + ")");
+            y++;
+            }
+        
+        // load sortedFitUnder
+        sortedFitUnder = new float[sortedPop.length-boundary];
+        y=0;
+        for(int x=0;x<sortedPop.length-boundary;x++)
+            {
+            sortedFitUnder[y] = (i[sortedPop[x]]).fitness.fitness();
+            if (sortedFitUnder[y] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  Greedy Overselection requires that all fitness values be non-negative (offending subpopulation #" + subpopulation + ")");
+            y++;
+            }
+
+        // organize the distributions.  All zeros in fitness is fine
+        RandomChoice.organizeDistribution(sortedFitUnder, true);
+        RandomChoice.organizeDistribution(sortedFitOver, true);
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        // pick a coin toss
+        if (state.random[thread].nextBoolean(gets_n_percent))
+            // over -- sortedFitUnder.length to sortedPop.length
+            return sortedPop[
+                sortedFitUnder.length + RandomChoice.pickFromDistribution(
+                    sortedFitOver,state.random[thread].nextFloat())];
+        else
+            // under -- 0 to sortedFitUnder.length
+            return sortedPop[RandomChoice.pickFromDistribution(
+                    sortedFitUnder,state.random[thread].nextFloat())];
+        }
+
+    public void finishProducing(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // release the distributions so we can quickly 
+        // garbage-collect them if necessary
+        sortedFitUnder = null;
+        sortedFitOver = null;
+        sortedPop = null;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/MultiSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/MultiSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/MultiSelection.java	(revision 6152)
@@ -0,0 +1,198 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * MultiSelection.java
+ * 
+ * Created: Wed Dec 29 21:44:50 1999
+ * By: Sean Luke
+ */
+
+/**
+ * MultiSelection is a SelectionMethod which stores some <i>n</i> subordinate
+ * SelectionMethods.  Each time it must produce an individual, 
+ * it picks one of these SelectionMethods at random and has it do the production
+ * instead.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>num-selects</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(The number of subordinate SelectionMethods)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>select.</tt><i>n</i><br>
+ <font size=-1>classname, inherits and != SelectionMethod</tt><br>
+ <td valign=top>(Subordinate SelectionMethod <i>n</i>)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.multiselect
+
+ <p><b>Parameter bases</b><br>
+ <table>
+
+ <tr><td valign=top><i>base</i>.<tt>select.</tt><i>n</i><br>
+ <td>Subordinate SelectionMethod <i>n</i></td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class MultiSelection extends SelectionMethod
+    {
+    public static final String P_NUMSELECTS = "num-selects";
+    public static final String P_SELECT = "select";
+    public static final String P_MULTISELECT = "multiselect";
+
+    /** The MultiSelection's individuals */
+    public SelectionMethod selects[];
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_MULTISELECT);
+        }
+
+    public Object clone()
+        {
+        MultiSelection c = (MultiSelection)(super.clone());
+        
+        // make a new array
+        c.selects = new SelectionMethod[selects.length];
+
+        // clone the selects -- we won't go through the hassle of
+        // determining if we have a DAG or not -- we'll just clone
+        // it out to a tree.  I doubt it's worth it.
+
+        for(int x=0;x<selects.length;x++)
+            c.selects[x] = (SelectionMethod)(selects[x].clone());
+
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        Parameter def = defaultBase();
+
+        int numSelects = state.parameters.getInt(
+            base.push(P_NUMSELECTS),def.push(P_NUMSELECTS),1);
+        if (numSelects==0)
+            state.output.fatal("The number of MultiSelection sub-selection methods must be >= 1).",
+                base.push(P_NUMSELECTS),def.push(P_NUMSELECTS));
+
+        // make our arrays
+        selects = new SelectionMethod[numSelects];
+
+        float total = 0.0f;
+
+        for(int x=0;x<numSelects;x++)
+            {
+            Parameter p = base.push(P_SELECT).push(""+x);
+            Parameter d = def.push(P_SELECT).push(""+x);
+
+            selects[x] = (SelectionMethod)
+                (state.parameters.getInstanceForParameter(
+                    p,d, SelectionMethod.class));       
+            selects[x].setup(state,p);
+            
+            // now check probability
+            if (selects[x].probability<0.0)
+                state.output.error(
+                    "MultiSelection select #" + x + 
+                    " must have a probability >= 0.0",
+                    p.push(P_PROB),d.push(P_PROB));
+            else total += selects[x].probability;
+            }
+
+        state.output.exitIfErrors();
+
+        // Now check for valid probability
+        if (total <= 0.0)
+            state.output.fatal("MultiSelection selects do not sum to a positive probability",base);
+
+        if (total != 1.0)
+            {
+            state.output.message("Must normalize probabilities for " + base);
+            for(int x=0;x<numSelects;x++) selects[x].probability /= total;
+            }
+
+        // totalize
+        float tmp = 0.0f;
+        for(int x=0;x<numSelects-1;x++) // yes, it's off by one
+            { 
+            tmp += selects[x].probability; 
+            selects[x].probability = tmp;
+            }
+        selects[numSelects-1].probability = 1.0f;
+        }
+
+    public boolean produces(final EvolutionState state,
+        final Population newpop,
+        final int subpopulation,
+        final int thread)
+        {
+        if (!super.produces(state,newpop,subpopulation,thread))
+            return false;
+
+        for(int x=0;x<selects.length;x++)
+            if (!selects[x].produces(state,newpop,subpopulation,thread))
+                return false;
+        return true;
+        }
+
+
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        for(int x=0;x<selects.length;x++)
+            selects[x].prepareToProduce(s,subpopulation,thread);
+        }
+
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        return selects[BreedingSource.pickRandom(
+                selects,state.random[thread].nextFloat())].produce(
+                    subpopulation,state,thread);
+        }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        return selects[BreedingSource.pickRandom(
+                selects,state.random[thread].nextFloat())].produce(
+                    min,max,start,subpopulation,inds,state,thread);
+        }
+
+    public void preparePipeline(Object hook)
+        {
+        // the default form calls this on all the selects.
+        // note that it follows all the source paths even if they're
+        // duplicates
+        for(int x=0; x<selects.length;x++) 
+            selects[x].preparePipeline(hook);
+        }
+        
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/README	(revision 6152)
@@ -0,0 +1,89 @@
+This package provides various common selection operators.  In ECJ, selection
+operators (called SelectionMethods) appear as leaf nodes in breeding pipelines.
+If you're having trouble selecting, we suggest you use TournamentSelection,
+perhaps with a tournament size of 2.
+
+Some of these methods require that all fitnesses be >= 0.
+
+Other methods, when first requested to select an individual, buffer up a large
+number of precomputed selections to provide later, or compute certain
+statistics to be used later.  Such selection methods cannot be used efficiently
+in steady state algorithms.
+
+ec.select.MultiSelection 
+	This isn't a selection method so much as a utility procedure.  The
+	algorithm maintains some number of subsidiary selection methods
+	(the 'selects').  When asked to produce a child, it picks a subsidiary
+	according to its associated probability; it then asks for a child from
+	that subsidiary.  The probability is defined in the 'probability'
+	parameter in the subsidiary pipeline.  Compare to 
+	ec.breed.MultiBreedingPipeline, which does more or less the same
+	thing, but as a BreedingPipeline, always copies the children produced
+	from its sources.  MultiSelection, like a good selection operator,
+	makes no such copies (and so is a bit more efficient in this context).
+
+ec.select.BestSelection
+	Always selects uniformly from among the best N individuals in the
+	population.  Can also optionally select from among the N worst.
+
+ec.select.TournamentSelection		[acceptable for Steady State]
+	When asked to select an individual, first picks N individuals at
+	random with replacement, then returns the fittest individual among
+	those N.  The size of N is known as the tournament size, and you
+	specify this.  Can also optionally select the worst among the N. 
+
+ec.select.FitProportionateSelection
+	Selects from among the individuals in the population in proportion
+	to their fitness values (which must all be >= 0).
+
+ec.select.SUSSelection
+	Performs Stochastic Universal Sampling selection, a variant of
+	fitness proportionate selection which guarantees that sufficiently
+	fit individuals will always be selected at least once.  When first
+	asked to select, SUSSelection computes selection choices for an entire
+	populations' worth of individuals beforehand.  It then begins handing
+	these choices out in response to successive requests.  When the choices
+	have been depleted, SUSSelection computes another populations's worth.
+	Like fitness proportionate selection, SUSSelection requires that all
+	fitnesses be >= 0.
+
+ec.select.GreedyOverselection
+	A version of FitProportionateSelection used in early forms of genetic
+	programming.  The individuals are divided by fitness into two groups:
+	the good group and the bad group.  To select an individual, the 
+	algorithm first picks either the good group or the bad group, then
+	performs fitness proportionate selection within that group.  You 
+	specify the size of the good group and the probability that it will
+	be selected.  Like fitness proportionate selection, SUSSelection
+	requires that all fitnesses be >= 0.
+
+ec.select.RandomSelection		[acceptable for Steady State]
+	Always provides a random individual.  This is equivalent to a
+	tournament selection with a tournament size of 1.
+
+ec.select.FirstSelection		[acceptable for Steady State]
+	Always selects the first individual in the population array.  Only
+	used for debugging purposes.
+
+ec.select.BoltzmannSelection		[NOTE: UNTESTED]
+	Performs Boltzman Selection, variation of fitness proportionate
+	selection which makes fitness differences insignificant initially
+	and more prominent as time goes on (think Simulated Annealing).
+	Each generatiowe compute a temperature, defined as the initial
+	temperature (which you define) minus the current generation times
+	the cooling rate (which you also define).  If the temperature is
+	below 1.0, the fitnesses are not adjusted.  Otherwise each
+	fitness is adjusted as E^(fitness / temperature).
+
+ec.select.SigmaScalingSelection		[NOTE: UNTESTED]
+	Performs Sigma Scaling, a variation of fitness propoprtionate
+	selection which stretches fitnesses out if they have been
+	all bunched up together, enabling fitness proportionate 
+	selection methods to still distinguish between them.  We begin
+	by computing the mean and standard deviation of the current
+	fitnesses.  If the standard deviation is not zero, we then
+	adjust each fitness as 1 + (fitness - mean)/(2 * standardDeviation).
+	If the standard deviation is zero, all fitnesses are set to 1.
+	If any fitness is less than a minimal acceptable fitness (the "floor"),
+	it is set to the floor.  This prevents fitnesses from getting stretched
+	so small that they cannot compete.  You specify the floor.
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/RandomSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/RandomSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/RandomSelection.java	(revision 6152)
@@ -0,0 +1,83 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+
+/* 
+ * RandomSelection.java
+ * 
+ * Created: Tue Sep 3 2002
+ * By: Liviu Panait
+ */
+
+/**
+ * Picks a random individual in the subpopulation.  This is mostly
+ * for testing purposes.
+ *
+
+ <p><b>Default Base</b><br>
+ select.random
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class RandomSelection extends SelectionMethod implements SteadyStateBSourceForm
+    {
+    /** default base */
+    public static final String P_RANDOM = "random";
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_RANDOM);
+        }
+
+    // I hard-code both produce(...) methods for efficiency's sake
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        return state.random[thread].nextInt( state.population.subpops[subpopulation].individuals.length );
+        }
+
+    // I hard-code both produce(...) methods for efficiency's sake
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        int n = 1;
+        if (n>max) n = max;
+        if (n<min) n = min;
+
+        for(int q = 0; q < n; q++)
+            {
+            Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+            inds[start+q] = oldinds[state.random[thread].nextInt( state.population.subpops[subpopulation].individuals.length )];
+            }
+        return n;
+        }
+
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        { return; }
+    
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        { return; }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/SUSSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/SUSSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/SUSSelection.java	(revision 6152)
@@ -0,0 +1,179 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.util.*;
+import ec.*;
+
+/* 
+ * SUSSelection.java
+ * 
+ * Created: Thu Feb 12 16:19:52 EST 2009
+ * By: Sean Luke
+ */
+
+/**
+ * Picks individuals in a population using the Stochastic Universal Selection (SUS) process, using
+ * fitnesses as returned by their fitness() methods.  This is expensive to
+ * set up and bring down, so it's not appropriate for steady-state evolution.
+ * If you're not familiar with the relative advantages of 
+ * selection methods and just want a good one,
+ * use TournamentSelection instead.   Not appropriate for
+ * multiobjective fitnesses.
+ *
+ * <p>By default this implementation of SUS shuffles the order of the individuals
+ * in the distribution before performing selection.  This isn't always present in classic
+ * implementations of the algorithm but it can't hurt anything and certainly can avoid
+ * certain pathological situations.  If you'd prefer not to preshuffle, set shuffle=false
+ * Note that we don't actually change the order of the individuals in the population -- instead
+ * we maintain our own internal array of indices and shuffle that.
+ *
+ * <p>Like truncation selection, 
+ * SUS samples N individuals (with replacement) up front from the population,
+ * Then returns those individuals one by one.
+ * ECJ's implementation assumes that N is the size of the population -- that is, you're
+ * going to ultimately request a whole population out of this one selection method.
+ * This could be a false assumption: for example, if you only sometimes call this
+ * selection method, and sometimes TournamentSelection; or if you've got multiple
+ * pipelines.  In these cases, SUS is probably a bad choice anyway.
+ *
+ * <p>If you ask for <i>more</i> than a population's worth of individuals, SUS tries
+ * to handle this gracefully by reshuffling its array and starting to select over
+ * again.  But again that might suggest you are doing something wrong.
+ *
+ * <p><b><font color=red>
+ * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
+ * </font></b>
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>shuffle</tt><br>
+ <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
+ <td valign=top>(should we preshuffle the array before doing selection?)</td></tr>
+
+ </table>
+ <p><b>Default Base</b><br>
+ select.sus
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SUSSelection extends SelectionMethod
+    {
+    /** Default base */
+    public static final String P_SUS = "sus";
+    public static final String P_SHUFFLE = "shuffle";
+    
+    /** An array of pointers to individuals in the population, shuffled along with the fitnesses array. */
+    public int[] indices;
+    /** The distribution of fitnesses. */
+    public float[] fitnesses;
+    
+    /** Should we shuffle first? */
+    public boolean shuffle = true;
+    /** The floating point value to consider for the next selected individual. */
+    public float offset = 0.0f;
+    /** The index in the array of the last individual selected. */
+    public int lastIndex;
+    /** How many samples have been done?  */
+    public int steps;
+    
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_SUS);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+        shuffle = state.parameters.getBoolean(base.push(P_SHUFFLE),def.push(P_SHUFFLE),true);
+        }
+
+    /* Largely stolen from sim.util.Bag.  Shuffles both the indices and the floats */
+    void shuffle(MersenneTwisterFast random)
+        {
+        int numObjs = fitnesses.length;
+        float[] fitnesses = this.fitnesses;
+        int[] indices = this.indices;
+        
+        float f;
+        int i;
+        int rand;
+        
+        for(int x=numObjs-1; x >= 1 ; x--)
+            {
+            rand = random.nextInt(x+1);
+            f = fitnesses[x];
+            fitnesses[x] = fitnesses[rand];
+            fitnesses[rand] = f;
+
+            i = indices[x];
+            indices[x] = indices[rand];
+            indices[rand] = i;
+            }
+        }
+
+    // don't need clone etc. 
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        lastIndex = 0;
+        steps = 0;
+        
+        // compute offset
+        offset = (float)(s.random[thread].nextDouble() / fitnesses.length);
+        
+        // load fitnesses but don't build distribution yet
+        fitnesses = new float[s.population.subpops[subpopulation].individuals.length];
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            fitnesses[x] = ((Individual)(s.population.subpops[subpopulation].individuals[x])).fitness.fitness();
+            if (fitnesses[x] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  SUSSelection requires that all fitness values be non-negative(offending subpopulation #" + subpopulation + ")");
+            }
+
+        // construct and optionally shuffle fitness distribution and indices
+        indices = new int[s.population.subpops[subpopulation].individuals.length];
+        for(int i=0;i<indices.length;i++) indices[i] = i;
+        if (shuffle) shuffle(s.random[thread]);
+                
+        // organize the distribution.  All zeros in fitness is fine
+        RandomChoice.organizeDistribution(fitnesses, true);
+        }
+
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        if (steps >= fitnesses.length)  // we've gone too far, clearly an error
+            {
+            state.output.warning("SUSSelection was asked for too many individuals, so we're re-shuffling.  This will give you proper results, but it might suggest an error in your code.");
+            boolean s = shuffle;
+            shuffle = true;
+            prepareToProduce(state, subpopulation, thread);  // rebuild
+            shuffle = s; // just in case
+            }
+            
+        // find the next index
+        for( /* empty */ ; lastIndex < fitnesses.length - 1; lastIndex++)
+            if ((lastIndex == 0 || offset >= fitnesses[lastIndex - 1]) && offset < fitnesses[lastIndex])
+                break;
+
+        offset += (float)(1.0 / fitnesses.length);  // update for next time
+        steps++;
+        return indices[lastIndex];
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/SelectDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/SelectDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/SelectDefaults.java	(revision 6152)
@@ -0,0 +1,34 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * SelectDefaults.java
+ * 
+ * Created: Thu Jan 20 17:14:40 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class SelectDefaults implements DefaultsForm
+    {
+    public static final String P_SELECT = "select";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_SELECT);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/SigmaScalingSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/SigmaScalingSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/SigmaScalingSelection.java	(revision 6152)
@@ -0,0 +1,143 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.util.*;
+import ec.*;
+
+/* 
+ * SigmaScalingSelection.java
+ * 
+ * Created: Fri Jun 5 2009
+ * By: Jack Compton
+ */
+
+/**
+ * Similar to FitProportionateSelection, but with adjustments to scale up/exaggerate differences in fitness for selection when true fitness values are very close to 
+ * eachother across the population. This addreses a common problem with FitProportionateSelection wherein selection approaches random selection during 
+ * late runs when fitness values do not differ by much.
+ *
+ * <p>
+ * Like FitProportionateSelection this is not appropriate for steady-state evolution.
+ * If you're not familiar with the relative advantages of 
+ * selection methods and just want a good one,
+ * use TournamentSelection instead. Not appropriate for
+ * multiobjective fitnesses.
+ *
+ * <p><b><font color=red>
+ * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
+ * </font></b>
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>scaled-fitness-floor</tt><br>
+ <font size=-1>double = some small number (defaults to 0.1)</font></td>
+ <td valign=top>(The sigma scaling formula sometimes returns negative values. This is unacceptable for fitness proportionate style selection so we must substitute 
+ the fitnessFloor (some value >= 0) for the sigma scaled fitness when that sigma scaled fitness <= fitnessFloor.)</td></tr>
+ </table> 
+ 
+
+ <p><b>Default Base</b><br>
+ select.sigma-scaling
+
+ *
+ * @author Jack Compton
+ * @version 1.0 
+ */
+
+public class SigmaScalingSelection extends FitProportionateSelection
+    {
+    /** Default base */
+    public static final String P_SIGMA_SCALING = "sigma-scaling";
+                
+    /** Scaled fitness floor */
+    // Used as a cut-off point when negative valued scaled fitnesses are encountered (negative fitness values are not compatible with fitness proportionate style selection methods)
+    public static final String P_SCALED_FITNESS_FLOOR = "scaled-fitness-floor";     
+                
+    /** Floor for sigma scaled fitnesses **/
+    private float fitnessFloor;
+                
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_SIGMA_SCALING);
+        }
+        
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+                        
+        Parameter def = defaultBase();
+                        
+        fitnessFloor = state.parameters.getFloatWithDefault(base.push(P_SCALED_FITNESS_FLOOR),def.push(P_SCALED_FITNESS_FLOOR),0.1); // default scaled fitness floor of 0.1 according to Tanese (1989)
+                        
+        if (fitnessFloor < 0)
+            {
+            //Hey! you gotta cool!  Set your cooling rate to a positive value!
+            state.output.fatal("The scaled-fitness-floor must be a non-negative value.",base.push(P_SCALED_FITNESS_FLOOR),def.push(P_SCALED_FITNESS_FLOOR));
+            }
+        }
+                
+    // completely override FitProportionateSelection.prepareToProduce
+    public void prepareToProduce(final EvolutionState s,
+        final int subpopulation,
+        final int thread)
+        {
+        // load fitnesses
+        fitnesses = new float[s.population.subpops[subpopulation].individuals.length];
+        
+        double sigma;
+        double meanFitness;
+        double meanSum = 0;
+        double squaredDeviationsSum = 0;
+                
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            fitnesses[x] = ((Individual)(s.population.subpops[subpopulation].individuals[x])).fitness.fitness();
+            if (fitnesses[x] < 0) // uh oh
+                s.output.fatal("Discovered a negative fitness value.  SigmaScalingSelection requires that all fitness values be non-negative(offending subpopulation #" + subpopulation + ")");
+            }
+                        
+        // Calculate meanFitness
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            meanSum = meanSum + fitnesses[x];
+            }
+        meanFitness = meanSum/fitnesses.length;
+                        
+        // Calculate sum of squared deviations
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            squaredDeviationsSum = squaredDeviationsSum + Math.pow(fitnesses[x]-meanFitness,2);
+            }
+        sigma = Math.sqrt(squaredDeviationsSum/(fitnesses.length-1));
+                
+        // Fill fitnesses[] with sigma scaled fitness values
+        for(int x=0;x<fitnesses.length;x++)
+            {
+            fitnesses[x] = (float)sigmaScaledValue(fitnesses[x], meanFitness, sigma, s); // adjust the fitness proportion according to sigma scaling.
+                                
+            // Sigma scaling formula can return negative values, this is unacceptable for fitness proportionate style selection...
+            // so we must substitute the fitnessFloor (some value >= 0) when a sigma scaled fitness <= fitnessFloor is encountered.
+            if (fitnesses[x] < fitnessFloor)  
+                fitnesses[x] = fitnessFloor; 
+            }
+        
+        // organize the distribution.  All zeros in fitness is fine
+        RandomChoice.organizeDistribution(fitnesses, true);
+        }
+
+    private double sigmaScaledValue(double fitness, double meanFitness, double sigma, final EvolutionState s)
+        {
+        if (sigma != 0)
+            return 1+(fitness-meanFitness)/(2*sigma);
+        return 1.0;
+        }
+        
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/select/TournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/select/TournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/select/TournamentSelection.java	(revision 6152)
@@ -0,0 +1,175 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.select;
+import ec.*;
+import ec.util.*;
+import ec.steadystate.*;
+
+/* 
+ * TournamentSelection.java
+ * 
+ * Created: Mon Aug 30 19:27:15 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Does a simple tournament selection, limited to the subpopulation it's
+ * working in at the time.
+ *
+ * <p>Tournament selection works like this: first, <i>size</i> individuals
+ * are chosen at random from the population.  Then of those individuals,
+ * the one with the best fitness is selected.  
+ * 
+ * <p><i>size</i> can also be a floating-point value between 1.0 and 2.0,
+ * exclusive of them. In this situation, two individuals are chosen at random, and
+ * the better one is selected with a probability of <i>size/2</i> 
+ *
+ * <p>Common sizes for <i>size</i> include: 2, popular in Genetic Algorithms
+ * circles, and 7, popularized in Genetic Programming by John Koza.
+ * If the size is 1, then individuals are picked entirely at random.
+ *
+ * <p>Tournament selection is so simple that it doesn't need to maintain
+ * a cache of any form, so many of the SelectionMethod methods just
+ * don't do anything at all.
+ *
+
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ Always 1.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>size</tt><br>
+ <font size=-1>float &gt;= 1</font></td>
+ <td valign=top>(the tournament size)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>pick-worst</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we pick the <i>worst</i> individual in the tournament instead of the <i>best</i>?)</td></tr>
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ select.tournament
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class TournamentSelection extends SelectionMethod implements SteadyStateBSourceForm
+    {
+    /** default base */
+    public static final String P_TOURNAMENT = "tournament";
+
+    public static final String P_PICKWORST = "pick-worst";
+
+    /** size parameter */
+    public static final String P_SIZE = "size";
+
+    /* Default size */
+    public static final int DEFAULT_SIZE = 7;
+
+    /** Base size of the tournament; this may change.  */
+    int size;
+
+    /** Probablity of picking the size plus one */
+    public double probabilityOfPickingSizePlusOne;
+    
+    /** Do we pick the worst instead of the best? */
+    public boolean pickWorst;
+
+    public Parameter defaultBase()
+        {
+        return SelectDefaults.base().push(P_TOURNAMENT);
+        }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        double val = state.parameters.getDouble(base.push(P_SIZE),def.push(P_SIZE),1.0);
+        if (val < 1.0)
+            state.output.fatal("Tournament size must be >= 1.",base.push(P_SIZE),def.push(P_SIZE));
+        else if (val == (int) val)  // easy, it's just an integer
+            {
+            size = (int) val;
+            probabilityOfPickingSizePlusOne = 0.0;
+            }
+        else
+            {
+            size = (int) Math.floor(val);
+            probabilityOfPickingSizePlusOne = val - size;  // for example, if we have 5.4, then the probability of picking *6* is 0.4
+            }
+
+        pickWorst = state.parameters.getBoolean(base.push(P_PICKWORST),def.push(P_PICKWORST),false);
+        }
+
+    /** Returns a tournament size to use, at random, based on base size and probability of picking the size plus one. */
+    public int getTournamentSizeToUse(MersenneTwisterFast random)
+        {
+        double p = probabilityOfPickingSizePlusOne;   // pulls us to under 35 bytes
+        if (p == 0.0) return size;
+        return size + (random.nextBoolean(p) ? 1 : 0);
+        }
+
+
+    /** Produces the index of a (typically uniformly distributed) randomly chosen individual
+        to fill the tournament.  <i>number</> is the position of the individual in the tournament.  */
+    public int getRandomIndividual(int number, int subpopulation, EvolutionState state, int thread)
+        {
+        Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+        return state.random[thread].nextInt(oldinds.length);
+        }
+
+    /** Returns true if *first* is a better (fitter, whatever) individual than *second*. */
+    public boolean betterThan(Individual first, Individual second, int subpopulation, EvolutionState state, int thread)
+        {
+        return first.fitness.betterThan(second.fitness);
+        }
+                
+    public int produce(final int subpopulation,
+        final EvolutionState state,
+        final int thread)
+        {
+        // pick size random individuals, then pick the best.
+        Individual[] oldinds = state.population.subpops[subpopulation].individuals;
+        int best = getRandomIndividual(0, subpopulation, state, thread);
+        
+        int s = getTournamentSizeToUse(state.random[thread]);
+                
+        if (pickWorst)
+            for (int x=1;x<s;x++)
+                {
+                int j = getRandomIndividual(x, subpopulation, state, thread);
+                if (!betterThan(oldinds[j], oldinds[best], subpopulation, state, thread))  // j is at least as bad as best
+                    best = j;
+                }
+        else
+            for (int x=1;x<s;x++)
+                {
+                int j = getRandomIndividual(x, subpopulation, state, thread);
+                if (betterThan(oldinds[j], oldinds[best], subpopulation, state, thread))  // j is better than best
+                    best = j;
+                }
+            
+        return best;
+        }
+
+    // included for SteadyState
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        { return; }
+    
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state)
+        { return; }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/README	(revision 6152)
@@ -0,0 +1,73 @@
+ec/simple/ contains typical implementations of the abstract forms found in ec/.
+Specifically, ec/simple defines generational evolution common in genetic
+algorithms, plus some simple statistics modules sufficient to do common work.
+
+The simple.params file is used by a wide range of applications and other tools
+as a basic starting point.
+
+
+
+The classes are:
+
+
+
+ec.simple.SimpleEvolutionState
+
+Performs generational evolution.
+
+
+ec.simple.SimpleEvaluator
+
+Performs simple multithreaded evaluation of populations by, for each subpopulation,
+breaking the subpopulation into N chunks of even size and handing each chunk to
+a separate thread to evaluate.
+
+
+ec.simple.SimpleBreeder
+
+Performs simple multithreaded breeding of populations by, for each subpopulation,
+breaking the subpopulation into N chunks of even size and handing each chunk to
+a separate thread to fill with individuals generated from breeding pipelines.
+SimpleBreeder also has an optional elitism function: the best M individuals in each
+subpopulation are advanced to the next generation automatically.
+
+
+ec.simple.SimpleExchanger
+ec.simple.SimpleFinisher
+
+Implementations of Exchanger and Finisher which do nothing at all.
+
+
+ec.simple.SimpleInitializer
+
+A basic initializer which simply calls populate() on the Population to cause it to
+fill itself with new individuals.  Note that certain representations have their own
+required subclass of SimpleInitializer which does other minor duties as well.
+
+
+ec.simple.SimpleProblemForm
+
+An interface which defines how basic, non-coevolutionary, single-individual
+fitness evaluation is perfomed.  Your Problem subclass will probably be required
+to implement this interface.
+
+
+ec.simple.SimpleFitness
+
+A basic single-objective fitness class which defines better fitnesses as ones which
+have higher values.  In some cases you may wish to restrict such fitness values
+to be positive.
+
+
+ec.simple.SimpleStatistics
+
+A basic Statistics object which prints out the best individual of generation, for
+each generation, plus the best individual of run at the end.
+
+
+ec.simple.SimpleShortStatistics
+
+A basic Statistics object which prints out, one line per generation, a variety of
+easily parsed statistical information about that generation's results.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleBreeder.java	(revision 6152)
@@ -0,0 +1,275 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.Initializer;
+import ec.Individual;
+import ec.BreedingPipeline;
+import ec.Breeder;
+import ec.EvolutionState;
+import ec.Population;
+import ec.util.Parameter;
+import ec.util.*;
+
+/* 
+ * SimpleBreeder.java
+ * 
+ * Created: Tue Aug 10 21:00:11 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Breeds each subpopulation separately, with no inter-population exchange,
+ * and using a generational approach.  A SimpleBreeder may have multiple
+ * threads; it divvys up a subpopulation into chunks and hands one chunk
+ * to each thread to populate.  One array of BreedingPipelines is obtained
+ * from a population's Species for each operating breeding thread.
+ *
+ * Prior to breeding a subpopulation, a SimpleBreeder may first fill part of the new
+ * subpopulation up with the best <i>n</i> individuals from the old subpopulation.
+ * By default, <i>n</i> is 0 for each subpopulation (that is, this "elitism"
+ * is not done).  The elitist step is performed by a single thread.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt><i>base</i>.elite.<i>i</i></tt><br>
+ <font size=-1>int >= 0 (default=0)</font></td>
+ <td valign=top>(the number of elitist individuals for subpopulation <i>i</i>)</td></tr>
+ <tr><td valign=top><tt><i>base</i>.reevalate-elites.<i>i</i></tt><br>
+ <font size=-1>boolean (default = false)</font></td>
+ <td valign=top>(should we reevaluate the elites of subpopulation <i>i</i> each generation?)</td></tr>
+ </table>
+ *
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleBreeder extends Breeder
+    {
+    public static final String P_ELITE = "elite";
+    public static final String P_REEVALUATE_ELITES = "reevalate-elites";
+    /** An array[subpop] of the number of elites to keep for that subpopulation */
+    public int[] elite;
+    public boolean[] reevaluateElites;
+
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        Parameter p = new Parameter(Initializer.P_POP).push(Population.P_SIZE);
+        int size = state.parameters.getInt(p,null,1);  // if size is wrong, we'll let Population complain about it -- for us, we'll just make 0-sized arrays and drop out.
+
+        elite = new int[size];
+        reevaluateElites = new boolean[size];
+                
+        for(int x=0;x<size;x++)
+            {
+            elite[x] = state.parameters.getIntWithDefault(base.push(P_ELITE).push(""+x),null,0);
+            if (elite[x]<0) state.output.error("The number of elites for subpopulation " + x + " must be >= 0",base.push(P_ELITE).push(""+x));
+            reevaluateElites[x] = state.parameters.getBoolean(base.push(P_REEVALUATE_ELITES).push(""+x),null,false);
+            }
+
+        state.output.exitIfErrors();
+        }
+
+    /** Elites are often stored in the top part of the subpopulation; this function returns what
+        part of the subpopulation contains individuals to replace with newly-bred ones
+        (up to but not including the elites). */
+    public int computeSubpopulationLength(Population newpop, int subpopulation)
+        {
+        return newpop.subpops[subpopulation].individuals.length - elite[subpopulation];
+        }
+
+    /** A simple breeder that doesn't attempt to do any cross-
+        population breeding.  Basically it applies pipelines,
+        one per thread, to various subchunks of a new population. */
+    public Population breedPopulation(EvolutionState state) 
+        {
+        int numinds[][] = 
+            new int[state.breedthreads][state.population.subpops.length];
+        int from[][] = 
+            new int[state.breedthreads][state.population.subpops.length];
+
+        Population newpop = (Population) state.population.emptyClone();
+        
+        // load elites into top of newpop
+        loadElites(state, newpop);
+
+        for(int y=0;y<state.breedthreads;y++)
+            for(int x=0;x<state.population.subpops.length;x++)
+                {
+                // the number of individuals we need to breed
+                int length = computeSubpopulationLength(newpop, x);
+                // the size of each breeding chunk except the last one
+                int firstBreedChunkSizes = length/state.breedthreads;
+                // the size of the last breeding chunk
+                int lastBreedChunkSize = 
+                    firstBreedChunkSizes + length - firstBreedChunkSizes * (state.breedthreads);
+                
+                // figure numinds
+                if (y < state.breedthreads-1) // not the last one
+                    numinds[y][x] = firstBreedChunkSizes;
+                else // the last one
+                    numinds[y][x] = lastBreedChunkSize;
+                
+                // figure from
+                from[y][x] = (firstBreedChunkSizes * y);
+                }
+            
+        if (state.breedthreads==1)
+            {
+            breedPopChunk(newpop,state,numinds[0],from[0],0);
+            }
+        else
+            {
+            Thread[] t = new Thread[state.breedthreads];
+                
+            // start up the threads
+            for(int y=0;y<state.breedthreads;y++)
+                {
+                SimpleBreederThread r = new SimpleBreederThread();
+                r.threadnum = y;
+                r.newpop = newpop;
+                r.numinds = numinds[y];
+                r.from = from[y];
+                r.me = this;
+                r.state = state;
+                t[y] = new Thread(r);
+                t[y].start();
+                }
+                
+            // gather the threads
+            for(int y=0;y<state.breedthreads;y++) try
+                                                      {
+                                                      t[y].join();
+                                                      }
+                catch(InterruptedException e)
+                    {
+                    state.output.fatal("Whoa! The main breeding thread got interrupted!  Dying...");
+                    }
+            }
+        return newpop;
+        }
+
+
+    /** A private helper function for breedPopulation which breeds a chunk
+        of individuals in a subpopulation for a given thread.
+        Although this method is declared
+        public (for the benefit of a private helper class in this file),
+        you should not call it. */
+
+    protected void breedPopChunk(Population newpop, EvolutionState state,
+        int[] numinds, int[] from, int threadnum) 
+        {
+        //System.out.println("Breeding: " + numinds[0] + " Starting at: " + from[0]);
+        for(int subpop=0;subpop<newpop.subpops.length;subpop++)
+            {
+            BreedingPipeline bp = (BreedingPipeline)newpop.subpops[subpop].
+                species.pipe_prototype.clone();
+                
+            // check to make sure that the breeding pipeline produces
+            // the right kind of individuals.  Don't want a mistake there! :-)
+            int x;
+            if (!bp.produces(state,newpop,subpop,threadnum))
+                state.output.fatal("The Breeding Pipeline of subpopulation " + subpop + " does not produce individuals of the expected species " + newpop.subpops[subpop].species.getClass().getName() + " or fitness " + newpop.subpops[subpop].species.f_prototype );
+            bp.prepareToProduce(state,subpop,threadnum);
+                
+            // start breedin'!
+                
+            x=from[subpop];
+            int upperbound = from[subpop]+numinds[subpop];
+            while(x<upperbound)
+                x += bp.produce(1,upperbound-x,x,subpop,
+                    newpop.subpops[subpop].individuals,
+                    state,threadnum);
+            if (x>upperbound) // uh oh!  Someone blew it!
+                state.output.fatal("Whoa!  A breeding pipeline overwrote the space of another pipeline in subpopulation " + subpop + ".  You need to check your breeding pipeline code (in produce() ).");
+
+            bp.finishProducing(state,subpop,threadnum);
+            }
+        }
+    
+    class EliteComparator implements SortComparatorL
+        {
+        Individual[] inds;
+        public EliteComparator(Individual[] inds) {super(); this.inds = inds;}
+        public boolean lt(long a, long b)
+            { return inds[(int)b].fitness.betterThan(inds[(int)a].fitness); }
+        public boolean gt(long a, long b)
+            { return inds[(int)a].fitness.betterThan(inds[(int)b].fitness); }
+        }
+
+    protected void unmarkElitesEvaluated(Population newpop)
+        {
+        for(int sub=0;sub<newpop.subpops.length;sub++)
+            for(int e=0; e < elite[sub]; e++)
+                {
+                int len = newpop.subpops[sub].individuals.length;
+                if (reevaluateElites[sub])
+                    newpop.subpops[sub].individuals[len - elite[sub]].evaluated = false;
+                }
+        }
+
+    /** A private helper function for breedPopulation which loads elites into
+        a subpopulation. */
+
+    protected void loadElites(EvolutionState state, Population newpop)
+        {
+        // are our elites small enough?
+        for(int x=0;x<state.population.subpops.length;x++)
+            if (elite[x]>state.population.subpops[x].individuals.length)
+                state.output.error("The number of elites for subpopulation " + x + " exceeds the actual size of the subpopulation", new Parameter(EvolutionState.P_BREEDER).push(P_ELITE).push(""+x));
+        state.output.exitIfErrors();
+
+        // we assume that we're only grabbing a small number (say <10%), so
+        // it's not being done multithreaded
+        for(int sub=0;sub<state.population.subpops.length;sub++) 
+            // if the number of elites is 1, then we handle this by just finding the best one.
+            if (elite[sub]==1)
+                {
+                int best = 0;
+                Individual[] oldinds = state.population.subpops[sub].individuals;
+                for(int x=1;x<oldinds.length;x++)
+                    if (oldinds[x].fitness.betterThan(oldinds[best].fitness))
+                        best = x;
+                Individual[] inds = newpop.subpops[sub].individuals;
+                inds[inds.length-1] = (Individual)(oldinds[best].clone());
+                }
+            else if (elite[sub]>0)  // we'll need to sort
+                {
+                int[] orderedPop = new int[state.population.subpops[sub].individuals.length];
+                for(int x=0;x<state.population.subpops[sub].individuals.length;x++) orderedPop[x] = x;
+
+                // sort the best so far where "<" means "not as fit as"
+                QuickSort.qsort(orderedPop, new EliteComparator(state.population.subpops[sub].individuals));
+                // load the top N individuals
+
+                Individual[] inds = newpop.subpops[sub].individuals;
+                Individual[] oldinds = state.population.subpops[sub].individuals;
+                for(int x=inds.length-elite[sub];x<inds.length;x++)
+                    inds[x] = (Individual)(oldinds[orderedPop[x]].clone());
+                }
+                
+        // optionally force reevaluation
+        unmarkElitesEvaluated(newpop);
+        }
+    }
+
+
+/** A private helper class for implementing multithreaded breeding */
+class SimpleBreederThread implements Runnable
+    {
+    Population newpop;
+    public int[] numinds;
+    public int[] from;
+    public SimpleBreeder me;
+    public EvolutionState state;
+    public int threadnum;
+    public void run()
+        {
+        me.breedPopChunk(newpop,state,numinds,from,threadnum);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleDefaults.java	(revision 6152)
@@ -0,0 +1,33 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.util.Parameter;
+import ec.*;
+
+/* 
+ * SimpleDefaults.java
+ * 
+ * Created: Thu Jan 20 17:19:12 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class SimpleDefaults implements DefaultsForm 
+    {
+    public static final String P_SIMPLE = "simple";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_SIMPLE);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleEvaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleEvaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleEvaluator.java	(revision 6152)
@@ -0,0 +1,159 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.Evaluator;
+import ec.EvolutionState;
+import ec.util.Parameter;
+import ec.Individual;
+
+/* 
+ * SimpleEvaluator.java
+ * 
+ * Created: Wed Aug 18 21:31:18 1999
+ * By: Sean Luke
+ */
+
+/**
+ * The SimpleEvaluator is a simple, non-coevolved generational evaluator which
+ * evaluates every single member of every subpopulation individually in its
+ * own problem space.  One Problem instance is cloned from p_problem for
+ * each evaluating thread.  The Problem must implement SimpleProblemForm.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleEvaluator extends Evaluator
+    {
+    // checks to make sure that the Problem implements SimpleProblemForm
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        if (!(p_problem instanceof SimpleProblemForm))
+            state.output.fatal("" + this.getClass() + " used, but the Problem is not of SimpleProblemForm",
+                base.push(P_PROBLEM));
+        }
+    
+    /** A simple evaluator that doesn't do any coevolutionary
+        evaluation.  Basically it applies evaluation pipelines,
+        one per thread, to various subchunks of a new population. */
+    public void evaluatePopulation(final EvolutionState state)
+        {
+        int numinds[][] = 
+            new int[state.evalthreads][state.population.subpops.length];
+        int from[][] = 
+            new int[state.evalthreads][state.population.subpops.length];
+        
+        for(int y=0;y<state.evalthreads;y++)
+            for(int x=0;x<state.population.subpops.length;x++)
+                {
+                // figure numinds
+                if (y<state.evalthreads-1) // not last one
+                    numinds[y][x]=
+                        state.population.subpops[x].individuals.length/
+                        state.evalthreads;
+                else // in case we're slightly off in division
+                    numinds[y][x]=
+                        state.population.subpops[x].individuals.length/
+                        state.evalthreads +
+                        
+                        (state.population.subpops[x].individuals.length -
+                            (state.population.subpops[x].individuals.length /
+                            state.evalthreads)  // note integer division
+                        *state.evalthreads);                    
+
+                // figure from
+                from[y][x]=
+                    (state.population.subpops[x].individuals.length/
+                    state.evalthreads) * y;
+                }
+
+        if (state.evalthreads==1)
+            evalPopChunk(state,numinds[0],from[0],0,(SimpleProblemForm)(p_problem.clone()));  
+        
+        else
+            {
+            Thread[] t = new Thread[state.evalthreads];
+            
+            // start up the threads
+            for(int y=0;y<state.evalthreads;y++)
+                {
+                SimpleEvaluatorThread r = new SimpleEvaluatorThread();
+                r.threadnum = y;
+                r.numinds = numinds[y];
+                r.from = from[y];
+                r.me = this;
+                r.state = state;
+                r.p = (SimpleProblemForm)(p_problem.clone());
+                t[y] = new Thread(r);
+                t[y].start();
+                }
+
+            // gather the threads
+            for(int y=0;y<state.evalthreads;y++) try
+                                                     {
+                                                     t[y].join();
+                                                     }
+                catch(InterruptedException e)
+                    {
+                    state.output.fatal("Whoa! The main evaluation thread got interrupted!  Dying...");
+                    }
+
+            }
+        }
+
+    /** A private helper function for evaluatePopulation which evaluates a chunk
+        of individuals in a subpopulation for a given thread.
+        Although this method is declared
+        public (for the benefit of a private helper class in this file),
+        you should not call it. */
+
+    protected void evalPopChunk(EvolutionState state, int[] numinds, int[] from,
+        int threadnum, SimpleProblemForm p)
+        {
+        ((ec.Problem)p).prepareToEvaluate(state,threadnum);
+        
+        for(int pop=0;pop<state.population.subpops.length;pop++)
+            {
+            // start evaluatin'!
+            int upperbound = from[pop]+numinds[pop];
+            for (int x=from[pop];x<upperbound;x++)
+                {
+                p.evaluate(state,state.population.subpops[pop].individuals[x], pop, threadnum);
+                }
+            }
+        ((ec.Problem)p).finishEvaluating(state,threadnum);
+        }
+    
+    /** The SimpleEvaluator determines that a run is complete by asking
+        each individual in each population if he's optimal; if he 
+        finds an individual somewhere that's optimal,
+        he signals that the run is complete. */
+    public boolean runComplete(final EvolutionState state)
+        {
+        for(int x = 0;x<state.population.subpops.length;x++)
+            for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                if (state.population.subpops[x].
+                    individuals[y].fitness.isIdealFitness())
+                    return true;
+        return false;
+        }
+    }
+
+/** A private helper class for implementing multithreaded evaluation */
+class SimpleEvaluatorThread implements Runnable
+    {
+    public int[] numinds;
+    public int[] from;
+    public SimpleEvaluator me;
+    public EvolutionState state;
+    public int threadnum;
+    public SimpleProblemForm p;
+    public synchronized void run() 
+        { me.evalPopChunk(state,numinds,from,threadnum,p); }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleEvolutionState.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleEvolutionState.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleEvolutionState.java	(revision 6152)
@@ -0,0 +1,155 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.*;
+import ec.util.Checkpoint;
+
+/* 
+ * SimpleEvolutionState.java
+ * 
+ * Created: Tue Aug 10 22:14:46 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A SimpleEvolutionState is an EvolutionState which implements a simple form
+ * of generational evolution.
+ *
+ * <p>First, all the individuals in the population are created.
+ * <b>(A)</b>Then all individuals in the population are evaluated.
+ * Then the population is replaced in its entirety with a new population
+ * of individuals bred from the old population.  Goto <b>(A)</b>.
+ *
+ * <p>Evolution stops when an ideal individual is found (if quitOnRunComplete
+ * is set to true), or when the number of generations (loops of <b>(A)</b>)
+ * exceeds the parameter value numGenerations.  Each generation the system
+ * will perform garbage collection and checkpointing, if the appropriate
+ * parameters were set.
+ *
+ * <p>This approach can be readily used for
+ * most applications of Genetic Algorithms and Genetic Programming.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleEvolutionState extends EvolutionState
+    {
+
+    /**
+     * 
+     */
+    public void startFresh() 
+        {
+        output.message("Setting up");
+        setup(this,null);  // a garbage Parameter
+
+        // POPULATION INITIALIZATION
+        output.message("Initializing Generation 0");
+        statistics.preInitializationStatistics(this);
+        population = initializer.initialPopulation(this, 0); // unthreaded
+        statistics.postInitializationStatistics(this);
+
+        // INITIALIZE CONTACTS -- done after initialization to allow
+        // a hook for the user to do things in Initializer before
+        // an attempt is made to connect to island models etc.
+        exchanger.initializeContacts(this);
+        evaluator.initializeContacts(this);
+        }
+
+    /**
+     * @return
+     * @throws InternalError
+     */
+    public int evolve()
+        {
+        if (generation > 0) 
+            output.message("Generation " + generation);
+
+        // EVALUATION
+        statistics.preEvaluationStatistics(this);
+        evaluator.evaluatePopulation(this);
+        statistics.postEvaluationStatistics(this);
+
+        // SHOULD WE QUIT?
+        if (evaluator.runComplete(this) && quitOnRunComplete)
+            {
+            output.message("Found Ideal Individual");
+            return R_SUCCESS;
+            }
+
+        // SHOULD WE QUIT?
+        if (generation == numGenerations-1)
+            {
+            return R_FAILURE;
+            }
+
+        // PRE-BREEDING EXCHANGING
+        statistics.prePreBreedingExchangeStatistics(this);
+        population = exchanger.preBreedingExchangePopulation(this);
+        statistics.postPreBreedingExchangeStatistics(this);
+
+        String exchangerWantsToShutdown = exchanger.runComplete(this);
+        if (exchangerWantsToShutdown!=null)
+            { 
+            output.message(exchangerWantsToShutdown);
+            /*
+             * Don't really know what to return here.  The only place I could
+             * find where runComplete ever returns non-null is 
+             * IslandExchange.  However, that can return non-null whether or
+             * not the ideal individual was found (for example, if there was
+             * a communication error with the server).
+             * 
+             * Since the original version of this code didn't care, and the
+             * result was initialized to R_SUCCESS before the while loop, I'm 
+             * just going to return R_SUCCESS here. 
+             */
+            
+            return R_SUCCESS;
+            }
+
+        // BREEDING
+        statistics.preBreedingStatistics(this);
+
+        population = breeder.breedPopulation(this);
+        
+        // POST-BREEDING EXCHANGING
+        statistics.postBreedingStatistics(this);
+            
+        // POST-BREEDING EXCHANGING
+        statistics.prePostBreedingExchangeStatistics(this);
+        population = exchanger.postBreedingExchangePopulation(this);
+        statistics.postPostBreedingExchangeStatistics(this);
+
+        // INCREMENT GENERATION AND CHECKPOINT
+        generation++;
+        if (checkpoint && generation%checkpointModulo == 0) 
+            {
+            output.message("Checkpointing");
+            statistics.preCheckpointStatistics(this);
+            Checkpoint.setCheckpoint(this);
+            statistics.postCheckpointStatistics(this);
+            }
+
+        return R_NOTDONE;
+        }
+
+    /**
+     * @param result
+     */
+    public void finish(int result) 
+        {
+        //Output.message("Finishing");
+        /* finish up -- we completed. */
+        statistics.finalStatistics(this,result);
+        finisher.finishPopulation(this,result);
+        exchanger.closeContacts(this,result);
+        evaluator.closeContacts(this,result);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleExchanger.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleExchanger.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleExchanger.java	(revision 6152)
@@ -0,0 +1,80 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.EvolutionState;
+import ec.Population;
+import ec.Exchanger;
+import ec.util.Parameter;
+import ec.steadystate.*;
+
+/* 
+ * SimpleExchanger.java
+ * 
+ * Created: Tue Aug 10 21:59:17 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A SimpleExchanger is a default Exchanger which, well, doesn't do anything.
+ * Most applications don't need Exchanger facilities; this simple version
+ * will suffice.
+ * 
+ * <p>The SimpleExchanger implements the SteadyStateExchangerForm, mostly
+ * because it does nothing with individuals.  For this reason, it is final;
+ * implement your own Exchanger if you need to do something more advanced.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class SimpleExchanger extends Exchanger implements SteadyStateExchangerForm
+    {
+    public void setup(final EvolutionState state, final Parameter base) { }
+
+    /** Doesn't do anything. */
+    public void initializeContacts(final EvolutionState state)
+        {
+        // don't care
+        return;
+        }
+
+    /** Doesn't do anything. */
+    public void reinitializeContacts(final EvolutionState state)
+        {
+        // don't care
+        return;
+        }
+
+    /** Simply returns state.population. */
+    public Population preBreedingExchangePopulation(final EvolutionState state)
+        {
+        // don't care
+        return state.population;
+        }
+
+    /** Simply returns state.population. */
+    public Population postBreedingExchangePopulation(final EvolutionState state)
+        {
+        // don't care
+        return state.population;
+        }
+
+    /** Doesn't do anything. */
+    public void closeContacts(final EvolutionState state, final int result)
+        {
+        // don't care
+        return;
+        }
+
+    /** Always returns null */
+    public String runComplete(final EvolutionState state)
+        {
+        return null;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleFinisher.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleFinisher.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleFinisher.java	(revision 6152)
@@ -0,0 +1,41 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.Finisher;
+import ec.EvolutionState;
+import ec.util.Parameter;
+
+/* 
+ * SimpleFinisher.java
+ * 
+ * Created: Tue Aug 10 21:09:18 1999
+ * By: Sean Luke
+ */
+
+/**
+ * SimpleFinisher is a default Finisher which doesn't do anything.  Most
+ * application's don't need Finisher facilities, so this version will work
+ * fine.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleFinisher extends Finisher
+    {
+
+    public void setup(final EvolutionState state, final Parameter base) { }
+
+
+    /** Doesn't do anything. */
+    public void finishPopulation(final EvolutionState state, final int result)
+        {
+        // don't care
+        return;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleFitness.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleFitness.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleFitness.java	(revision 6152)
@@ -0,0 +1,161 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.Fitness;
+import ec.EvolutionState;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * SimpleFitness.java
+ *
+ * Created: Tue Aug 10 20:10:42 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A simple default fitness, consisting of a single floating-point value
+ * where fitness A is superior to fitness B if and only if A > B.  
+ * Fitness values may range from (-infinity,infinity) exclusive -- that is,
+ * you may not have infinite fitnesses.  
+ *
+ * <p>Some kinds of selection methods require a more stringent definition of
+ * fitness.  For example, FitProportionateSelection requires that fitnesses
+ * be non-negative (since it must place them into a proportionate distribution).
+ * You may wish to restrict yourself to values in [0,1] or [0,infinity) in
+ * such cases.
+ *
+ <p><b>Default Base</b><br>
+ simple.fitness
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class SimpleFitness extends Fitness
+    {
+    protected float fitness;
+    protected boolean isIdeal;
+
+    public Parameter defaultBase()
+        {
+        return SimpleDefaults.base().push(P_FITNESS);
+        }
+
+    /**
+       Deprecated -- now redefined to set the fitness but ALWAYS say that it's not ideal.
+       If you need to specify that it's ideal, you should use the new function 
+       setFitness(final EvolutionState state, float _f, boolean _isIdeal).
+       @deprecated
+    */
+    public void setFitness(final EvolutionState state, float _f)
+        {
+        setFitness(state,_f,false);
+        }
+        
+    public void setFitness(final EvolutionState state, float _f, boolean _isIdeal)
+        {
+        // we now allow f to be *any* value, positive or negative
+        if (_f == Float.POSITIVE_INFINITY || _f == Float.NEGATIVE_INFINITY || Float.isNaN(_f))
+            {
+            state.output.warning("Bad fitness: " + _f + ", setting to 0.");
+            fitness = 0;
+            }
+        else fitness = _f;
+        isIdeal = _isIdeal;
+        }
+
+    public float fitness()
+        {
+        return fitness;
+        }
+
+    public void setup(final EvolutionState state, Parameter base) 
+        {
+        super.setup(state,base);  // unnecessary but what the heck
+        }
+
+    public boolean isIdealFitness()
+        {
+        return isIdeal;
+        }
+
+    public boolean equivalentTo(final Fitness _fitness)
+        {
+        return _fitness.fitness() == fitness();
+        }
+
+    public boolean betterThan(final Fitness _fitness)
+        {
+        return _fitness.fitness() < fitness();
+        }
+
+    public String fitnessToString()
+        {
+        return FITNESS_PREAMBLE + Code.encode(fitness());
+        }
+        
+    public String fitnessToStringForHumans()
+        {
+        return FITNESS_PREAMBLE + fitness();
+        }
+
+    /** Presently does not decode the fact that the fitness is ideal or not */
+    public void readFitness(final EvolutionState state, 
+        final LineNumberReader reader)
+        throws IOException
+        {
+        setFitness(state, Code.readFloatWithPreamble(FITNESS_PREAMBLE, state, reader));
+
+/*
+  int linenumber = reader.getLineNumber();
+  String s = reader.readLine();
+  if (s==null || s.length() < FITNESS_PREAMBLE.length()) // uh oh
+  state.output.fatal("Reading Line " + linenumber + ": " +
+  "Bad Fitness.");
+  DecodeReturn d = new DecodeReturn(s, FITNESS_PREAMBLE.length());
+  Code.decode(d);
+  if (d.type!=DecodeReturn.T_FLOAT)
+  state.output.fatal("Reading Line " + linenumber + ": " +
+  "Bad Fitness.");
+  setFitness(state,(float)d.d,false);
+*/
+        }
+
+    public void writeFitness(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeFloat(fitness);
+        dataOutput.writeBoolean(isIdeal);
+        }
+
+    public void readFitness(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        fitness = dataInput.readFloat();
+        isIdeal = dataInput.readBoolean();
+        }
+
+    public void setToMeanOf(EvolutionState state, Fitness[] fitnesses)
+        {
+        // this is not numerically stable.  Perhaps we should have a numerically stable algorithm for sums
+        // we're presuming it's not a very large number of elements, so it's probably not a big deal,
+        // since this function is meant to be used mostly for gathering trials together.
+        double f = 0;
+        boolean ideal = true;
+        for(int i = 0; i < fitnesses.length; i++)
+            {
+            SimpleFitness fit = (SimpleFitness)(fitnesses[i]);
+            f += fit.fitness;
+            ideal = ideal && fit.isIdeal;
+            }
+        f /= fitnesses.length;
+        fitness = (float)f;
+        isIdeal = ideal;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleInitializer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleInitializer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleInitializer.java	(revision 6152)
@@ -0,0 +1,56 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.Initializer;
+import ec.EvolutionState;
+import ec.util.Parameter;
+import ec.Population;
+
+/* 
+ * SimpleInitializer.java
+ * 
+ * Created: Tue Aug 10 21:07:42 1999
+ * By: Sean Luke
+ */
+
+/**
+ * SimpleInitializer is a default Initializer which initializes a Population
+ * by calling the Population's populate(...) method.  For most applications,
+ * this should suffice.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleInitializer extends Initializer
+    {
+    public void setup(final EvolutionState state, final Parameter base)
+        { 
+        }
+
+    /** Creates, populates, and returns a new population by making a new
+        population, calling setup(...) on it, and calling populate(...)
+        on it, assuming an unthreaded environment (thread 0).
+        Obviously, this is an expensive method.  It should only
+        be called once typically in a run. */
+
+    public Population initialPopulation(final EvolutionState state, int thread)
+        {
+        Population p = setupPopulation(state, thread); 
+        p.populate(state, thread);
+        return p;
+        }
+                
+    public Population setupPopulation(final EvolutionState state, int thread)
+        {
+        Parameter base = new Parameter(P_POP);
+        Population p = (Population) state.parameters.getInstanceForParameterEq(base,null,Population.class);  // Population.class is fine
+        p.setup(state,base);
+        return p;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleProblemForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleProblemForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleProblemForm.java	(revision 6152)
@@ -0,0 +1,51 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.*;
+
+/* 
+ * SimpleProblemForm.java
+ * 
+ * Created: Tue Mar  6 11:33:37 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * SimpleProblemForm is an interface which defines methods
+ * for Problems to implement simple, single-individual (non-coevolutionary)
+ * evaluation.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface SimpleProblemForm
+    {
+    /** Evaluates the individual in ind, if necessary (perhaps
+        not evaluating them if their evaluated flags are true),
+        and sets their fitness appropriately. 
+    */
+
+    public void evaluate(final EvolutionState state,
+        final Individual ind,
+        final int subpopulation,
+        final int threadnum);
+
+    /** "Reevaluates" an individual,
+        for the purpose of printing out
+        interesting facts about the individual in the context of the
+        Problem, and logs the results.  This might be called to print out 
+        facts about the best individual in the population, for example.  */
+    
+    public void describe(
+        final EvolutionState state, 
+        final Individual ind, 
+        final int subpopulation,
+        final int threadnum,
+        final int log);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleShortStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleShortStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleShortStatistics.java	(revision 6152)
@@ -0,0 +1,265 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.*;
+import java.io.*;
+import ec.util.*;
+import ec.eval.*;
+
+/* 
+ * SimpleShortStatistics.java
+ * 
+ * Created: Tue Jun 19 15:08:29 EDT 2001
+ * By: Sean Luke
+ */
+
+/**
+ * A Simple-style statistics generator, intended to be easily parseable with
+ * awk or other Unix tools.  Prints fitness information,
+ * one generation (or pseudo-generation) per line.
+ * If gather-full is true, then timing information, number of nodes
+ * and depths of trees, etc. are also given.  No final statistics information
+ * is given.
+ *
+ * <p> Each line represents a single generation.  
+ * The first items on a line are always:
+ <ul>
+ <li> The generation number
+ <li> (if gather-full) how long initialization took in milliseconds, or how long the previous generation took to breed to form this generation
+ <li> (if gather-full) how many bytes initialization took, or how how many bytes the previous generation took to breed to form this generation.  This utilization is an approximation only, made by the Java system, and does not take into consideration the possibility of garbage collection (which might make the number negative).
+ <li> (if gather-full) How long evaluation took in milliseconds this generation
+ <li> (if gather-full) how many bytes evaluation took this generation.  This utilization is an approximation only, made by the Java system, and does not take into consideration the possibility of garbage collection (which might make the number negative).
+ </ul>
+
+ <p>Then the following items appear, per subpopulation:
+ <ul>
+ <li> (if gather-full) The average size of an individual this generation
+ <li> (if gather-full) The average size of an individual so far in the run
+ <li> The mean fitness of the subpopulation this generation
+ <li> The best fitness of the subpopulation this generation
+ <li> The best fitness of the subpopulation so far in the run
+ <li> (if gather-full) The size of the best individual this generation
+ <li> (if gather-full) The size of the best individual so far in the run
+ </ul>
+
+ Compressed files will be overridden on restart from checkpoint; uncompressed files will be 
+ appended on restart.
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>gzip</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether or not to compress the file (.gz suffix added)</td></tr>
+ <tr><td valign=top><i>base.</i><tt>file</tt><br>
+ <font size=-1>String (a filename), or nonexistant (signifies stdout)</font></td>
+ <td valign=top>(the log for statistics)</td></tr>
+ <tr><td valign=top><i>base</i>.<tt>gather-full</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(should we full statistics on individuals (will run slower, though the slowness is due to off-line processing that won't mess up timings)</td></tr>
+ </table>
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleShortStatistics extends Statistics // implements ProvidesBestSoFar
+    {
+    public Individual[] getBestSoFar() { return best_of_run; }
+        
+    /** log file parameter */
+    public static final String P_STATISTICS_FILE = "file";
+
+    /** The Statistics' log */
+    public int statisticslog;
+
+    /** compress? */
+    public static final String P_COMPRESS = "gzip";
+
+    public static final String P_FULL = "gather-full";
+
+    public boolean doFull;
+
+    public Individual[] best_of_run;
+    public long lengths[];
+
+    // timings
+    public long lastTime;
+    
+    // usage
+    public long lastUsage;
+    
+    public SimpleShortStatistics() { /*best_of_run = null;*/ statisticslog = 0; /* stdout */ }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        File statisticsFile = state.parameters.getFile(
+            base.push(P_STATISTICS_FILE),null);
+
+        if (statisticsFile!=null) try
+                                      {
+                                      statisticslog = state.output.addLog(statisticsFile,
+                                          !state.parameters.getBoolean(base.push(P_COMPRESS),null,false),
+                                          state.parameters.getBoolean(base.push(P_COMPRESS),null,false));
+                                      }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + statisticsFile + ":\n" + i);
+                }
+        doFull = state.parameters.getBoolean(base.push(P_FULL),null,false);
+        }
+
+
+    public void preInitializationStatistics(final EvolutionState state)
+        {
+        super.preInitializationStatistics(state);
+        
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+    
+    public void postInitializationStatistics(final EvolutionState state)
+        {
+        super.postInitializationStatistics(state);
+        
+        // set up our best_of_run array -- can't do this in setup, because
+        // we don't know if the number of subpopulations has been determined yet
+        best_of_run = new Individual[state.population.subpops.length];
+        
+        // print out our generation number
+        state.output.print("0 ", statisticslog);
+
+        // gather timings       
+        if (doFull)
+            {
+            lengths = new long[state.population.subpops.length];
+            for(int x=0;x<lengths.length;x++) lengths[x] = 0;
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();          
+            state.output.print("" + (System.currentTimeMillis()-lastTime) + " ",  statisticslog);
+            state.output.print("" + (curU-lastUsage) + " ",  statisticslog);            
+            }
+        }
+
+    public void preBreedingStatistics(final EvolutionState state)
+        {
+        super.preBreedingStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    public void postBreedingStatistics(final EvolutionState state) 
+        {
+        super.postBreedingStatistics(state);
+        state.output.print("" + (state.generation + 1) + " ", statisticslog); // 1 because we're putting the breeding info on the same line as the generation it *produces*, and the generation number is increased *after* breeding occurs, and statistics for it
+
+        // gather timings
+        if (doFull)
+            {
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();          
+            state.output.print("" + (System.currentTimeMillis()-lastTime) + " ",  statisticslog);
+            state.output.print("" + (curU-lastUsage) + " ",  statisticslog);            
+            }
+        }
+
+    public void preEvaluationStatistics(final EvolutionState state)
+        {
+        super.preEvaluationStatistics(state);
+        if (doFull) 
+            {
+            Runtime r = Runtime.getRuntime();
+            lastTime = System.currentTimeMillis();
+            lastUsage = r.totalMemory() - r.freeMemory();
+            }
+        }
+
+    /** Prints out the statistics, but does not end with a println --
+        this lets overriding methods print additional statistics on the same line */
+    protected void _postEvaluationStatistics(final EvolutionState state)
+        {
+        // gather timings
+        if (doFull)
+            {
+            Runtime r = Runtime.getRuntime();
+            long curU =  r.totalMemory() - r.freeMemory();          
+            state.output.print("" + (System.currentTimeMillis()-lastTime) + " ",  statisticslog);
+            state.output.print("" + (curU-lastUsage) + " ",  statisticslog);            
+            }
+        
+
+        long lengthPerGen = 0;
+        Individual[] best_i = new Individual[state.population.subpops.length];
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            if (doFull)
+                {
+                lengthPerGen = 0;
+                for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                    {
+                    long size = state.population.subpops[x].individuals[y].size();
+                    lengthPerGen += size;
+                    lengths[x] += size;
+                    }
+
+                state.output.print("" + ((double)lengthPerGen)/state.population.subpops[x].individuals.length + " ",  statisticslog);
+
+                state.output.print("" + ((double)lengths[x])/(state.population.subpops[x].individuals.length * (state.generation + 1)) + " ",  statisticslog);
+                }
+                    
+            // fitness information
+            double meanFitness = 0.0;
+
+            for(int y=0;y<state.population.subpops[x].individuals.length;y++)
+                {
+                // best individual
+                if (best_i[x]==null ||
+                    state.population.subpops[x].individuals[y].fitness.betterThan(best_i[x].fitness))
+                    best_i[x] = state.population.subpops[x].individuals[y];
+
+                // mean fitness for population
+                meanFitness += state.population.subpops[x].individuals[y].fitness.fitness();
+                }
+            
+            // compute fitness stats
+            meanFitness /= state.population.subpops[x].individuals.length;
+            state.output.print("" + meanFitness + " " + best_i[x].fitness.fitness() + " ",
+                statisticslog);
+
+            // now test to see if it's the new best_of_run[x]
+            if (best_of_run[x]==null || best_i[x].fitness.betterThan(best_of_run[x].fitness))
+                best_of_run[x] = (Individual)(best_i[x].clone());
+            
+            state.output.print("" + best_of_run[x].fitness.fitness() + " ",
+                statisticslog);
+
+            if( doFull )
+                {
+                state.output.print("" + (double)(best_i[x].size()) + " " +
+                    (double)(best_of_run[x].size()) + " ",
+                    statisticslog);
+                }
+            }
+        // we're done!
+        }
+
+    public void postEvaluationStatistics(final EvolutionState state)
+        {
+        super.postEvaluationStatistics(state);
+        _postEvaluationStatistics(state);
+        state.output.println("", statisticslog);
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleStatistics.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleStatistics.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/SimpleStatistics.java	(revision 6152)
@@ -0,0 +1,154 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.simple;
+import ec.*;
+import ec.steadystate.*;
+import java.io.IOException;
+import ec.util.*;
+import java.io.File;
+
+/* 
+ * SimpleStatistics.java
+ * 
+ * Created: Tue Aug 10 21:10:48 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A basic Statistics class suitable for simple problem applications.
+ *
+ * SimpleStatistics prints out the best individual, per subpopulation,
+ * each generation.  At the end of a run, it also prints out the best
+ * individual of the run.  SimpleStatistics outputs this data to a log
+ * which may either be a provided file or stdout.  Compressed files will
+ * be overridden on restart from checkpoint; uncompressed files will be 
+ * appended on restart.
+ *
+ * <p>SimpleStatistics implements a simple version of steady-state statistics:
+ * if it quits before a generation boundary,
+ * it will include the best individual discovered, even if the individual was discovered
+ * after the last boundary.  This is done by using individualsEvaluatedStatistics(...)
+ * to update best-individual-of-generation in addition to doing it in
+ * postEvaluationStatistics(...).
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>gzip</tt><br>
+ <font size=-1>boolean</font></td>
+ <td valign=top>(whether or not to compress the file (.gz suffix added)</td></tr>
+ <tr><td valign=top><i>base.</i><tt>file</tt><br>
+ <font size=-1>String (a filename), or nonexistant (signifies stdout)</font></td>
+ <td valign=top>(the log for statistics)</td></tr>
+ </table>
+
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SimpleStatistics extends Statistics implements SteadyStateStatisticsForm //, ec.eval.ProvidesBestSoFar
+    {
+    public Individual[] getBestSoFar() { return best_of_run; }
+
+    /** log file parameter */
+    public static final String P_STATISTICS_FILE = "file";
+    
+    /** compress? */
+    public static final String P_COMPRESS = "gzip";
+
+    /** The Statistics' log */
+    public int statisticslog;
+
+    /** The best individual we've found so far */
+    public Individual[] best_of_run;
+        
+    /** Should we compress the file? */
+    public boolean compress;
+
+
+    public SimpleStatistics() { best_of_run = null; statisticslog = 0; /* stdout */ }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        
+        compress = state.parameters.getBoolean(base.push(P_COMPRESS),null,false);
+                
+        File statisticsFile = state.parameters.getFile(
+            base.push(P_STATISTICS_FILE),null);
+
+        if (statisticsFile!=null)
+            try
+                {
+                statisticslog = state.output.addLog(statisticsFile, !compress, compress);
+                }
+            catch (IOException i)
+                {
+                state.output.fatal("An IOException occurred while trying to create the log " + statisticsFile + ":\n" + i);
+                }
+        }
+
+    public void postInitializationStatistics(final EvolutionState state)
+        {
+        super.postInitializationStatistics(state);
+        
+        // set up our best_of_run array -- can't do this in setup, because
+        // we don't know if the number of subpopulations has been determined yet
+        best_of_run = new Individual[state.population.subpops.length];
+        }
+
+    /** Logs the best individual of the generation. */
+    public void postEvaluationStatistics(final EvolutionState state)
+        {
+        super.postEvaluationStatistics(state);
+        
+        // for now we just print the best fitness per subpopulation.
+        Individual[] best_i = new Individual[state.population.subpops.length];  // quiets compiler complaints
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            best_i[x] = state.population.subpops[x].individuals[0];
+            for(int y=1;y<state.population.subpops[x].individuals.length;y++)
+                if (state.population.subpops[x].individuals[y].fitness.betterThan(best_i[x].fitness))
+                    best_i[x] = state.population.subpops[x].individuals[y];
+        
+            // now test to see if it's the new best_of_run
+            if (best_of_run[x]==null || best_i[x].fitness.betterThan(best_of_run[x].fitness))
+                best_of_run[x] = (Individual)(best_i[x].clone());
+            }
+        
+        // print the best-of-generation individual
+        state.output.println("\nGeneration: " + state.generation,statisticslog);
+        state.output.println("Best Individual:",statisticslog);
+        for(int x=0;x<state.population.subpops.length;x++)
+            {
+            state.output.println("Subpopulation " + x + ":",statisticslog);
+            best_i[x].printIndividualForHumans(state,statisticslog);
+            state.output.message("Subpop " + x + " best fitness of generation: " + best_i[x].fitness.fitnessToStringForHumans());
+            }
+        }
+
+    /** Logs the best individual of the run. */
+    public void finalStatistics(final EvolutionState state, final int result)
+        {
+        super.finalStatistics(state,result);
+        
+        // for now we just print the best fitness 
+        
+        state.output.println("\nBest Individual of Run:",statisticslog);
+        for(int x=0;x<state.population.subpops.length;x++ )
+            {
+            state.output.println("Subpopulation " + x + ":",statisticslog);
+            best_of_run[x].printIndividualForHumans(state,statisticslog);
+            state.output.message("Subpop " + x + " best fitness of run: " + best_of_run[x].fitness.fitnessToStringForHumans());
+
+            // finally describe the winner if there is a description
+            if (state.evaluator.p_problem instanceof SimpleProblemForm)
+                ((SimpleProblemForm)(state.evaluator.p_problem.clone())).describe(state, best_of_run[x], x, 0, statisticslog);      
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/simple/simple.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/simple/simple.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/simple/simple.params	(revision 6152)
@@ -0,0 +1,91 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+parent.0 = ../ec.params
+
+# 
+# The following parameter file will set up a very basic form
+# of evolution, single-threaded, no coevolution, no exchanging,
+# no cross-population breeding, using generational evolution,
+# simple fitness, popsize=1024, etc. 
+# You'll need to fill in some of the gaps.
+#
+
+# ec.Evolve
+# ==============================
+
+# simple generational evolution
+state = 				ec.simple.SimpleEvolutionState
+
+
+
+# ec.EvolutionState
+# ==============================
+
+# We're using the standard initialization method
+init = 					ec.simple.SimpleInitializer
+
+# We're using the standard (empty) finalization method
+finish = 	        		ec.simple.SimpleFinisher
+
+# We're using the standard (empty) exchange method
+exch = 					ec.simple.SimpleExchanger
+
+# We're using standard breeding -- no cross-population breeding
+breed =					ec.simple.SimpleBreeder
+
+# We're using standard evaluation -- no coevolution
+eval =					ec.simple.SimpleEvaluator
+
+# We're using simple statistics
+stat =					ec.simple.SimpleStatistics
+
+# run for 51 generations, quit prematurely if I find something ideal
+generations =				51
+quit-on-run-complete =			true
+
+
+
+# ec.Initializer
+# ==============================
+
+pop = 					ec.Population
+
+
+# ec.Population
+# ==============================
+
+# No multiple populations
+pop.subpops =				1
+pop.subpop.0 = 				ec.Subpopulation
+
+
+# ec.Subpopulation
+# ==============================
+
+# subpop size is 1024 individuals
+pop.subpop.0.size =			1024
+# don't bother trying to eliminate duplicates from the
+# initial population
+pop.subpop.0.duplicate-retries =	0
+
+# ==You need to provide the species info for the subpopulation.==
+
+# ec.simple.SimpleBreeder
+# ==============================
+
+# By default elitism isn't done.  If you want to do elitism for, say,
+# the top 10 individuals in subpopulation 0, you'd say:
+
+# breed.elite.0 = 			10
+
+
+# ec.SimpleStatistics
+# ==============================
+
+# output statistics to the file "out.stat" in the directory
+# the run was started in
+stat.file				$out.stat
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/README	(revision 6152)
@@ -0,0 +1,47 @@
+The spatial package contains basic functionality for implementing spatially
+embedded (or so-called "fine-grained parallel") population models.  In these
+models each subpopulation has its individuals spread out in some notional
+space (such as a grid), and breeding is accomplished by selecting an
+individual, picking a sufficiently fit "neighbor" of that individual, breeding
+the two, and replacing the original individual with the resulting child.  The 
+definition of the space and the notion of neighborhood is up to the particular
+space being used.  The 'Space' interface defines the necessary functions
+for creating a subpopulation embedded with some space of your choosing.
+Use the SpatialTournamentSelection selection method to select individuals
+in your breeding pipeline, and a spatial Breeder.  Classes of interest:
+
+
+
+ec.spatial.Space
+
+An interface which includes methods necessary to embed notions of
+some kind of space into a subpopulation.  
+
+
+ec.spatial.Spatial1DSubpopulation
+
+A basic Subpopulation which implements Space to define a 1-dimensional
+toroidal space (that is, a ring).
+
+
+ec.spatial.SpatialTournamentSelection
+
+A variation of Tournament Selection which only picks neighbors of the current
+individual as entrants into the tournament.
+
+
+ec.spatial.SpatialBreeder
+
+A version of Breeder which, working with SpatialTournamentSelection,
+iteratively walks through the subpopulation and breeds new individuals to
+replace each slot in the subpopulation while adhering to the Space constraints.
+
+
+ec.spatial.SpatialMultiPopCoevolutionaryEvaluator
+
+A multi-population coevolutionary evaluator (similar to
+ec.coevolve.MultiPopCoevolutionaryEvaluator) which additionally can select 
+one of the partners of a given individual(s) to be the individual in the exact
+same slot in the other subpopulation(s).
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/Space.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/Space.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/Space.java	(revision 6152)
@@ -0,0 +1,73 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.spatial;
+
+import ec.*;
+
+/* 
+ * Space.java
+ * 
+ * By: Liviu Panait
+ */
+
+
+/**
+ *      In a spatially-embedded EA, the subpopulations of individuals are assumed to be
+ *      spatially distributed in some sort of space, be it one-dimmensional, two-
+ *      dimmensional, or whatever else.  The space may or may not be toroidal (although
+ *      it usually is).  Each location in the space has a set of neighboring locations.
+ *      Thus, each individual has an index in the subpopulation, and also a location in
+ *      the space.
+ *
+ *      This public interface provides a method to obtain the indexes of the neighbors
+ *      of a location.
+ *
+ *
+ *
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public interface Space
+    {
+    /*
+      The Space should provide a bijectional mapping from locations in space
+      to indexes in the subpopulation.  Returns -1 if error occured.
+    */
+    // public int locationToIndex( final Object location );
+
+    /*
+      The Space provide a bijectional mapping from indexes in the subpopulation
+      to locations in space.  Returns null if error occured.
+    */
+    // public Object indexToLocation( final int index);
+
+    /**
+       Input: a threadnumber (either for evaluation or for breeding), and an index in a subpopulation
+       (the index in the subpopulation is, of course, associated with a location in the space)
+       Functionality: stores the index and the threadnumber for further accesses to the getIndexRandomNeighbor
+       method.  All such accesses from the specific thread will use the exact same index, until
+       this function is called again to change the index.
+    */
+    public void setIndex( int threadnum, int index );
+
+    /**
+       Functionality: retrieve the index for a specific threanum.
+       Returns -1 if any error is encountered.
+    */
+    public int getIndex( int threadnum );
+
+    /**
+       Input: the maximum distance for neighbors.
+       Functionality: computes the location in space associated with the index, then
+       computes the neighbors of that location that are within the specified distance.
+       Output: returns one random neighbor within that distance (possibly including self)
+    */
+    public int getIndexRandomNeighbor( final EvolutionState state, int threadnum, int distance );
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/Spatial1DSubpopulation.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/Spatial1DSubpopulation.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/Spatial1DSubpopulation.java	(revision 6152)
@@ -0,0 +1,140 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.spatial;
+
+import ec.*;
+import ec.util.*;
+
+/* 
+ * Spatial1DSubpopulation.java
+ * 
+ * By: Liviu Panait
+ */
+
+/**
+ *      A Spatial1DSubpopulation is an EC subpopulation that is additionally embedded into
+ *      a one-dimmensional space.
+ *      In a spatially-embedded EA, the subpopulations of individuals are assumed to be
+ *      spatially distributed in some sort of space, be it one-dimmensional, two-
+ *      dimmensional, or whatever else.  The space may or may not be toroidal (although
+ *      it usually is).  Each location in the space has a set of neighboring locations.
+ *      Thus, each individual has an index in the subpopulation, and also a location in
+ *      the space.
+ *
+ *      <p>This public interface provides a method to obtain the indexes of the neighbors
+ *      of a location.
+ *
+ *      <P>This Subpopulation does not include toroidalness in writing out to streams.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt>toroidal</tt><br>
+ <font size=-1>true (default) or false</font></td>
+ <td valign=top>(Is this space toroidal?)</td></tr>
+
+ *
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+public class Spatial1DSubpopulation extends Subpopulation implements Space
+    {
+    /**
+       This parameter stipulates whether the world is toroidal or not.
+       If missing, its default value is true.
+    */
+    public static final String P_TOROIDAL = "toroidal";
+    public boolean toroidal;
+
+    /**
+       Read additional parameters for the spatially-embedded subpopulation.
+    */
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+
+        // by default, the space is toroidal
+        toroidal = state.parameters.getBoolean(base.push(P_TOROIDAL),null,true);
+
+        }
+
+    /*
+      1D mapping is identity
+    */
+    /*
+      public int locationToIndex( final Object location )
+      {
+      if( location instanceof Integer )
+      return ((Integer)location).intValue();
+      return -1;
+      }
+    */
+
+    /*
+      1D mapping is identity
+    */
+    /*
+      public Object indexToLocation( final int index)
+      {
+      return new Integer(index);
+      }
+    */
+
+    public void setIndex( int threadnum, int index )
+        {
+        if( indexes == null )
+            indexes = new int[threadnum+1];
+        if( threadnum >= indexes.length )
+            {
+            int currentSize = indexes.length;
+            int[] temp = new int[threadnum*2+1];
+            System.arraycopy(indexes,0,temp,0,currentSize);
+            indexes = temp;
+            }
+        indexes[threadnum] = index;
+        }
+
+    public int getIndex( int threadnum )
+        {
+        if( indexes == null || threadnum > indexes.length )
+            return -1;
+        else
+            return indexes[threadnum];
+        }
+
+    // indexed by threadnum
+    int[] indexes;
+
+    /**
+       Returns a the index of a random neighbor.
+    */
+    public int getIndexRandomNeighbor( final EvolutionState state, int threadnum, int distance )
+        {
+        int index = indexes[threadnum];
+
+        int size = individuals.length;
+        if( size == 0 )
+            return index;
+        if( toroidal )
+            {
+            int max = (2*distance+1>size) ? size : (2*distance+1);
+            int rand = state.random[threadnum].nextInt(max);
+            int val= (index+rand-distance);
+            if (val >= 0 && val < size) return val;
+            val = val % size;
+            if (val >= 0) return val;
+            else return val + size;
+            }
+        else
+            {
+            int min = (index-distance<0) ? 0 : (index-distance);
+            int max = (index+distance>=size) ? size : (index+distance);
+            int val = min + state.random[threadnum].nextInt(max-min+1);
+            return val;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialBreeder.java	(revision 6152)
@@ -0,0 +1,89 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.spatial;
+
+import ec.Initializer;
+import ec.Individual;
+import ec.BreedingPipeline;
+import ec.Breeder;
+import ec.simple.*;
+import ec.EvolutionState;
+import ec.Population;
+import ec.util.Parameter;
+import ec.util.*;
+
+/* 
+ * SpatialBreeder.java
+ * 
+ * By: Liviu Panait
+ */
+
+/**
+ * A slight modification of the simple breeder for spatially-embedded EAs.
+ 
+ * Breeds each subpopulation separately, with no inter-population exchange,
+ * and using a generational approach.  A SpatialBreeder may have multiple
+ * threads; it divvys up a subpopulation into chunks and hands one chunk
+ * to each thread to populate.  One array of BreedingPipelines is obtained
+ * from a population's Species for each operating breeding thread.
+ *
+ *
+ *
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public class SpatialBreeder extends SimpleBreeder
+    {
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+                
+        // check for elitism and warn about it
+        for(int i = 0 ; i < elite.length; i++)
+            if (elite[i] > 0)
+                {
+                state.output.warning("You're using elitism with SpatialBreeder.  This is unwise as elitism is done by moving individuals around in the population, thus messing up the spatial nature of breeding.",
+                    base.push(P_ELITE).push(""+i));
+                break;
+                }
+        }
+                
+    protected void breedPopChunk(Population newpop, EvolutionState state,
+        int[] numinds, int[] from, int threadnum) 
+        {
+        for(int subpop=0;subpop<newpop.subpops.length;subpop++)
+            {
+            BreedingPipeline bp = (BreedingPipeline)newpop.subpops[subpop].
+                species.pipe_prototype.clone();
+                                
+            if (!(state.population.subpops[subpop] instanceof Space))
+                state.output.fatal("Subpopulation " + subpop + " does not implement the Space interface.");
+            Space space = (Space)(state.population.subpops[subpop]);
+                        
+            // check to make sure that the breeding pipeline produces
+            // the right kind of individuals.  Don't want a mistake there! :-)
+            if (!bp.produces(state,newpop,subpop,threadnum))
+                state.output.fatal("The Breeding Pipeline of subpopulation " + subpop + " does not produce individuals of the expected species " + newpop.subpops[subpop].species.getClass().getName() + " or fitness " + newpop.subpops[subpop].species.f_prototype );
+            bp.prepareToProduce(state,subpop,threadnum);
+                        
+            // start breedin'!
+            for(int x = from[subpop]; x < from[subpop] + numinds[subpop]; x++)
+                {
+                space.setIndex(threadnum, x);
+                if (bp.produce(1, 1, x, subpop, newpop.subpops[subpop].individuals, state, threadnum) != 1)
+                    state.output.fatal( "The pipelines should produce one individual at a time!" );
+                }
+                                
+            bp.finishProducing(state,subpop,threadnum);
+            }
+        }
+
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialDefaults.java	(revision 6152)
@@ -0,0 +1,32 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.spatial;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * SpatialDefaults.java
+ * 
+ * Created: Thu Feb  2 13:39:52 EST 2006
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class SpatialDefaults implements DefaultsForm
+    {
+    public static final String P_SPATIAL = "spatial";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_SPATIAL);
+        }    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialMultiPopCoevolutionaryEvaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialMultiPopCoevolutionaryEvaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialMultiPopCoevolutionaryEvaluator.java	(revision 6152)
@@ -0,0 +1,41 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.spatial;
+
+import ec.*;
+import ec.util.*;
+import ec.coevolve.*;
+
+/* 
+ * SpatialMultiPopCoevolutionaryEvaluator.java
+ * 
+ * By: Liviu Panait and Sean Luke
+ */
+
+/** 
+ * SpatialMultiPopCoevolutionaryEvaluator implements a coevolutionary evaluator involving multiple
+ * spatially-embedded subpopulations.  You ought to use it in conjuction with SpatialTournamentSelection
+ * (for selecting current-generation individuals, set the tournament selection size to 1, which will
+ * pick randomly from the space).
+ *
+ * @author Liviu Panait Sean Luke
+ * @version 2.0 
+ */
+
+public class SpatialMultiPopCoevolutionaryEvaluator extends MultiPopCoevolutionaryEvaluator
+    {
+    protected Individual produce(SelectionMethod method, int subpopulation, int individual, EvolutionState state, int thread)
+        {
+        if (!(state.population.subpops[subpopulation] instanceof Space))
+            state.output.fatal("Subpopulation " + subpopulation + " is not a Space.");
+                        
+        Space space = (Space)(state.population.subpops[subpopulation]);
+        space.setIndex(thread, individual);
+                
+        return state.population.subpops[subpopulation].individuals[method.produce(subpopulation, state, thread)];
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialTournamentSelection.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialTournamentSelection.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/spatial/SpatialTournamentSelection.java	(revision 6152)
@@ -0,0 +1,134 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.spatial;
+
+import ec.*;
+import ec.util.*;
+import ec.select.TournamentSelection;
+
+/* 
+ * SpatialTournamentSelection.java
+ * 
+ * By: Liviu Panait
+ */
+
+/**
+ * A slight modification of the tournament selection procedure for use with spatially-embedded EAs.
+ *
+ * When selecting an individual, the SpatialTournamentSelection is told a specific individual.
+ * It then picks N individuals at random which are within a certain distance (the <i>neighborhood size</i>) of that individual.  These
+ * individuals then enter a tournament a-la standard Tournament Selection.  
+ *
+ * <p>The method of picking individuals is either <tt>uniform</tt> (picking individuals using the Space interface's
+ * getRandomIndividual(...)) or <tt>random-walk</tt> (wandering <i>distance</i> steps at random).  You can also
+ * stipulate whether the original individual must be in the tournament.
+ *
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base.</i><tt>neighborhood-size</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(the neighborhood size)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>ind-competes</tt><br>
+ <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
+ <td valign=top>(Do we include the base individual in the tournament?)</td></tr>
+
+ <tr><td valign=top><i>base.</i><tt>type</tt><br>
+ <font size=-1>String: uniform (default) or random-walk</font></td>
+ <td valign=top>Method for selecting individuals in neighborhood</td></tr>
+
+ </table>
+
+ Further parameters may be found in ec.select.TournamentSelection.
+
+ <p><b>Default Base</b><br>
+ spatial.tournament
+ *
+ * @author Liviu Panait and Sean Luke
+ * @version 2.0
+ */
+public class SpatialTournamentSelection extends TournamentSelection
+    {
+    /**
+       The size of the neighborhood from where parents are selected.  Small neighborhood sizes
+       enforce a local selection pressure, while larger values for this parameters allow further-away
+       individuals to compete for breeding as well.
+    */
+    public static final String P_N_SIZE = "neighborhood-size";
+    int neighborhoodSize;
+
+    /**
+       Some models assume an individual is always selected to compete for breeding a child that would
+       take its location in space.  Other models don't make this assumption.  This parameter allows one
+       to specify whether an individual will be selected to compete with others for breeding a child that
+       will take its location in space.  If the parameter value is not specified, it is assumed to be false
+       by default.
+    */
+    public static final String P_IND_COMPETES = "ind-competes";
+    boolean indCompetes;
+
+
+    /**
+       Selection procedure.
+    */
+    public static final String P_TYPE = "type";
+    public static final String V_UNIFORM = "uniform";
+    public static final String V_RANDOM_WALK = "random-walk";
+    public static final int TYPE_UNIFORM = 0;
+    public static final int TYPE_RANDOM_WALK = 1;
+    int type;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+                
+        Parameter defaultBase = defaultBase();
+
+        neighborhoodSize = state.parameters.getInt( base.push(P_N_SIZE), defaultBase.push(P_N_SIZE), 1 );
+        if( neighborhoodSize < 1 )
+            state.output.fatal( "Parameter not found, or its value is < 1.", base.push(P_N_SIZE), defaultBase.push(P_N_SIZE));
+
+        if (!state.parameters.exists(base.push(P_TYPE), defaultBase.push(P_TYPE)) ||
+            state.parameters.getString( base.push(P_TYPE), defaultBase.push(P_TYPE)).equals(V_UNIFORM))
+            type = TYPE_UNIFORM;
+        else if (state.parameters.getString( base.push(P_TYPE), defaultBase.push(P_TYPE)).equals(V_RANDOM_WALK))
+            type = TYPE_RANDOM_WALK;
+        else state.output.fatal("Invalid parameter, must be either " + V_RANDOM_WALK + " or " + V_UNIFORM + ".",
+            base.push(P_TYPE), defaultBase.push(P_TYPE));
+                
+        indCompetes = state.parameters.getBoolean(base.push(P_IND_COMPETES), defaultBase.push(P_IND_COMPETES), false);
+        }
+
+
+    public Parameter defaultBase()
+        {
+        return SpatialDefaults.base().push(P_TOURNAMENT);
+        }
+
+    public int getRandomIndividual(int number, int subpopulation, EvolutionState state, int thread)
+        {
+        Subpopulation subpop = state.population.subpops[subpopulation];
+        if (!(subpop instanceof Space))
+            state.output.fatal( "Subpopulation "+subpopulation+" is not a spatially-embedded subpopulation.\n");
+        Space space = (Space)(state.population.subpops[subpopulation]);
+        int index = space.getIndex(thread);
+                
+        if (number==0 && indCompetes)           // Should we just return the individual?
+            return index;
+        else if (type == TYPE_UNIFORM)          // Should we pick randomly in the space up to the given distance?
+            return space.getIndexRandomNeighbor(state,thread,neighborhoodSize);
+        else // if (type == TYPE_RANDOM_WALK)  // Should we do a random walk?
+            {
+            int oldIndex = index;
+            for(int x=0; x < neighborhoodSize; x++)
+                space.setIndex(thread, space.getIndexRandomNeighbor(state, thread, 1));
+            int val = space.getIndex(thread);
+            space.setIndex(thread,oldIndex);  // just in case we weren't supposed to mess around with that
+            return val;
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/QueueIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/QueueIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/QueueIndividual.java	(revision 6152)
@@ -0,0 +1,26 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+/*
+  A simple class which contains both an Individual and the Queue it's located in.
+  Used by SteadyState and by various assistant functions in the distributed evaluator
+  to provide individuals to SteadyState
+*/
+                
+package ec.steadystate;
+import ec.*;
+
+public class QueueIndividual implements java.io.Serializable
+    { 
+    public Individual ind;
+    public int subpop; 
+    public  QueueIndividual(Individual i, int s)
+        {
+        ind = i; 
+        subpop=s; 
+        }
+    };
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/README	(revision 6152)
@@ -0,0 +1,98 @@
+This package implements steady state evolution and, by extension, asynchronous
+evolution when used in combination with the master/slave evaluation package.
+The steady state evolution facility in ECJ is fairly simple: each iteration
+the facility breeds a single individual, evaluates it, and reinserts it into
+the population (selecting an individual to die and be replaced with it).  In
+asynchronous evolution, the system breeds individuals and ships them off to
+remote slaves to evaluated whenever a remote slave is available; when an 
+individual is completed from a remote slave, if the initial population has not
+yet been filed up, the individual is inserted directly in the population, else
+the system selects an individual to die and be replaced by it.
+
+To do this magic requires several replacement classes: a new top-level
+evolution state object provides the evolutionary loop, plus a custom breeder
+and evaluator.  Because steady-state isn't generational, certain ECJ classes
+are required to implement special interfaces in order to be compatible with
+it: breeding sources (breeding pipelines, selection methods) must be of
+SteadyStateBSourceform -- notably many selection methods don't work right,
+we suggest using Tournament Selection; the statistics facility must implement
+a different non-generational collection of statistics hooks embodied in 
+SteadyStateStatisticsForm; and exchangers must implement 
+SteadyStateExchangerForm.
+
+Steady state evolution doesn't have a notion of generations per se, as no
+entire generation is replaced each iteration.  Instead, the evolution state
+facility defines a "generation" as when a population's worth of individuals
+has just been introduced into the system.  Most statistics counts are run
+not off of these pseudo-generations but rather are based on the number of
+*evaluations* (a variable in SteadyStateEvolutionState) which have been
+done so far.  As such you have the option of either stating the number
+of evaluations that the system should run for, OR the number of "generations"
+(so to speak) the system should run for.  See the file steadystate.params
+for an example of how to set up steady state evolution.
+
+Classes of relevance:
+
+
+
+ec.steady.SteadyStateEvolutionState
+
+The top-level EvolutionState which performs steady-state and asynchronous
+evolution loops.
+
+
+ec.steady.SteadyStateBreeder
+
+The steady-state breeder.   A drop-in replacement for Breeder, except that
+it also requires an additional parameter 'deselector' which indicates the
+SelectionMethod used to pick individuals to be replaced with new incoming
+children.  This could be a random selector, or a Tournament Selection
+method picking the worst individuals, etc.  See steadystate.params for
+an example.
+
+
+ec.steady.SteadyStateEvaluator
+
+The steady-state evaluator.  A drop-in replacement for Evaluator.
+
+
+ec.steady.QueueIndividual
+
+A wrapper which holds an Individual, plus the subpopulation the Individual
+is stored in.  This class is used by the SteadyStateEvaluator and also by
+the master-slave evaluation system to maintain some additional information 
+about the Individual for purposes of Asynchronous Evolution.  It's an 
+internal class and shouldn't be fooled around with; it's public because
+the master-slave facility must also be able to use it.  Ignore it.
+
+
+ec.steady.SteadyStateStatisticsForm
+
+Statistics objects which implement this interface will receive additional
+statistics hooks appropriate for the steady state loop (based largely on
+individuals being evaluated rather than based around generations).  This
+is an optional interface and your Statistics object can always be used
+even if it doesn't implement this interface; it just won't receive the
+new method calls.
+
+
+ec.steady.SteadyStateExchangerForm
+
+All exchangers must implement the SteadyStateExchangerForm in order to be
+used with the steady state facility.  This is a "gold star" interface which
+has no methods but merely is implemented by exchangers which have agreed
+to perform certain special tasks (see the code of the class).
+
+
+ec.steady.SteadyStateBSourceForm
+
+All breeding sources (BreedingPipelines, SelectionMethods) must implement
+this interface in order to be used with the steady state facility.  The
+interface largely informs breeding sources that an individual has replaced
+another in the population  Some breeding sources (such as 
+FitnessProportionateSelection) must update their distributions each time
+this happens, which is quite expensive, and so they do not implement this
+interface.  We suggest you use Tournament Selection, which is effective
+and fast.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateBSourceForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateBSourceForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateBSourceForm.java	(revision 6152)
@@ -0,0 +1,44 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.steadystate;
+
+/* 
+ * SteadyStateBSourceForm.java
+ * 
+ * Created: Sat Nov 20 17:00:18 1999
+ * By: Sean Luke
+ *
+ * This form is required of all BreedingSources in a pipeline used in Steady-State Evolution.
+ * It consists of two methods: <b>sourcesAreProperForm</b> which checks recursively to determine
+ * that a BreedingPipeline's own sources are also using this interface; and <b>individualReplaced</b>,
+ * which informs the BreedingSource that a new individual has entered into the population, displacing
+ * another.  This is important because it may signal to SelectionMethods that they need to update their
+ * statistics.
+ *
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface SteadyStateBSourceForm
+    {
+    /** Called whenever an individual has been replaced by another
+        in the population. */
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual);
+    
+    /** Issue an error (not a fatal -- we guarantee that callers
+        of this method will also call exitIfErrors) if any
+        of your sources, or <i>their</i> sources, etc., are not
+        of SteadyStateBSourceForm.*/
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateBreeder.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateBreeder.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateBreeder.java	(revision 6152)
@@ -0,0 +1,173 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.steadystate;
+import ec.simple.*;
+import ec.*;
+import ec.util.*;
+import java.util.*;
+
+/* 
+ * SteadyStateBreeder.java
+ * 
+ */
+
+/**
+ * This subclass of Breeder performs the evaluation portion of Steady-State Evolution and (in distributed form)
+ * Asynchronous Evolution. The procedure is as follows.  We begin with an empty Population and one by
+ * one create new Indivdiuals and send them off to be evaluated.  In basic Steady-State Evolution the
+ * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated
+ * for however long it takes and we don't wait for them to finish.  When individuals return they are
+ * added to the Population until it is full.  No duplicate individuals are allowed.
+ *
+ * <p>At this point the system switches to its "steady state": individuals are bred from the population
+ * one by one, and sent off to be evaluated.  Once again, in basic Steady-State Evolution the
+ * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated
+ * for however long it takes and we don't wait for them to finish.  When an individual returns, we
+ * mark an individual in the Population for death, then replace it with the new returning individual.
+ * Note that during the steady-state, Asynchronous Evolution could be still sending back some "new" individuals
+ * created during the initialization phase, not "bred" individuals.
+ *
+ * <p>The determination of how an individual is marked for death is done by the SteadyStateBreeder.  This is
+ * a SelectionMethod.  Note that this SelectionMethod probably should <i>not</i> be selecting for the "fittest"
+ * individuals, but rather for either random individuals (the standard approach) or for "bad" individuals.
+ * 
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt>deselector</tt><br>
+ <font size=-1>classname, inherits and != ec.SelectionMethod</font></td>
+ <td valign=top>(The SelectionMethod used to pick individuals for death)</td></tr>
+ </table>
+
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SteadyStateBreeder extends SimpleBreeder
+    {
+    /** If st.firstTimeAround, this acts exactly like SimpleBreeder.
+        Else, it only breeds one new individual per subpopulation, to 
+        place in position 0 of the subpopulation.  
+    */
+    BreedingPipeline[] bp;
+    
+    public static final String P_DESELECTOR = "deselector";
+    // public static final String P_RETRIES = "duplicate-retries";
+        
+    /** Loaded during the first iteration of breedPopulation */
+    SelectionMethod deselectors[];
+        
+    /** Do we allow duplicates? */
+    // public int numDuplicateRetries;
+    
+    public SteadyStateBreeder() { bp = null; deselectors = null; }
+        
+    public void setup(final EvolutionState state, final Parameter base) 
+        {
+        super.setup(state,base);
+                
+        Parameter p = new Parameter(Initializer.P_POP).push(Population.P_SIZE);
+        int size = state.parameters.getInt(p,null,1);  
+        
+        // if size is wrong, we'll let Population complain about it  -- for us, we'll just make 0-sized arrays and drop out.
+        if (size > 0)
+            deselectors = new SelectionMethod[size];
+        
+        // load the deselectors
+        for(int x=0;x<deselectors.length;x++)
+            {
+            deselectors[x] = (SelectionMethod)(
+                state.parameters.getInstanceForParameter(
+                    SteadyStateDefaults.base().push(P_DESELECTOR).push(""+x),null,SelectionMethod.class));
+            if (!(deselectors[x] instanceof SteadyStateBSourceForm))
+                state.output.error("Deselector for subpopulation " + x + " is not of SteadyStateBSourceForm.");
+            deselectors[x].setup(state,SteadyStateDefaults.base().push(P_DESELECTOR).push(""+x));
+            }
+        state.output.exitIfErrors();
+        
+        // How often do we retry if we find a duplicate?
+        /*
+          numDuplicateRetries = state.parameters.getInt(
+          SteadyStateDefaults.base().push(P_RETRIES),null,0);
+          if (numDuplicateRetries < 0) state.output.fatal(
+          "The number of retries for duplicates must be an integer >= 0.\n",
+          base.push(P_RETRIES),null);
+        */
+        }
+        
+    /** Called to check to see if the breeding sources are correct -- if you
+        use this method, you must call state.output.exitIfErrors() immediately 
+        afterwards. */
+    public void sourcesAreProperForm(final SteadyStateEvolutionState state,
+        final BreedingPipeline[] breedingPipelines)
+        {
+        for(int x=0;x<breedingPipelines.length;x++)
+            {
+            if (!(breedingPipelines[x] instanceof SteadyStateBSourceForm))
+                state.output.error("Breeding Pipeline of subpopulation " + x + " is not of SteadyStateBSourceForm");
+            ((SteadyStateBSourceForm)(breedingPipelines[x])).sourcesAreProperForm(state);
+            }
+        }
+    
+    /** Called whenever individuals have been replaced by new
+        individuals in the population. */
+    public void individualReplaced(final SteadyStateEvolutionState state,
+        final int subpopulation,
+        final int thread,
+        final int individual)
+        {
+        for(int x=0;x<bp.length;x++)
+            ((SteadyStateBSourceForm)bp[x]).
+                individualReplaced(state,subpopulation,thread,individual);
+        // let the deselector know
+        ((SteadyStateBSourceForm)deselectors[subpopulation]).individualReplaced(state,subpopulation,thread,individual);
+        }
+        
+    public void finishPipelines(EvolutionState state)
+        {
+        for(int x = 0 ; x < deselectors.length; x++)
+            {
+            bp[x].finishProducing(state,x,0);
+            deselectors[x].finishProducing(state,x,0);
+            }
+        }
+        
+    public void prepareToBreed(EvolutionState state, int thread)
+        {
+        final SteadyStateEvolutionState st = (SteadyStateEvolutionState) state;
+        // set up the breeding pipelines
+        bp = new BreedingPipeline[st.population.subpops.length];
+        for(int pop=0;pop<bp.length;pop++)
+            {
+            bp[pop] = (BreedingPipeline)st.population.subpops[pop].species.pipe_prototype.clone();
+            if (!bp[pop].produces(st,st.population,pop,0))
+                st.output.error("The Breeding Pipeline of subpopulation " + pop + " does not produce individuals of the expected species " + st.population.subpops[pop].species.getClass().getName() + " and with the expected Fitness class " + st.population.subpops[pop].species.f_prototype.getClass().getName());
+            }
+        // are they of the proper form?
+        sourcesAreProperForm(st,bp);
+        // because I promised when calling sourcesAreProperForm
+        st.output.exitIfErrors();
+                
+        // warm them up
+        for(int pop=0;pop<bp.length;pop++)
+            {
+            bp[pop].prepareToProduce(state,pop,0);
+            deselectors[pop].prepareToProduce(state,pop,0);
+            }
+        }
+        
+    public Individual breedIndividual(final EvolutionState state, int subpop, int thread)
+        {
+        final SteadyStateEvolutionState st = (SteadyStateEvolutionState) state;
+        Individual[] newind = new Individual[1]; 
+                
+        // breed a single individual 
+        bp[subpop].produce(1,1,0,subpop,newind,state,thread);
+        return newind[0]; 
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateDefaults.java	(revision 6152)
@@ -0,0 +1,33 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.steadystate;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * SteadyStateDefaults.java
+ * 
+ * Created: Thu Jan 20 16:49:57 2000
+ * By: Sean Luke
+ */
+
+/**
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public final class SteadyStateDefaults implements DefaultsForm
+    {
+    public static final String P_STEADYSTATE = "steady";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_STEADYSTATE);
+        }    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateEvaluator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateEvaluator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateEvaluator.java	(revision 6152)
@@ -0,0 +1,123 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+                
+package ec.steadystate;
+import ec.simple.*;
+import ec.*;
+import ec.util.Parameter;
+import java.util.*; 
+import ec.eval.MasterProblem;
+
+/* 
+ * SteadyStateEvaluator.java
+ * 
+ */
+
+/**
+ * This subclass of Evaluator performs the evaluation portion of Steady-State Evolution and (in distributed form)
+ * Asynchronous Evolution. The procedure is as follows.  We begin with an empty Population and one by
+ * one create new Indivdiuals and send them off to be evaluated.  In basic Steady-State Evolution the
+ * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated
+ * for however long it takes and we don't wait for them to finish.  When individuals return they are
+ * added to the Population until it is full.  No duplicate individuals are allowed.
+ *
+ * <p>At this point the system switches to its "steady state": individuals are bred from the population
+ * one by one, and sent off to be evaluated.  Once again, in basic Steady-State Evolution the
+ * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated
+ * for however long it takes and we don't wait for them to finish.  When an individual returns, we
+ * mark an individual in the Population for death, then replace it with the new returning individual.
+ * Note that during the steady-state, Asynchronous Evolution could be still sending back some "new" individuals
+ * created during the initialization phase, not "bred" individuals.
+ *
+ * <p>The determination of how an individual is marked for death is done by the SteadyStateBreeder.
+ *
+ * <p>When SteadyStateEvaluator sends indivduals off to be evaluated, it stores them in an internal queue, along
+ * with the subpopulation in which they were destined.  This tuple is defined by QueueIndividual.java
+ * 
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class SteadyStateEvaluator extends SimpleEvaluator
+    {
+    LinkedList queue = new LinkedList();
+    
+    /** Holds the subpopulation currently being evaluated.  */ 
+    int subpopulationBeingEvaluated = -1;
+
+    /** Our problem. */
+    SimpleProblemForm problem; 
+        
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        }
+        
+    public void prepareToEvaluate(EvolutionState state, int thread) 
+        {
+        problem = (SimpleProblemForm)p_problem.clone();
+                
+        /* 
+           We only call prepareToEvaluate during Asynchronous Evolution.
+        */
+        if (problem instanceof MasterProblem) 
+            ((MasterProblem)problem).prepareToEvaluate(state, thread); 
+        }
+        
+    /** Submits an individual to be evaluated by the Problem, and adds it and its subpopulation to the queue. */
+    public void evaluateIndividual(final EvolutionState state, Individual ind, int subpop)
+        {
+        problem.evaluate(state, ind, subpop, 0);
+        queue.addLast(new QueueIndividual(ind, subpop));
+        }
+    
+    /** Returns true if we're ready to evaluate an individual.  Ordinarily this is ALWAYS true,
+        except in the asynchronous evolution situation, where we may not have a processor ready yet. */
+    public boolean canEvaluate() 
+        {
+        if (problem instanceof MasterProblem)
+            return ((MasterProblem)problem).canEvaluate();
+        else return true;
+        }
+        
+    /** Returns an evaluated individual is in the queue and ready to come back to us.  
+        Ordinarily this is ALWAYS true at the point that we call it, except in the asynchronous 
+        evolution situation, where we may not have a job completed yet, in which case NULL is
+        returned. Once an individual is returned by this function, no other individual will
+        be returned until the system is ready to provide us with another one.  NULL will
+        be returned otherwise.  */
+    public Individual getNextEvaluatedIndividual()
+        {
+        QueueIndividual qind = null;
+        
+        if (problem instanceof MasterProblem)
+            {
+            if (((MasterProblem)problem).evaluatedIndividualAvailable())
+                qind = ((MasterProblem)problem).getNextEvaluatedIndividual();
+            }
+        else
+            {
+            qind = (QueueIndividual)(queue.removeFirst());
+            }
+        
+        if (qind == null) return null;
+        
+        subpopulationBeingEvaluated = qind.subpop;
+        return qind.ind;
+        }
+    
+    /** Returns the subpopulation of the last evaluated individual returned by getNextEvaluatedIndividual, or potentially -1 if
+        getNextEvaluatedIndividual was never called or hasn't returned an individual yet. */
+    public int getSubpopulationOfEvaluatedIndividual()
+        {
+        return subpopulationBeingEvaluated;
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateEvolutionState.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateEvolutionState.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateEvolutionState.java	(revision 6152)
@@ -0,0 +1,315 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.steadystate;
+import ec.*;
+import ec.util.Parameter;
+import ec.util.Checkpoint;
+import ec.util.Output;
+import ec.simple.*;
+//import ec.eval.MasterProblem;
+import java.util.*; 
+
+/* 
+ * SteadyStateEvolutionState.java
+ * 
+ */
+
+/**
+ * This subclass of EvolutionState implements basic Steady-State Evolution and (in distributed form)
+ * Asynchronous Evolution. The procedure is as follows.  We begin with an empty Population and one by
+ * one create new Indivdiuals and send them off to be evaluated.  In basic Steady-State Evolution the
+ * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated
+ * for however long it takes and we don't wait for them to finish.  When individuals return they are
+ * added to the Population until it is full.  No duplicate individuals are allowed.
+ *
+ * <p>At this point the system switches to its "steady state": individuals are bred from the population
+ * one by one, and sent off to be evaluated.  Once again, in basic Steady-State Evolution the
+ * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated
+ * for however long it takes and we don't wait for them to finish.  When an individual returns, we
+ * mark an individual in the Population for death, then replace it with the new returning individual.
+ * Note that during the steady-state, Asynchronous Evolution could be still sending back some "new" individuals
+ * created during the initialization phase, not "bred" individuals.
+ *
+ * <p>The determination of how an individual is marked for death is done by the SteadyStateBreeder.
+ *
+ * <p>SteadyStateEvolutionState will run either for some N "generations" or for some M evaluations of
+ * individuals.   A "generation" is defined as a Population's worth of evaluations.   If you do not
+ * specify the number of evaluations (the M), then SteadyStateEvolutionState will use the standard
+ * generations parameter defined in EvolutionState.
+ *
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt>evaluations</tt><br>
+ <font size=-1>int &gt;= 1</font></td>
+ <td valign=top>(maximal number of evaluations to run.)</td></tr>
+ </table>
+ 
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+
+public class SteadyStateEvolutionState extends EvolutionState
+    {
+    /** base parameter for steady-state */
+    public static final String P_NUMEVALUATIONS = "evaluations";
+        
+    /** Did we just start a new generation? */
+    public boolean generationBoundary;
+    /** How many evaluations should we run for?  If set to UNDEFINED (0), we run for the number of generations instead. */
+    public long numEvaluations;
+    public static long UNDEFINED = 0;
+    /** how big is a generation? Set to the size of subpopulation 0 of the initial population. */
+    public int generationSize;
+    /** How many evaluations have we run so far? */
+    public long evaluations;
+        
+    /** How many individuals have we added to the initial population? */ 
+    int[] individualCount; 
+        
+    /** Hash table to check for duplicate individuals */ 
+    HashMap[] individualHash; 
+        
+    /** Holds which subpopulation we are currently operating on */
+    int whichSubpop;
+    
+    /** First time calling evolve */
+    protected boolean firstTime; 
+        
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+                
+        // double check that we have valid evaluators and breeders and exchangers
+        if (!(breeder instanceof SteadyStateBreeder))
+            state.output.error("You've chosen to use Steady-State Evolution, but your breeder is not of the class SteadyStateBreeder.",base);
+        if (!(evaluator instanceof SteadyStateEvaluator))
+            state.output.error("You've chosen to use Steady-State Evolution, but your evaluator is not of the class SteadyStateEvaluator.",base);
+        if (!(exchanger instanceof SteadyStateExchangerForm))
+            state.output.error("You've chosen to use Steady-State Evolution, but your exchanger does not implement the SteadyStateExchangerForm.",base);
+        
+        checkStatistics(state, statistics, base);
+        
+        numEvaluations = parameters.getLong(new Parameter(P_NUMEVALUATIONS),null,1);
+        if (numEvaluations == 0)
+            output.message("Number of evaluations not defined; using number of generations");
+        }
+    
+    // recursively prints out warnings for all statistics that are not
+    // of steadystate statistics form
+    void checkStatistics(final EvolutionState state, Statistics stat, final Parameter base)
+        {
+        if (!(stat instanceof SteadyStateStatisticsForm))
+            state.output.warning("You've chosen to use Steady-State Evolution, but your statistics does not implement the SteadyStateStatisticsForm.",base);
+        for(int x=0;x<stat.children.length;x++)
+            if (stat.children[x]!=null)
+                checkStatistics(state, stat.children[x], base.push("child").push(""+x));
+        }
+    
+    
+    /**
+     * 
+     */
+    public void startFresh() 
+        {
+        output.message("Setting up");
+        setup(this,null);  // a garbage Parameter
+
+        // POPULATION INITIALIZATION
+        output.message("Initializing Generation 0");
+        statistics.preInitializationStatistics(this);
+        population = initializer.setupPopulation(this, 0);  // unthreaded.  We're NOT initializing here, just setting up.
+
+        // INITIALIZE VARIABLES
+        if (numEvaluations > 0 && numEvaluations < population.subpops[0].individuals.length)
+            output.fatal("Number of evaluations desired is smaller than the initial population of individuals");
+        generationSize = 0;
+        generationBoundary = false;
+        firstTime = true; 
+        evaluations=0; 
+        whichSubpop=-1; 
+                
+        individualHash = new HashMap[population.subpops.length];
+        for(int i=0;i<population.subpops.length; i++) individualHash[i] = new HashMap();
+                
+        individualCount = new int[population.subpops.length];
+        for (int sub=0; sub < population.subpops.length; sub++)  
+            { 
+            individualCount[sub]=0;
+            generationSize += population.subpops[sub].individuals.length;  // so our sum total 'generationSize' will be the initial total number of individuals
+            }
+
+        // INITIALIZE CONTACTS -- done after initialization to allow
+        // a hook for the user to do things in Initializer before
+        // an attempt is made to connect to island models etc.
+        exchanger.initializeContacts(this);
+        evaluator.initializeContacts(this);
+        }
+
+
+  
+    public int evolve()
+        {
+        if (generationBoundary && generation > 0)
+            {
+            output.message("Generation " + generation +"\tEvaluations " + evaluations);
+            statistics.generationBoundaryStatistics(this); 
+            statistics.postEvaluationStatistics(this); 
+            }
+                
+        if (firstTime) 
+            {
+            if (statistics instanceof SteadyStateStatisticsForm)
+                ((SteadyStateStatisticsForm)statistics).enteringInitialPopulationStatistics(this);
+            statistics.postInitializationStatistics(this); 
+            ((SteadyStateBreeder)breeder).prepareToBreed(this, 0); // unthreaded 
+            ((SteadyStateEvaluator)evaluator).prepareToEvaluate(this, 0); // unthreaded 
+            firstTime=false; 
+            } 
+                
+        whichSubpop = (whichSubpop+1)%population.subpops.length;  // round robin selection
+                
+        // is the current subpop full? 
+        boolean partiallyFullSubpop = (individualCount[whichSubpop] < population.subpops[whichSubpop].individuals.length);  
+                
+        // MAIN EVOLVE LOOP 
+        if (((SteadyStateEvaluator) evaluator).canEvaluate())   // are we ready to evaluate? 
+            {
+            Individual ind=null; 
+            int numDuplicateRetries = population.subpops[whichSubpop].numDuplicateRetries; 
+
+            for (int tries=0; tries <= numDuplicateRetries; tries++)  // see Subpopulation
+                { 
+                if ( partiallyFullSubpop )   // is population full?
+                    {
+                    ind = population.subpops[whichSubpop].species.newIndividual(this, 0);  // unthreaded 
+                    }
+                else  
+                    { 
+                    ind = ((SteadyStateBreeder)breeder).breedIndividual(this, whichSubpop,0); 
+                    statistics.individualsBredStatistics(this, new Individual[]{ind}); 
+                    }
+                                
+                if (numDuplicateRetries >= 1)  
+                    { 
+                    Object o = individualHash[whichSubpop].get(ind); 
+                    if (o == null) 
+                        { 
+                        individualHash[whichSubpop].put(ind, ind); 
+                        break; 
+                        }
+                    }
+                } // tried to cut down the duplicates 
+                        
+            // evaluate the new individual
+            ((SteadyStateEvaluator)evaluator).evaluateIndividual(this, ind, whichSubpop);
+            }
+        
+        Individual ind = ((SteadyStateEvaluator)evaluator).getNextEvaluatedIndividual();
+        if (ind != null)   // do we have an evaluated individual? 
+            {
+            int subpop = ((SteadyStateEvaluator)evaluator).getSubpopulationOfEvaluatedIndividual(); 
+                                                
+            if ( partiallyFullSubpop ) // is subpopulation full? 
+                {  
+                population.subpops[subpop].individuals[individualCount[subpop]++]=ind; 
+                                
+                // STATISTICS FOR GENERATION ZERO 
+                if ( individualCount[subpop] == population.subpops[subpop].individuals.length ) 
+                    if (statistics instanceof SteadyStateStatisticsForm)
+                        ((SteadyStateStatisticsForm)statistics).enteringSteadyStateStatistics(subpop, this); 
+                }
+            else 
+                { 
+                // mark individual for death 
+                int deadIndividual = ((SteadyStateBreeder)breeder).deselectors[subpop].produce(subpop,this,0);
+                Individual deadInd = population.subpops[subpop].individuals[deadIndividual];
+                                
+                // replace dead individual with new individual 
+                population.subpops[subpop].individuals[deadIndividual] = ind; 
+                                
+                // update duplicate hash table 
+                individualHash[subpop].remove(deadInd); 
+                                
+                if (statistics instanceof SteadyStateStatisticsForm) 
+                    ((SteadyStateStatisticsForm)statistics).individualsEvaluatedStatistics(this, 
+                        new Individual[]{ind}, new Individual[]{deadInd}, new int[]{subpop}, new int[]{deadIndividual}); 
+                }
+                                                
+            // INCREMENT NUMBER OF COMPLETED EVALUATIONS
+            evaluations++;
+            
+            // COMPUTE GENERATION BOUNDARY
+            generationBoundary = (evaluations % generationSize == 0);
+            }
+        else
+            {
+            generationBoundary = false; 
+            }
+
+        // SHOULD WE QUIT?
+        if (!partiallyFullSubpop && evaluator.runComplete(this) && quitOnRunComplete)
+            { 
+            output.message("Found Ideal Individual"); 
+            return R_SUCCESS;
+            }
+                
+        if ((numEvaluations > 0 && evaluations >= numEvaluations) ||  // using numEvaluations
+            (numEvaluations <= 0 && generationBoundary && generation == numGenerations -1))  // not using numEvaluations
+            {
+            return R_FAILURE;
+            }
+                
+                
+        // EXCHANGING
+        if (generationBoundary)
+            {
+            // PRE-BREED EXCHANGE 
+            statistics.prePreBreedingExchangeStatistics(this);
+            population = exchanger.preBreedingExchangePopulation(this);
+            statistics.postPreBreedingExchangeStatistics(this);
+            String exchangerWantsToShutdown = exchanger.runComplete(this);
+            if (exchangerWantsToShutdown!=null)
+                { 
+                output.message(exchangerWantsToShutdown); 
+                return R_SUCCESS;
+                }
+                        
+            // POST BREED EXCHANGE
+            statistics.prePostBreedingExchangeStatistics(this);
+            population = exchanger.postBreedingExchangePopulation(this);
+            statistics.postPostBreedingExchangeStatistics(this);
+                        
+            // INCREMENT GENERATION AND CHECKPOINT
+            generation++;
+            if (checkpoint && generation%checkpointModulo == 0) 
+                {
+                output.message("Checkpointing");
+                statistics.preCheckpointStatistics(this);
+                Checkpoint.setCheckpoint(this);
+                statistics.postCheckpointStatistics(this);
+                }
+            }
+        return R_NOTDONE;
+        }
+        
+    /**
+     * @param result
+     */
+    public void finish(int result)
+        {
+        /* finish up -- we completed. */
+        ((SteadyStateBreeder)breeder).finishPipelines(this);
+        statistics.finalStatistics(this,result);
+        finisher.finishPopulation(this,result);
+        exchanger.closeContacts(this,result);
+        evaluator.closeContacts(this,result);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateExchangerForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateExchangerForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateExchangerForm.java	(revision 6152)
@@ -0,0 +1,31 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.steadystate;
+
+/* 
+ * SteadyStateExchangerForm
+ * 
+ * Created: Tue Aug 10 21:59:17 1999
+ * By: Sean Luke
+ */
+
+/**
+ * The SteadyStateExchangerForm is a badge which Exchanger subclasses
+ * may wear if they work properly with the SteadyStateEvolutionState
+ * mechanism.  The basic thing such classes must remember to do is:
+ * Remember to call state.breeder.individualsReplaced(...) if
+ * you modify or replace any individuals in a subpopulation.  Also,
+ * realize that any individuals you exchange in will not be checked
+ * to see if they're the ideal individual
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface SteadyStateExchangerForm
+    {
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateStatisticsForm.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateStatisticsForm.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/SteadyStateStatisticsForm.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.steadystate;
+import ec.*;
+
+/* 
+ * SteadyStateStatisticsForm.java
+ * 
+ * Created: Fri Nov  9 20:45:26 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * This interface defines the hooks for SteadyStateEvolutionState objects
+ * to update themselves on.  Note that the the only methods in common
+ * with the standard statistics are initialization and final. This is an
+ * optional interface: SteadyStateEvolutionState will complain, but
+ * will permit Statistics objects that don't adhere to it, though they will
+ * only have their initialization and final statistics methods called!
+ *
+ * <p>See SteadyStateEvolutionState for how regular Statistics objects'
+ * hook methods are called in steady state evolution.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface SteadyStateStatisticsForm 
+    {
+    /** Called when we created an empty initial Population. */
+    public void enteringInitialPopulationStatistics(SteadyStateEvolutionState state);
+    /** Called when we have filled the initial population and are entering the steady state. */
+    public void enteringSteadyStateStatistics(int subpop, SteadyStateEvolutionState state);
+    /** Called each time new individuals are bred during the steady-state
+        process.   */
+    public void individualsBredStatistics(SteadyStateEvolutionState state, Individual[] individuals);
+    /** Called each time new individuals are evaluated during the steady-state
+        process, NOT including the initial generation's individuals. */
+    public void individualsEvaluatedStatistics(SteadyStateEvolutionState state, Individual[] newIndividuals, 
+        Individual[] oldIndividuals, int[] subpopulations, int[] indices);
+    /** Called when the generation count increments */ 
+    public void generationBoundaryStatistics(final EvolutionState state); 
+    /** Called immediately before checkpointing occurs. */
+    public void preCheckpointStatistics(final EvolutionState state);
+    /** Called immediately after checkpointing occurs. */
+    public void postCheckpointStatistics(final EvolutionState state);
+    /** Called immediately before the pre-breeding exchange occurs. */
+    public void prePreBreedingExchangeStatistics(final EvolutionState state);
+    /** Called immediately after the pre-breeding exchange occurs. */
+    public void postPreBreedingExchangeStatistics(final EvolutionState state);
+    /** Called immediately before the post-breeding exchange occurs. */
+    public void prePostBreedingExchangeStatistics(final EvolutionState state);
+    /** Called immediately after the post-breeding exchange occurs. */
+    public void postPostBreedingExchangeStatistics(final EvolutionState state);
+    /** Called immediately after the run has completed.  <i>result</i>
+        is either <tt>state.R_FAILURE</tt>, indicating that an ideal individual
+        was not found, or <tt>state.R_SUCCESS</tt>, indicating that an ideal
+        individual <i>was</i> found. */
+    public void finalStatistics(final EvolutionState state, final int result);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/steadystate/steadystate.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/steadystate/steadystate.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/steadystate/steadystate.params	(revision 6152)
@@ -0,0 +1,46 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+#
+# Some sample aditional parameters for steady-state evolution,
+# beyond what's provided in, say, simple/simple.params
+#
+
+# ec.Evolve
+# ==============================
+
+# simple generational evolution
+state = 				ec.steadystate.SteadyStateEvolutionState
+
+# We can EITHER say to run for N evaluations of subpopulation 0
+# (evaluations in other subpopulations are not counted) like this:
+# evaluations = 50000
+
+# ... or we can say to run for N generations, where a generation
+# is equal to the size of subpopulation 0.  After the initial population
+# is evaluated, only one additional individual is evaluated each time
+# generations = 50
+
+# threads should be 1 each
+evalthreads = 				1
+breedthreads = 				1
+
+# ec.EvolutionState
+# ==============================
+
+# We'll use a SimpleExchanger
+exch = 					ec.simple.SimpleExchanger
+
+# We MUST use a SteadyStateBreeder and SteadyStateEvaluator
+breed =					ec.steadystate.SteadyStateBreeder
+eval =					ec.steadystate.SteadyStateEvaluator
+
+# We must specify a deselector for each subpopulation.  Here is random
+# deselection for subpopulation 0.
+steady.deselector.0 =			ec.select.TournamentSelection
+steady.deselector.0.size =		1
+steady.deselector.0.pick-worst =	true
+
+# Traditionally, steady-state GAs try hard not to produce duplicates.
+steady.duplicate-retries =		100
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/BadParameterException.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/BadParameterException.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/BadParameterException.java	(revision 6152)
@@ -0,0 +1,27 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/*
+ * BadParameterException.java
+ * Created: Sat Aug  7 12:06:49 1999
+ */
+
+
+/**
+ *
+ * Thrown when you attempt to create a Parameter from bad path items.
+ *
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class BadParameterException extends RuntimeException
+    {
+    public BadParameterException(String s) { super("\n"+s); }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Checkpoint.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Checkpoint.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Checkpoint.java	(revision 6152)
@@ -0,0 +1,94 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.util.zip.*;
+import ec.EvolutionState;
+import java.io.*;
+
+/* 
+ * Checkpoint.java
+ * 
+ * Created: Tue Aug 10 22:39:19 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Checkpoints ec.EvolutionState objects out to checkpoint files, or 
+ * restores the same from checkpoint files.  Checkpoint take the following
+ * form:
+ *
+ * <p><i>checkpointPrefix</i><tt>.</tt><i>generation</i><tt>.gz</tt>
+ *
+ * <p>...where <i>checkpointPrefix</i> is the checkpoing prefix given
+ * in ec.EvolutionState, and <i>generation</i> is the current generation number
+ * also given in ec.EvolutionState.
+ * The ".gz" is added because the file is GZIPped to save space.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Checkpoint
+    {
+
+    /** Writes the evolution state out to a file. */
+
+    public static void setCheckpoint(EvolutionState state)
+        {
+        try
+            {
+            ObjectOutputStream s = 
+                new ObjectOutputStream(
+                    new GZIPOutputStream (
+                        new BufferedOutputStream(
+                            new FileOutputStream ("" + state.checkpointPrefix + 
+                                "." + state.generation + ".gz"))));
+            s.writeObject(state);
+            s.close();
+            state.output.message("Wrote out checkpoint file " + 
+                state.checkpointPrefix + "." + 
+                state.generation + ".gz");
+            }
+        catch (IOException e)
+            {
+            state.output.warning("Unable to create the checkpoint file " + 
+                state.checkpointPrefix + "." +
+                state.generation + ".gz" + 
+                "because of an IOException:\n--EXCEPTION--\n" +
+                e + 
+                "\n--EXCEPTION-END--\n");
+            }
+        }
+
+
+    /** Returns an EvolutionState object read from a checkpoint file
+        whose filename is <i>checkpoint</i> 
+        *
+        @exception java.lang.ClassNotFoundException thrown when the checkpoint file contains a class reference which doesn't exist in your class hierarchy.
+    **/
+    public static EvolutionState restoreFromCheckpoint(String checkpoint)
+        throws IOException, ClassNotFoundException, OptionalDataException
+    /* must throw something if error -- NEVER return null */
+        { 
+        // load from the file
+        ObjectInputStream s = 
+            new ObjectInputStream(
+                new GZIPInputStream (
+                    new BufferedInputStream (
+                        new FileInputStream (checkpoint))));
+
+        EvolutionState e = (EvolutionState) s.readObject();
+        s.close();
+
+        // restart from the checkpoint
+    
+        e.resetFromCheckpoint();
+        return e; 
+        }
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Code.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Code.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Code.java	(revision 6152)
@@ -0,0 +1,779 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.io.*;
+import ec.*;
+
+/* 
+ * Code.java
+ * 
+ * Created: Sat Oct 23 13:45:20 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Code provides some simple wrapper functions for encoding and decoding
+ * basic data types for storage in a pseudo-Java source code strings
+ * format.  This differs from just "printing"
+ * them to string in that the actual precision of the object is maintained.
+ * Code attempts to keep the representations as "Java-like" as possible --
+ * the exceptions being primarily floats and doubles, which are encoded as
+ * ints and longs.  Encoding of objects and arrays is not supported.  You'll
+ * have to handle that yourself.  Strings are supported.
+ *
+ * <p>Everything is case-SENSITIVE.  Here's the breakdown.
+ *
+
+ <p><table>
+ <tr><td><b>Type</b></td><td><b>Format</b></td></tr>
+ <tr><td>boolean</td><td><tt>true</tt> or <tt>false</tt> (old style, case sensitive) or <tt>T</tt> or <tt>F</tt> (new style, case sensitive)</td></tr>
+ <tr><td>byte</td><td><tt>b<i>byte</i>|</tt></td></tr>
+ <tr><td>short</td><td><tt>s<i>short</i>|</tt></td></tr>
+ <tr><td>int</td><td><tt>i<i>int</i>|</tt></td></tr>
+ <tr><td>long</td><td><tt>l<i>long</i>|</tt></td></tr>
+ <tr><td>float</td><td><tt>f<i>floatConvertedToIntForStorage</i>|<i>humanReadableFloat</i>|</tt> or (only for reading in) f|<i>humanReadableFloat</i>|</td></tr>
+ <tr><td>float</td><td><tt>d<i>doubleConvertedToLongForStorage</i>|<i>humanReadableDouble</i>|</tt> or (only for reading in) d|<i>humanReadableDouble</i>|</td></tr>
+ <tr><td>char</td><td>standard Java char, except that the only valid escape sequences are: \0 \t \n \b \' \" \ u <i>unicodeHex</i></td></tr>
+ <tr><td>string</td><td>standard Java string with \ u ...\ u Unicode escapes, except that the only other valid escape sequences are:  \0 \t \n \b \' \" </i></td></tr>
+ </table>
+ *
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Code 
+    {
+    /** Encodes a boolean. */
+    public static String encode(final boolean b) 
+    // old style -- no longer used
+    // { return b ? Boolean.TRUE.toString() : Boolean.FALSE.toString(); }
+        { return b ? "T" : "F"; }
+
+    /** Encodes a byte. */
+    public static String encode(final byte b) 
+        { return "b" + Byte.toString(b) + "|"; }
+
+    /** Encodes a character. */
+    public static String encode(final char c)
+        {
+        if (c >= 32 && c < 127 && c !='\\' && 
+            c!= '\'') // we can safely print it
+            return "'" + String.valueOf(c) + "'";
+        else
+            {
+            // print it with an escape character
+            if (c=='\b')
+                return "'\\b'";
+            else if (c=='\n')
+                return "'\\n'";
+            else if (c=='\t')
+                return "'\\t'";
+            else if (c=='\'')
+                return "'\\''";
+            else if (c=='\\')
+                return "'\\\\'";
+            else if (c=='\0')
+                return "'\\\\0";
+            else
+                {
+                String s = Integer.toHexString((int)c);
+                // pad with 0's  -- Java's parser freaks out otherwise
+                switch (s.length())
+                    {
+                    case 1:  s = "'\\u000" + s + "'"; break;
+                    case 2:  s = "'\\u00" + s + "'"; break;
+                    case 3:  s = "'\\u0" + s + "'"; break;
+                    case 4:  s = "'\\u" + s + "'"; break;
+                    }
+                return s;
+                }
+            }
+        }
+
+    /** Encodes a short. */
+    public static String encode(final short s)
+        { return "s" + Short.toString(s) + "|"; }
+
+    /** Encodes an int. */
+    public static String encode(final int i)
+        { return "i" + Integer.toString(i) + "|";  }
+    
+    /** Encodes a long. */
+    public static String encode(final long l)
+        { return "l" + Long.toString(l) + "|"; }
+
+    /** Encodes a float. */
+    public static String encode(final float f)
+        { return "f" + Integer.toString(Float.floatToIntBits(f))+ "|" + String.valueOf(f) + "|"; }
+
+    /** Encodes a double. */
+    public static String encode(final double d)
+        { return "d" + Long.toString(Double.doubleToLongBits(d))+ "|" + String.valueOf(d) + "|"; }
+
+    /** Encodes a String. */
+    public static String encode(final String s)
+        {
+        boolean inUnicode = false;
+        int l = s.length();
+        StringBuffer sb = new StringBuffer(l);
+        sb.append("\"");
+        for(int x=0;x<l;x++)
+            {
+            char c = s.charAt(x);
+            if ( c >= 32 && c < 127 && c !='\\' && c!= '"') // we allow spaces
+                // we can safely print it
+                {
+                if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                sb.append(c);
+                }
+            else
+                {
+                // print it with an escape character
+                if (c=='\b')
+                    {
+                    if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                    sb.append("\\b");
+                    }
+                else if (c=='\n')
+                    {
+                    if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                    sb.append("\\n");
+                    }
+                else if (c=='\t')
+                    {
+                    if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                    sb.append("\\t");
+                    }
+                else if (c=='"')
+                    {
+                    if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                    sb.append("\\\"");
+                    }
+                else if (c=='\\')
+                    {
+                    if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                    sb.append("\\\\");
+                    }
+                else if (c=='\0')
+                    {
+                    if (inUnicode) { sb.append("\\u"); inUnicode=false; } 
+                    sb.append("\\0");
+                    }
+                else
+                    {
+                    if (!inUnicode) {sb.append("\\u"); inUnicode=true; }
+                    String ss = Integer.toHexString((int)c);
+                    // pad with 0's  -- Java's parser freaks out otherwise
+                    switch (ss.length())
+                        {
+                        case 1:  sb.append("000" + ss); break;
+                        case 2:  sb.append("00" + ss); break;
+                        case 3: sb.append("0" + ss); break;
+                        case 4: sb.append(ss); break;
+                        }
+                    }
+                }
+            }
+        if (inUnicode) sb.append("\\u");
+        sb.append("\"");
+        return sb.toString();
+        }
+
+
+
+
+
+
+
+
+
+    /** Decodes the next item out of a DecodeReturn and modifies the DecodeReturn to hold the results.  See DecodeReturn for more
+        explanations about how to interpret the results. */
+
+    public static void decode(DecodeReturn d)
+        {
+        String dat = d.data;
+        int x = d.pos;
+        int len = d.data.length();
+
+        // look for whitespace or ( or )
+        for ( ; x<len; x++ ) 
+            if (!Character.isWhitespace(dat.charAt(x))) break;
+
+        // am I at the end of my rope?
+        if (x==len) { d.type = DecodeReturn.T_ERROR; d.s = "Out of tokens"; return; }
+
+        // what type am I?
+        switch(dat.charAt(x))
+            {
+
+            case 't': // boolean (true)
+                if (x+3 < len && /* enough space */ 
+                    dat.charAt(x+1)=='r' && 
+                    dat.charAt(x+2)=='u' && 
+                    dat.charAt(x+3)=='e')
+                    { d.type = DecodeReturn.T_BOOLEAN; d.l = 1; d.pos = x+4; return; }
+                else { d.type = DecodeReturn.T_ERROR; d.s = "Expected a (true) boolean"; return; }
+                //break;
+
+            case 'T': // boolean (true)
+            { d.type = DecodeReturn.T_BOOLEAN; d.l = 1; d.pos = x+1; return; }
+            //break;
+                    
+            case 'F': // boolean (false)
+            { d.type = DecodeReturn.T_BOOLEAN; d.l = 0; d.pos = x+1; return; }
+            //break;
+                    
+
+
+
+            case 'f': // float or boolean
+                if (x+4 < len && /* enough space */ 
+                    dat.charAt(x+1)=='a' && dat.charAt(x+2)=='l' && dat.charAt(x+3)=='s' && dat.charAt(x+4)=='e' )
+                    { d.type = DecodeReturn.T_BOOLEAN; d.l = 0; d.pos = x+5; return; }
+                else
+                    {
+                    boolean readHuman = false;
+                    String sf = null;
+                    int initial = x+1;
+                                
+                    // look for next '|'
+                    for ( ; x < len; x++)
+                        if (dat.charAt(x)=='|') break;
+                    
+                    if (x==initial) readHuman=true;
+                                
+                    if ( x >= len )
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Expected a float"; return; }
+
+                    if (!readHuman)
+                        sf = dat.substring(initial,x);
+                    x++;
+                    
+                    // look for next '|'
+                    int initial2 = x;  // x is now just past first |
+                    for ( ; x < len; x++)
+                        if (dat.charAt(x)=='|') break;
+                    
+                    if ( x >= len )
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Expected a float"; return; }
+                    if (readHuman) 
+                        sf = dat.substring(initial2,x);
+                    
+                    float f;
+                    try 
+                        { 
+                        if (readHuman) f = Float.parseFloat(sf);
+                        else f = Float.intBitsToFloat(Integer.parseInt(sf)); 
+                        }
+                    catch (NumberFormatException e)
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Expected a float"; return; }
+                    d.type = DecodeReturn.T_FLOAT;
+                    d.d = f;
+                    d.pos = x+1;
+                    return;
+                    }
+
+
+
+
+
+
+
+
+            case 'd': // double
+                
+            {
+            boolean readHuman = false;
+            String sf = null;
+            int initial = x+1;
+                        
+            // look for next '|'
+            for ( ; x < len; x++)
+                if (dat.charAt(x)=='|') break;
+            
+            if (x==initial) readHuman=true;
+                        
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a double"; return; }
+
+            if (!readHuman)
+                sf = dat.substring(initial,x);
+            x++;
+            
+            // look for next '|'
+            int initial2 = x;  // x is now just past first |
+            for ( ; x < len; x++)
+                if (dat.charAt(x)=='|') break;
+            
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a double"; return; }
+            if (readHuman) 
+                sf = dat.substring(initial2,x);
+            
+            double f;
+            try 
+                { 
+                if (readHuman) f = Double.parseDouble(sf);
+                else f = Double.longBitsToDouble(Long.parseLong(sf)); 
+                }
+            catch (NumberFormatException e)
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a double"; return; }
+            d.type = DecodeReturn.T_DOUBLE;
+            d.d = f;
+            d.pos = x+1;
+            return;
+            }
+            // break;
+                        
+                        
+
+
+
+
+
+
+            case 'b': // byte
+                
+            {
+            int initial = x+1;
+                        
+            // look for next '|'
+            for ( ; x < len; x++)
+                if (dat.charAt(x)=='|') break;
+                        
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a byte"; return; }
+            String sf = dat.substring(initial,x);
+                                            
+            byte f;
+            try 
+                { f = Byte.parseByte(sf); }
+            catch (NumberFormatException e)
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a byte"; return; }
+            d.type = DecodeReturn.T_BYTE;
+            d.l = f;
+            d.pos = x+1;
+            return;
+            }
+            // break;
+
+
+
+
+
+
+            case 's': // short
+                
+            {
+            int initial = x+1;
+                        
+            // look for next '|'
+            for ( ; x < len; x++)
+                if (dat.charAt(x)=='|') break;
+                        
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a short"; return; }
+            String sf = dat.substring(initial,x);
+                                            
+            short f;
+            try 
+                { f = Short.parseShort(sf); }
+            catch (NumberFormatException e)
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a short"; return; }
+            d.type = DecodeReturn.T_SHORT;
+            d.l = f;
+            d.pos = x+1;
+            return;
+            }
+            // break;
+
+
+
+
+            case 'i': // int
+                
+            {
+            int initial = x+1;
+                        
+            // look for next '|'
+            for ( ; x < len; x++)
+                if (dat.charAt(x)=='|') break;
+                        
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected an int"; return; }
+            String sf = dat.substring(initial,x);
+                                            
+            int f;
+            try 
+                { f = Integer.parseInt(sf); }
+            catch (NumberFormatException e)
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected an int"; return; }
+            d.type = DecodeReturn.T_INT;
+            d.l = f;
+            d.pos = x+1;
+            return;
+            }
+            // break;
+
+
+
+
+
+
+            case 'l': // long
+                
+            {
+            int initial = x+1;
+                        
+            // look for next '|'
+            for ( ; x < len; x++)
+                if (dat.charAt(x)=='|') break;
+                        
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a long"; return; }
+            String sf = dat.substring(initial,x);
+                                            
+            long f;
+            try 
+                { f = Long.parseLong(sf); }
+            catch (NumberFormatException e)
+                { d.type = DecodeReturn.T_ERROR; d.s = "Expected a long"; return; }
+            d.type = DecodeReturn.T_LONG;
+            d.l = f;
+            d.pos = x+1;
+            return;
+            }
+            // break;
+
+
+
+
+
+
+            case '"':  // string
+            {
+            StringBuffer sb = new StringBuffer();
+            boolean inUnicode = false;
+            
+            x++;
+            for ( ; x < len; x++)
+                {
+                char c = dat.charAt(x);
+                if (c=='"') 
+                    {
+                    // done with the string
+                    if (inUnicode)  // uh oh
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Forgot to terminate Unicode with a '\\u' in the string"; return; }
+                    d.type = DecodeReturn.T_STRING; 
+                    d.s = sb.toString(); 
+                    d.pos = x+1;
+                    return;
+                    }
+                else if (c=='\\')  // escape
+                    {
+                    x++;
+                    if ( x >= len )
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Unterminated String"; return; }
+                    if (dat.charAt(x)!='u')
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Escape character in Unicode sequence"; return; }
+
+                    switch (dat.charAt(x))
+                        {
+                        case 'u': inUnicode = !inUnicode; break;
+                        case 'b': sb.append('\b'); break;
+                        case 'n': sb.append('\n'); break;
+                        case '"': sb.append('"'); break;
+                        case '\'': sb.append('\''); break;
+                        case 't': sb.append('\t'); break;
+                        case '\\': sb.append('\\'); break;
+                        case '0': sb.append('\0'); break;
+                        default: 
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Bad escape char in String"; return; }
+                        }
+                    }
+                else if (inUnicode)
+                    {
+                    if ( x + 3 >= len )
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Unterminated String"; return; }
+                    try
+                        {
+                        sb.append((char)(Integer.decode("0x" + c +
+                                    dat.charAt(x+1) +
+                                    dat.charAt(x+2) +
+                                    dat.charAt(x+3)).intValue()));;
+                        x+=3;
+                        }
+                    catch (NumberFormatException e)
+                        { d.type = DecodeReturn.T_ERROR; d.s = "Bad Unicode in String"; return; }
+                    }
+                else sb.append(c);
+                }
+            d.type = DecodeReturn.T_ERROR; d.s = "Unterminated String"; return;
+            }
+            //break;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+            case '\'': // char
+            {
+            x++;
+            if ( x >= len )
+                { d.type = DecodeReturn.T_ERROR; d.s = "Unterminated char"; return; }
+            char c = dat.charAt(x);
+            if (c=='\\')
+                {
+                x++;
+                if (x>=len)
+                    { d.type = DecodeReturn.T_ERROR; d.s = "Unterminated char"; return; }
+                switch (dat.charAt(x))
+                    {
+                    case 'u':
+                        if ( x + 4 >= len )
+                            { d.type = DecodeReturn.T_ERROR; d.s = "Unterminated char"; return; }
+                        try
+                            {
+                            c = (char)(Integer.decode("0x" + 
+                                    dat.charAt(x+1) +
+                                    dat.charAt(x+2) +
+                                    dat.charAt(x+3) +
+                                    dat.charAt(x+4)).intValue());
+                            }
+                        catch (NumberFormatException e)
+                            { d.type = DecodeReturn.T_ERROR; d.s = "Bad Unicode in char"; return; }
+                        x+=5;
+                        break;
+                    
+                    case 'b': c = '\b'; x++; break;
+                    case 'n': c = '\n'; x++; break;
+                    case '"': c = '"'; x++; break;
+                    case '\'': c = '\''; x++; break;
+                    case 't':  c = '\t'; x++; break;
+                    case '\\': c = '\\'; x++; break;
+                    case '0': c = '\0';  x++; break;
+                    default: 
+                    { d.type = DecodeReturn.T_ERROR; d.s = "Bad escape char in char"; return; }
+                    }
+                if (dat.charAt(x)!='\'')
+                    { d.type = DecodeReturn.T_ERROR; d.s = "Bad char"; return; }
+                d.type = DecodeReturn.T_CHAR;
+                d.l = c;
+                d.pos = x+1;
+                return;
+                }
+            else
+                {
+                x++;
+                if ( x >= len )
+                    { d.type = DecodeReturn.T_ERROR; d.s = "Unterminated char"; return; }
+                if (dat.charAt(x)!='\'')
+                    { d.type = DecodeReturn.T_ERROR; d.s = "Bad char"; return; }
+                d.type = DecodeReturn.T_CHAR;
+                d.l = c;
+                d.pos = x + 1;
+                return;
+                }
+
+
+            }
+            //break;
+
+
+
+
+
+
+            
+            default: 
+                d.type = DecodeReturn.T_ERROR; d.s = "Unknown token"; return; 
+                // break;
+            }
+        }
+
+    /** Finds the next nonblank line, then trims the line and checks the preamble.  Returns a DecodeReturn on the line if successful, else posts a fatal error.
+        Sets the DecodeReturn's line number.  The DecodeReturn has not yet been decoded.  You'll need to do that with Code.decode(...) */
+    public static DecodeReturn checkPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        int linenumber = 0;  // throw it away later
+        try
+            {
+            // get non-blank line
+            String s = "";
+            while(s != null && s.trim().equals(""))
+                {
+                linenumber = reader.getLineNumber();
+                s = reader.readLine();
+                }
+
+            // check the preamble
+            if (s==null || !(s = s.trim()).startsWith(preamble)) // uh oh
+                state.output.fatal("Line " + linenumber + 
+                    " has a bad preamble.Expected '" + preamble + "'\n-->" + s);
+            DecodeReturn d = new DecodeReturn(s, preamble.length());
+            d.lineNumber = linenumber;
+            return d;
+            }
+        catch (IOException e)
+            {
+            state.output.fatal("On line " + linenumber + " an IO error occurred:\n\n" + e);
+            return null;  // never happens
+            }
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a string if there is one, and returns it.
+        Generates an error otherwise. */
+    public static String readStringWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_STRING)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no string after preamble '" + preamble + "'\n-->" + d.data);
+        return (String)(d.s);
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a character if there is one, and returns it.
+        Generates an error otherwise. */
+    public static char readCharacterWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_CHAR)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no character after preamble '" + preamble + "'\n-->" + d.data);
+        return (char)(d.l);
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a byte if there is one, and returns it.
+        Generates an error otherwise. */
+    public static byte readByteWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_BYTE)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no byte after preamble '" + preamble + "'\n-->" + d.data);
+        return (byte)(d.l);
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a short if there is one, and returns it.
+        Generates an error otherwise. */
+    public static short readShortWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_SHORT)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no short after preamble '" + preamble + "'\n-->" + d.data);
+        return (short)(d.l);
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a long if there is one, and returns it.
+        Generates an error otherwise. */
+    public static long readLongWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_LONG)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no long after preamble '" + preamble + "'\n-->" + d.data);
+        return (long)(d.l);
+        }
+        
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in an integer if there is one, and returns it.
+        Generates an error otherwise. */
+    public static int readIntegerWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_INT)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no integer after preamble '" + preamble + "'\n-->" + d.data);
+        return (int)(d.l);
+        }
+
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a float if there is one, and returns it. 
+        Generates an error otherwise. */
+    public static float readFloatWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_FLOAT)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no floating point number after preamble '" + preamble + "'\n-->" + d.data);
+        return (float)(d.d);
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a double if there is one, and returns it. 
+        Generates an error otherwise. */
+    public static double readDoubleWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_DOUBLE)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no double floating point number after preamble '" + preamble + "'. -->" + d.data);
+        return d.d;
+        }
+
+    /** Finds the next nonblank line, skips past an expected preamble, and reads in a boolean value ("true" or "false") if there is one, and returns it. 
+        Generates an error otherwise. */
+    public static boolean readBooleanWithPreamble(String preamble, final EvolutionState state, 
+        final LineNumberReader reader)
+        {
+        DecodeReturn d = checkPreamble(preamble, state, reader);
+        Code.decode(d);
+        if (d.type!=DecodeReturn.T_BOOLEAN)
+            state.output.fatal("Line " + d.lineNumber + 
+                " has no boolean value ('true' or 'false') after preamble '" + preamble + "'\n-->" + d.data);
+        return (d.l != 0);
+        }
+
+    }
+
+
+/*
+  (BeanShell testing for decoding)
+
+  s = "      true false s-12| i232342|b22|f234123|3234.1| d234111231|4342.31|"
+
+
+  s = "\"Hello\" true false s-12| i232342|b22|f234123|3234.1| d234111231|4342.31| ' ' '\\'' '\\n' \"Hello\\u0000\\uWorld\""
+  c = new ec.util.Code();
+  r = new ec.util.DecodeReturn(s);
+
+  c.decode(r);
+  System.out.println(r.type);
+  System.out.println(r.l);
+
+  System.out.println(r.d);
+  System.out.println(r.s);
+
+*/
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/DataPipe.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/DataPipe.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/DataPipe.java	(revision 6152)
@@ -0,0 +1,150 @@
+/*
+  Copyright 2009 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.io.*;
+
+/*
+  DataPipe is a mechanism which allows you to pipe data from an OutputStream to an InputStream within a single thread.
+  This differs from a PipedInputStream/PipedOutputSteam pair in that it permits a single thread (in fact requires it
+  due to lack of synchronization for speed).  To do this, the DataPipe maintains an extensible buffer which gets as large
+  as necessary when filled with data from the InputStream, then expels it out the OutputStream when called.  The
+  default Input and Output streams of a DataPipe are DataInputStream and DataOutputStream, since reading and writing
+  binary objects is its primary function.
+
+  <p>The procedure is as follows: create the DataPipe, then start writing to its DataInputStream.  When you are done,
+  start reading from its DataOutputStream. DataPipe is meant to be one-shot: write a bunch of stuff, then read <i>all</i> of it.
+  You shouldn't read and write piecemeal as the DataPipe is not a true circular buffer and will grow without bound with wasted
+  space equal to the amount you've read so far.
+
+  <p>You <i>can</i>, however, reuse the DataPipe by calling reset() on it.  
+  Note that this retains the current buffer however large it has grown to.
+*/
+
+public class DataPipe
+    {
+    // an extensible array which can be pushed into, then pulled out of
+    byte[] buffer = new byte[8192];
+
+    // the number of bytes in the array -- in reality this is the number of bytes written to the array so far
+    int size = 0;
+    
+    // the number of bytes read from the array.  pull will always trail size
+    int pull = 0;
+    
+    // Double the size of the buffer
+    void resize()
+        {
+        byte[] newbuffer = new byte[buffer.length * 2];
+        System.arraycopy(buffer, 0, newbuffer, 0, buffer.length);
+        buffer = newbuffer;
+        }
+    
+    // Add a byte to the buffer
+    void push(byte b)
+        {
+        if (size >= buffer.length) resize();
+        buffer[size++] = b;
+        }
+    
+    // Add bytes to the buffer, read from b[offset]... b[offset+length-1]
+    void push(byte[] b, int offset, int length)
+        {
+        if (size + length > buffer.length) resize();
+        System.arraycopy(b, offset, buffer, size, length);
+        size += length;
+        }
+        
+    // Return an unsigned byte read from the buffer.
+    // If there are no bytes left to read, -1 is returned.
+    int pull()
+        {
+        if (pull==size) return -1;  // EOF
+        byte b = buffer[pull++];
+        if (b < 0) return b + 256;
+        return b;
+        }
+    
+    // Provide up to *length* bytes from the buffer.  They are
+    // placed into b[offset] ... b[offset + length - 1].
+    // If there aren't *length* bytes in the buffer, some number
+    // less than that is actually provided.  The actual number
+    // of bytes provided is returned.
+    // If there are no bytes left to read at all, -1 is returned.
+    int pull(byte[] b, int offset, int length)
+        {
+        if (pull==size) return -1;
+        if (length > size-pull) length = size-pull;
+        System.arraycopy(buffer, pull, b, offset, length);
+        pull += length;
+        return length;
+        }
+    
+    /** The input stream */
+    public DataInputStream input;
+    /** The output stream */
+    public DataOutputStream output;
+    
+    public DataPipe()
+        {
+        OutputStream outStream = new OutputStream()
+            {
+            public void write(int b) throws IOException { push((byte)b); }
+            public void write(byte[] b, int off, int len) throws IOException { push(b, off, len); }
+            public void write(byte[] b) throws IOException { push(b, 0, b.length); }
+            };
+        output = new DataOutputStream(outStream);
+        
+        InputStream inStream = new InputStream()
+            {
+            public int read() throws IOException { return pull(); }
+            public int read(byte[] b, int off, int len) throws IOException { return pull(b, off, len); }
+            public int read(byte[] b) throws IOException { return pull(b, 0, b.length); }
+            };
+        
+        input = new DataInputStream(inStream);
+        }
+    
+    /** Reset the buffer.  Does not resize it back to a smaller size -- if it has ballooned it will
+        stay large, though it will no longer have wasted space in it.  If you wish to make the buffer
+        a more manageable size, create a new DataPipe instead. */
+    public void reset()
+        {
+        pull = size = 0;
+        }
+        
+    /** Returns the total size of the buffer. */
+    public int size()
+        {
+        return buffer.length;
+        }
+    
+    /** Returns the number of elements written to the buffer so far (after the last reset()). */
+    public int numWritten()
+        {
+        return size;
+        }
+        
+    /** Returns the number of elements read from the buffer so far (after the last reset()). */
+    public int numRead()
+        {
+        return pull;
+        }
+        
+    /** A poor-man's clone for serializable but not cloneable objects:
+        serializes an object to the pipe, then deserializes it. */
+    public static Object copy(Serializable obj) throws IOException, ClassNotFoundException
+        {
+        DataPipe pipe = new DataPipe();
+        ObjectOutputStream s = new ObjectOutputStream(pipe.output);
+        ObjectInputStream u = new ObjectInputStream(pipe.input);
+        s.writeObject(obj);
+        return u.readObject();
+        }
+
+    public String toString() { return "DataPipe(" + numWritten() + ", " + numRead() + ", " + size() + ")"; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/DecodeReturn.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/DecodeReturn.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/DecodeReturn.java	(revision 6152)
@@ -0,0 +1,95 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * DecodeReturn.java
+ * 
+ * Created: Sat Oct 23 15:23:39 1999
+ * By: Sean Luke
+ */
+
+/**
+ * DecodeReturn is used by Code to provide varied information returned
+ * when decoding. 
+ * You start the decoding process by initializing the DecodeReturn
+ * on a string you want to decode items out of.  Then you repeatedly
+ * pass the DecodeReturn to Code.decode(...), and each time the
+ * DecodeReturn will contain information about the next token, namely,
+ * its type, the data of the token (depending on type, this
+ * can be in one of three slots, d, l, or s), and the start position
+ * for reading the next token.
+ *
+ * <p>In case of an error, type is set to DecodeReturn.T_ERROR,
+ * pos is kept at the token where the error occured, and
+ * s is set to an error message.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class DecodeReturn 
+    {
+    /** The actual error is stored in the String slot */
+    public static final byte T_ERROR = -1;
+
+    public static final byte T_BOOLEAN = 0;
+    public static final byte T_BYTE = 1;
+    public static final byte T_CHAR = 2;
+    /** Same as T_CHAR */
+    public static final byte T_CHARACTER = 2;
+    public static final byte T_SHORT = 3;
+    public static final byte T_INT = 4;
+    /** Same as T_INT */
+    public static final byte T_INTEGER = 4;
+    public static final byte T_LONG = 5;
+    public static final byte T_FLOAT = 6;
+    public static final byte T_DOUBLE = 7;
+    public static final byte T_STRING = 8;
+
+    /** The Line number, if it has been posted. */
+    public int lineNumber = 0;
+    
+    /** The DecodeReturn type */
+    public byte type;
+
+    /** The DecodeReturn string that's read from. */
+    public String data;
+
+    /** The DecodeReturn new position in the string.  Set this yourself.
+        New values get set here automatically. */
+    public int pos;
+
+    /** Stores booleans (0=false), bytes, chars, shorts, ints, longs */
+    public long l;
+
+    /** Stores floats, doubles */
+    public double d;
+    
+    /** Stores strings, error messages */
+    public String s;
+
+    /** Use this to make a new DecodeReturn starting at position 0 */
+    public DecodeReturn(String _data) { data = _data; pos = 0; }
+
+    /** Use this to make a new DecodeReturn starting at some position */
+    public DecodeReturn(String _data, int _pos) { data = _data; pos = _pos; }
+
+    /** Sets the DecodeReturn to begin scanning at _pos, which should be valid. */
+    public DecodeReturn scanAt(int _pos) 
+        {
+        pos = Math.min(Math.max(_pos,0),data.length());
+        return this;
+        }
+
+    /** Use this to reuse your DecodeReturn for another string */
+    public DecodeReturn reset(final String _data) { data = _data; pos = 0; return this; }
+    
+    /** Use this to reuse your DecodeReturn for another string */
+    public DecodeReturn reset(final String _data, int _pos) { data = _data; pos = _pos; return this; }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Lexer.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Lexer.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Lexer.java	(revision 6152)
@@ -0,0 +1,83 @@
+package ec.util;
+import java.util.regex.*;
+
+/*
+ * Lexer.java
+ *
+ * Created: Sun Dec  5 11:33:43 EST 2010
+ * By: Sean Luke
+ *
+ */
+
+/**
+ * A simple line-by-line String tokenizer.  You provide Lexer with a String or other
+ * CharSequence as input, plus an array of regular expressions.  Each time you call
+ * nextToken(...), the Lexer matches the next token against the regular expressions
+ * and returns it.  The regular expressions are checked in order, and the first one
+ * that matches is the winner.
+ * 
+ */
+
+public class Lexer
+    {
+    /** An index which indicates that no further tokens were found.  This could be due to the end of the string or due to a bad
+        string.  You'll need to check the index to determine for sure.*/
+    public static final int FAILURE = -1;
+        
+    CharSequence input;
+    int position = 0;
+    Matcher[] matchers;
+    String[] regexps;
+    int matchingIndex = FAILURE;
+        
+    /** Builds a Lexer for the given input with the provided regular expressions.  The regular expressions
+        will be checked in order against the input, and the first one which matches will be assumed to be the token.*/
+                
+    public Lexer(CharSequence input, String[] regexps)
+        {
+        this.regexps = regexps;
+        matchers = new Matcher[regexps.length];
+        for(int i = 0 ; i < regexps.length; i++)
+            matchers[i] = Pattern.compile(regexps[i]).matcher(input);  // not DOTALL
+        this.input = input;
+        }
+        
+    /** Returns the next token as a string.  If *trim* is true, then the string is first trimmed of whitespace. */
+    public String nextToken(boolean trim)
+        {
+        for(int i = 0 ; i < regexps.length; i++)
+            {
+            if (!matchers[i].region(position, input.length()).lookingAt()) continue;
+            position = matchers[i].end();
+            matchingIndex = i;
+            return ( trim ? matchers[i].group().trim() : matchers[i].group() );
+            }
+        // we failed
+        matchingIndex = -1;
+        return null; 
+        }
+
+    /** Returns the next token as a string.  The string is first trimmed of whitespace. */
+    public String nextToken() { return nextToken(true); }
+        
+
+    /** Returns the index of the regular expression which matched the most recent token. */
+    public int getMatchingIndex() 
+        {
+        return matchingIndex;
+        }
+                
+    /** Returns the regular expression which matched the most recent token. */
+    public String getMatchingRule()
+        {
+        if (matchingIndex == -1) return null;
+        return regexps[matchingIndex];
+        }
+                
+    /** Returns the position in the String just beyond the most recent token. */
+    public int getMatchingPosition() 
+        {
+        return position;
+        }
+        
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/LocalHost.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/LocalHost.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/LocalHost.java	(revision 6152)
@@ -0,0 +1,296 @@
+package ec.util;
+
+import java.net.*;
+import java.util.*;
+
+/**
+ * Modified from <a href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200803.mbox/%3C1066089445.1204637680849.JavaMail.jira@brutus%3E">
+ * apache mail-archives</a>. 
+ *
+ * This code was published in the public domain, but I believe it was probably intended to be
+ * distributed under the Apache license, like the rest of the Jakarta code.  That license is
+ * listed at the end of this file.
+ *
+ */
+ 
+public class LocalHost 
+    {
+    /**
+     * Returns an <code>InetAddress</code> object encapsulating what is most
+     * likely the machine's LAN IP address. <p/> This method is intended for use
+     * as a replacement of JDK method <code>InetAddress.getLocalHost</code>,
+     * because that method is ambiguous on Linux systems. Linux systems
+     * enumerate the loopback network interface the same way as regular LAN
+     * network interfaces, but the JDK <code>InetAddress.getLocalHost</code>
+     * method does not specify the algorithm used to select the address returned
+     * under such circumstances, and will often return the loopback address,
+     * which is not valid for network communication. Details <a
+     * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037"
+     * >here</a>. <p/> This method will scan all IP addresses on all network
+     * interfaces on the host machine to determine the IP address most likely to
+     * be the machine's LAN address. If the machine has multiple IP addresses,
+     * this method will prefer a site-local IP address (e.g. 192.168.x.x or
+     * 10.10.x.x, usually IPv4) if the machine has one (and will return the
+     * first site-local address if the machine has more than one), but if the
+     * machine does not hold a site-local address, this method will return
+     * simply the first non-loopback address found (IPv4 or IPv6). <p/> If this
+     * method cannot find a non-loopback address using this selection algorithm,
+     * it will fall back to calling and returning the result of JDK method
+     * <code>InetAddress.getLocalHost</code>. <p/>
+     * 
+     * @throws UnknownHostException
+     *             If the LAN address of the machine cannot be found.
+     */
+    public static InetAddress getLocalHost() throws UnknownHostException 
+        {
+        try 
+            {
+            InetAddress candidateAddress = null;
+            // Iterate all NICs (network interface cards)...
+            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();)
+                {
+                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
+                // Iterate all IP addresses assigned to each card...
+                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();)
+                    {
+                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
+                    if (!inetAddr.isLoopbackAddress()) 
+                        {
+                        if (inetAddr.isSiteLocalAddress()) return inetAddr;  // Found non-loopback site-local address.
+
+                        // Found non-loopback address, but not necessarily site-local.
+                        // Store it as a candidate to be returned if site-local address is not subsequently found...
+                        // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
+                        // only the first. For subsequent iterations, candidate will be non-null.
+                        else if (candidateAddress == null) candidateAddress = inetAddr;
+                        }
+                    }
+                }
+            // We did not find a site-local address, but we found some other non-loopback address.
+            // Server might have a non-site-local address assigned to its NIC (or it might be running
+            // IPv6 which deprecates the "site-local" concept).
+            // Return this non-loopback candidate address...
+            if (candidateAddress != null) return candidateAddress;
+
+            // At this point, we did not find a non-loopback address.
+            // Fall back to returning whatever InetAddress.getLocalHost() returns...
+            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
+            if (jdkSuppliedAddress == null)
+                throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
+            return jdkSuppliedAddress;
+            }
+        catch (Exception e) 
+            {
+            UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e);
+            unknownHostException.initCause(e);
+            throw unknownHostException;
+            }
+        }
+    }
+
+
+
+/*
+
+  Apache License
+  Version 2.0, January 2004
+  http://www.apache.org/licenses/
+
+  TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+  1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+  2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+  3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+  4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+  Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+  stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+  that You distribute, all copyright, patent, trademark, and
+  attribution notices from the Source form of the Work,
+  excluding those notices that do not pertain to any part of
+  the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+  distribution, then any Derivative Works that You distribute must
+  include a readable copy of the attribution notices contained
+  within such NOTICE file, excluding those notices that do not
+  pertain to any part of the Derivative Works, in at least one
+  of the following places: within a NOTICE text file distributed
+  as part of the Derivative Works; within the Source form or
+  documentation, if provided along with the Derivative Works; or,
+  within a display generated by the Derivative Works, if and
+  wherever such third-party notices normally appear. The contents
+  of the NOTICE file are for informational purposes only and
+  do not modify the License. You may add Your own attribution
+  notices within Derivative Works that You distribute, alongside
+  or as an addendum to the NOTICE text from the Work, provided
+  that such additional attribution notices cannot be construed
+  as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+  5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+  6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+  7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+  8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+  9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+  END OF TERMS AND CONDITIONS
+
+  APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+  Copyright [yyyy] [name of copyright owner]
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Log.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Log.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Log.java	(revision 6152)
@@ -0,0 +1,232 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.io.*;
+import java.util.zip.*;
+
+/*
+ * Log.java
+ * Created: Sun Aug  8 18:53:49 1999
+ */
+
+/**
+ * Defines a log to which Output outputs. 
+ *
+ * Logs can be <i>restarted</i> after a computer outage by using the 
+ * information stored in the LogRestarter
+ * <tt>restarter</tt>.  
+ *
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+
+public class Log implements Serializable
+    {
+    // basic log features
+
+    /** The log's writer */
+    public transient PrintWriter writer;   // the actual writer.
+
+    /** A filename, if the writer writes to a file */
+    public File filename;                // the filename to write to, if any
+
+    /** Should the log post announcements? */
+    public boolean postAnnouncements;      // will the log post announcements?
+
+    // stuff for restarting
+
+    /** The log's restarter */
+    public LogRestarter restarter;         // resets the log
+
+    /** Should the log repost all announcements on restart */
+    public boolean repostAnnouncementsOnRestart;   // repost all announcements?
+
+    /** If the log writes to a file, should it append to the file on restart,
+        or should it overwrite the file? */
+    public boolean appendOnRestart;        // append to a file or replace it?
+    
+    public boolean isLoggingToSystemOut;
+
+
+    // values for specifying logs based on System.out or System.err
+
+    /** Specifies that the log should write to stdout (System.out) */
+    public final static int D_STDOUT = 0;
+    
+    /** Specifies that the log should write to stderr (System.err) */
+    public final static int D_STDERR = 1;
+
+    protected void finalize() throws Throwable 
+        { 
+        // rarely happens though... :-(
+        super.finalize();
+        if (writer!=null && !isLoggingToSystemOut) writer.close();
+        }
+
+    /** Creates a log to a given filename; this file may or may not
+        be appended to on restart, depending on _appendOnRestart.  If
+        and only if the file is <i>not</i> appended to on restart, then
+        announcements are reposted on restart.*/
+    
+    public Log(File _filename,
+        boolean _postAnnouncements,
+        boolean _appendOnRestart) throws IOException
+        {
+        this(_filename, _postAnnouncements, _appendOnRestart, false);
+        }
+        
+    /** Creates a log to a given filename; this file may or may not
+        be appended to on restart, depending on _appendOnRestart.  If
+        and only if the file is <i>not</i> appended to on restart, then
+        announcements are reposted on restart. The file can be compressed
+        with gzip, but you may not both gzip AND appendOnRestart.  If gzipped,
+        then .gz is automagically appended to the file name.*/
+    
+    public Log(File _filename,
+        boolean _postAnnouncements,
+        boolean _appendOnRestart,
+        boolean gzip) throws IOException
+        {
+        postAnnouncements = _postAnnouncements;
+        repostAnnouncementsOnRestart = !_appendOnRestart;
+        appendOnRestart = _appendOnRestart;
+        isLoggingToSystemOut = false;
+                    
+        if (gzip)
+            {
+            filename = new File(_filename.getAbsolutePath() + ".gz");
+            if (appendOnRestart) throw new IOException("Cannot gzip and appendOnRestart at the same time: new Log(File,int,boolean,boolean,boolean)");
+
+            writer = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(
+                        new BufferedOutputStream(
+                            new FileOutputStream(filename)))));
+            restarter = new LogRestarter()
+                {
+                public Log restart(Log l) throws IOException
+                    {
+                    return reopen(l);
+                    }
+                public Log reopen(Log l) throws IOException
+                    {
+                    if (l.writer!=null && !l.isLoggingToSystemOut) l.writer.close();
+                    l.writer = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(
+                                new BufferedOutputStream(new FileOutputStream(l.filename)))));
+                    return l;
+                    }
+                };
+            }
+                            
+        else 
+            {
+            filename = _filename;
+            writer = new PrintWriter(new BufferedWriter(new FileWriter(filename)));
+            restarter = new LogRestarter()
+                {
+                public Log restart(Log l) throws IOException
+                    {
+                    l.writer = new PrintWriter(new BufferedWriter(new FileWriter(l.filename.getPath(),l.appendOnRestart)));
+                    return l;
+                    }
+                public Log reopen(Log l) throws IOException
+                    {
+                    if (l.writer!=null && !isLoggingToSystemOut) l.writer.close();
+                    l.writer = new PrintWriter(new BufferedWriter(new FileWriter(l.filename)));
+                    return l;
+                    }
+                };
+            }
+        }
+
+    /** Creates a log on stdout (descriptor == Log.D_STDOUT) 
+        or stderr (descriptor == Log.D_STDERR). */
+
+    public Log(int descriptor,
+        boolean _postAnnouncements)
+        {
+        filename = null;
+        postAnnouncements = _postAnnouncements;
+        repostAnnouncementsOnRestart = true;
+        appendOnRestart = true;  // doesn't matter
+        isLoggingToSystemOut = true;
+        if (descriptor == D_STDOUT)
+            {
+            writer = new PrintWriter(System.out);
+            restarter = new LogRestarter()
+                {
+                public Log restart(Log l) throws IOException
+                    {
+                    l.writer = new PrintWriter(System.out);
+                    return l;
+                    }
+                public Log reopen(Log l) throws IOException
+                    {
+                    return l;  // makes no sense
+                    }
+                };
+            }
+        else  // D_STDERR
+            {
+            writer = new PrintWriter(System.err);
+            restarter = new LogRestarter()
+                {
+                public Log restart(Log l) throws IOException
+                    {
+                    l.writer = new PrintWriter(System.err);
+                    return l;
+                    }
+                public Log reopen(Log l) throws IOException
+                    {
+                    return l;  // makes no sense
+                    }
+                };
+            }
+        }
+
+
+    /** Creates a log on a given Writer and custom LogRestarter.  In general,
+        You should not use this to write to a file.  Use Log(_filename...
+        instead. */
+
+    public Log(Writer _writer,
+        LogRestarter _restarter,
+        boolean _postAnnouncements,
+        boolean _repostAnnouncementsOnRestart)
+        {
+        filename = null;
+        postAnnouncements = _postAnnouncements;
+        repostAnnouncementsOnRestart = _repostAnnouncementsOnRestart;
+        appendOnRestart = true;  // doesn't matter
+        /*
+         * Unfortunately, we can't know if the specified Writer wraps
+         * System.out.  Err on the side of caution and assume we're not.
+         */
+        isLoggingToSystemOut = false;
+        writer = new PrintWriter(new BufferedWriter(_writer));
+        restarter = _restarter;
+        }
+
+
+    /** Restarts a log after a system restart from checkpoint.  Returns
+        the restarted log -- note that it may not be the same log! */
+    
+    public Log restart() throws IOException
+        {
+        return restarter.restart(this);
+        }
+
+    /** Forces a file-based log to reopen, erasing its previous contents.
+        non-file logs ignore this. */
+
+    public Log reopen() throws IOException
+        {
+        return restarter.reopen(this);
+        }
+
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/LogRestarter.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/LogRestarter.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/LogRestarter.java	(revision 6152)
@@ -0,0 +1,39 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.io.IOException;
+import java.io.Serializable;
+
+/* 
+ * LogRestarter.java
+ * 
+ * Created: Wed Aug 11 14:55:03 1999
+ * By: Sean Luke
+ */
+
+/**
+ * A LogRestarter is an abstract superclass of objects which are
+ * capable of restarting logs after a computer failure.   
+ * LogRestarters subclasses are generally used
+ * internally in Logs only; you shouldn't need to deal with them.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public abstract class LogRestarter implements Serializable
+    {
+    /* recreate the writer for, and properly reopen a log
+       upon a system restart from a checkpoint */
+    public abstract Log restart(Log l) throws IOException;
+
+    /* close an existing log file and reopen it (non-appending),
+       if that' appropriate for this kind of log.  Otherwise,
+       don't do anything. */
+    public abstract Log reopen(Log l) throws IOException;
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/MersenneTwister.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/MersenneTwister.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/MersenneTwister.java	(revision 6152)
@@ -0,0 +1,729 @@
+package ec.util;
+
+import java.io.*;
+
+/** 
+ * <h3>MersenneTwister and MersenneTwisterFast</h3>
+ * <p><b>Version 16</b>, based on version MT199937(99/10/29)
+ * of the Mersenne Twister algorithm found at 
+ * <a href="http://www.math.keio.ac.jp/matumoto/emt.html">
+ * The Mersenne Twister Home Page</a>, with the initialization
+ * improved using the new 2002/1/26 initialization algorithm
+ * By Sean Luke, October 2004.
+ * 
+ * <p><b>MersenneTwister</b> is a drop-in subclass replacement
+ * for java.util.Random.  It is properly synchronized and
+ * can be used in a multithreaded environment.  On modern VMs such
+ * as HotSpot, it is approximately 1/3 slower than java.util.Random.
+ *
+ * <p><b>MersenneTwisterFast</b> is not a subclass of java.util.Random.  It has
+ * the same public methods as Random does, however, and it is
+ * algorithmically identical to MersenneTwister.  MersenneTwisterFast
+ * has hard-code inlined all of its methods directly, and made all of them
+ * final (well, the ones of consequence anyway).  Further, these
+ * methods are <i>not</i> synchronized, so the same MersenneTwisterFast
+ * instance cannot be shared by multiple threads.  But all this helps
+ * MersenneTwisterFast achieve well over twice the speed of MersenneTwister.
+ * java.util.Random is about 1/3 slower than MersenneTwisterFast.
+ *
+ * <h3>About the Mersenne Twister</h3>
+ * <p>This is a Java version of the C-program for MT19937: Integer version.
+ * The MT19937 algorithm was created by Makoto Matsumoto and Takuji Nishimura,
+ * who ask: "When you use this, send an email to: matumoto@math.keio.ac.jp
+ * with an appropriate reference to your work".  Indicate that this
+ * is a translation of their algorithm into Java.
+ *
+ * <p><b>Reference. </b>
+ * Makato Matsumoto and Takuji Nishimura,
+ * "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform
+ * Pseudo-Random Number Generator",
+ * <i>ACM Transactions on Modeling and Computer Simulation,</i>
+ * Vol. 8, No. 1, January 1998, pp 3--30.
+ *
+ * <h3>About this Version</h3>
+ *
+ * <p><b>Changes Since V15:</b> Added serialVersionUID to quiet compiler warnings
+ * from Sun's overly verbose compilers as of JDK 1.5.
+ *
+ * <p><b>Changes Since V14:</b> made strictfp, with StrictMath.log and StrictMath.sqrt
+ * in nextGaussian instead of Math.log and Math.sqrt.  This is largely just to be safe,
+ * as it presently makes no difference in the speed, correctness, or results of the
+ * algorithm.
+ *
+ * <p><b>Changes Since V13:</b> clone() method CloneNotSupportedException removed.  
+ *
+ * <p><b>Changes Since V12:</b> clone() method added.
+ *
+ * <p><b>Changes Since V11:</b> stateEquals(...) method added.  MersenneTwisterFast
+ * is equal to other MersenneTwisterFasts with identical state; likewise
+ * MersenneTwister is equal to other MersenneTwister with identical state.
+ * This isn't equals(...) because that requires a contract of immutability
+ * to compare by value.
+ *
+ * <p><b>Changes Since V10:</b> A documentation error suggested that
+ * setSeed(int[]) required an int[] array 624 long.  In fact, the array
+ * can be any non-zero length.  The new version also checks for this fact.
+ *
+ * <p><b>Changes Since V9:</b> readState(stream) and writeState(stream)
+ * provided.
+ *
+ * <p><b>Changes Since V8:</b> setSeed(int) was only using the first 28 bits
+ * of the seed; it should have been 32 bits.  For small-number seeds the
+ * behavior is identical.
+ *
+ * <p><b>Changes Since V7:</b> A documentation error in MersenneTwisterFast
+ * (but not MersenneTwister) stated that nextDouble selects uniformly from
+ * the full-open interval [0,1].  It does not.  nextDouble's contract is
+ * identical across MersenneTwisterFast, MersenneTwister, and java.util.Random,
+ * namely, selection in the half-open interval [0,1).  That is, 1.0 should
+ * not be returned.  A similar contract exists in nextFloat.
+ *
+ * <p><b>Changes Since V6:</b> License has changed from LGPL to BSD.
+ * New timing information to compare against
+ * java.util.Random.  Recent versions of HotSpot have helped Random increase
+ * in speed to the point where it is faster than MersenneTwister but slower
+ * than MersenneTwisterFast (which should be the case, as it's a less complex
+ * algorithm but is synchronized).
+ * 
+ * <p><b>Changes Since V5:</b> New empty constructor made to work the same
+ * as java.util.Random -- namely, it seeds based on the current time in
+ * milliseconds.
+ *
+ * <p><b>Changes Since V4:</b> New initialization algorithms.  See
+ * (see <a href="http://www.math.keio.ac.jp/matumoto/MT2002/emt19937ar.html"</a>
+ * http://www.math.keio.ac.jp/matumoto/MT2002/emt19937ar.html</a>)
+ *
+ * <p>The MersenneTwister code is based on standard MT19937 C/C++ 
+ * code by Takuji Nishimura,
+ * with suggestions from Topher Cooper and Marc Rieffel, July 1997.
+ * The code was originally translated into Java by Michael Lecuyer,
+ * January 1999, and the original code is Copyright (c) 1999 by Michael Lecuyer.
+ *
+ * <h3>Java notes</h3>
+ * 
+ * <p>This implementation implements the bug fixes made
+ * in Java 1.2's version of Random, which means it can be used with
+ * earlier versions of Java.  See 
+ * <a href="http://www.javasoft.com/products/jdk/1.2/docs/api/java/util/Random.html">
+ * the JDK 1.2 java.util.Random documentation</a> for further documentation
+ * on the random-number generation contracts made.  Additionally, there's
+ * an undocumented bug in the JDK java.util.Random.nextBytes() method,
+ * which this code fixes.
+ *
+ * <p> Just like java.util.Random, this
+ * generator accepts a long seed but doesn't use all of it.  java.util.Random
+ * uses 48 bits.  The Mersenne Twister instead uses 32 bits (int size).
+ * So it's best if your seed does not exceed the int range.
+ *
+ * <p>MersenneTwister can be used reliably 
+ * on JDK version 1.1.5 or above.  Earlier Java versions have serious bugs in
+ * java.util.Random; only MersenneTwisterFast (and not MersenneTwister nor
+ * java.util.Random) should be used with them.
+ *
+ * <h3>License</h3>
+ *
+ * Copyright (c) 2003 by Sean Luke. <br>
+ * Portions copyright (c) 1993 by Michael Lecuyer. <br>
+ * All rights reserved. <br>
+ *
+ * <p>Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * <ul>
+ * <li> Redistributions of source code must retain the above copyright notice, 
+ * this list of conditions and the following disclaimer.
+ * <li> Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution.
+ * <li> Neither the name of the copyright owners, their employers, nor the 
+ * names of its contributors may be used to endorse or promote products 
+ * derived from this software without specific prior written permission.
+ * </ul>
+ * <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ @version 16
+*/
+
+public strictfp class MersenneTwister extends java.util.Random implements Serializable, Cloneable
+    {
+    // Serialization
+    private static final long serialVersionUID = -4035832775130174188L;  // locked as of Version 15
+
+    // Period parameters
+    private static final int N = 624;
+    private static final int M = 397;
+    private static final int MATRIX_A = 0x9908b0df;   //    private static final * constant vector a
+    private static final int UPPER_MASK = 0x80000000; // most significant w-r bits
+    private static final int LOWER_MASK = 0x7fffffff; // least significant r bits
+
+    // Tempering parameters
+    private static final int TEMPERING_MASK_B = 0x9d2c5680;
+    private static final int TEMPERING_MASK_C = 0xefc60000;
+    
+    private int mt[]; // the array for the state vector
+    private int mti; // mti==N+1 means mt[N] is not initialized
+    private int mag01[];
+    
+    // a good initial seed (of int size, though stored in a long)
+    //private static final long GOOD_SEED = 4357;
+
+    /* implemented here because there's a bug in Random's implementation
+       of the Gaussian code (divide by zero, and log(0), ugh!), yet its
+       gaussian variables are private so we can't access them here.  :-( */
+
+    private double __nextNextGaussian;
+    private boolean __haveNextNextGaussian;
+
+    /* We're overriding all internal data, to my knowledge, so this should be okay */
+    public Object clone()
+        {
+        try
+            {
+            MersenneTwister f = (MersenneTwister)(super.clone());
+            f.mt = (int[])(mt.clone());
+            f.mag01 = (int[])(mag01.clone());
+            return f;
+            }
+        catch (CloneNotSupportedException e) { throw new InternalError(); } // should never happen
+        }
+
+    public boolean stateEquals(Object o)
+        {
+        if (o==this) return true;
+        if (o == null || !(o instanceof MersenneTwister))
+            return false;
+        MersenneTwister other = (MersenneTwister) o;
+        if (mti != other.mti) return false;
+        for(int x=0;x<mag01.length;x++)
+            if (mag01[x] != other.mag01[x]) return false;
+        for(int x=0;x<mt.length;x++)
+            if (mt[x] != other.mt[x]) return false;
+        return true;
+        }
+
+    /** Reads the entire state of the MersenneTwister RNG from the stream */
+    public void readState(DataInputStream stream) throws IOException
+        {
+        int len = mt.length;
+        for(int x=0;x<len;x++) mt[x] = stream.readInt();
+        
+        len = mag01.length;
+        for(int x=0;x<len;x++) mag01[x] = stream.readInt();
+        
+        mti = stream.readInt();
+        __nextNextGaussian = stream.readDouble();
+        __haveNextNextGaussian = stream.readBoolean();
+        }
+        
+    /** Writes the entire state of the MersenneTwister RNG to the stream */
+    public void writeState(DataOutputStream stream) throws IOException
+        {
+        int len = mt.length;
+        for(int x=0;x<len;x++) stream.writeInt(mt[x]);
+        
+        len = mag01.length;
+        for(int x=0;x<len;x++) stream.writeInt(mag01[x]);
+        
+        stream.writeInt(mti);
+        stream.writeDouble(__nextNextGaussian);
+        stream.writeBoolean(__haveNextNextGaussian);
+        }
+
+
+    /**
+     * Constructor using the default seed.
+     */
+    public MersenneTwister()
+        {
+        this(System.currentTimeMillis());
+        }
+    
+    /**
+     * Constructor using a given seed.  Though you pass this seed in
+     * as a long, it's best to make sure it's actually an integer.
+     */
+    public MersenneTwister(final long seed)
+        {
+        super(seed);    /* just in case */
+        setSeed(seed);
+        }
+    
+    /**
+     * Constructor using an array of integers as seed.
+     * Your array must have a non-zero length.  Only the first 624 integers
+     * in the array are used; if the array is shorter than this then
+     * integers are repeatedly used in a wrap-around fashion.
+     */
+    public MersenneTwister(final int[] array)
+        {
+        super(System.currentTimeMillis());    /* pick something at random just in case */
+        setSeed(array);
+        }
+
+    /**
+     * Initalize the pseudo random number generator.  Don't
+     * pass in a long that's bigger than an int (Mersenne Twister
+     * only uses the first 32 bits for its seed).   
+     */
+
+    synchronized public void setSeed(final long seed)
+        {
+        // it's always good style to call super
+        super.setSeed(seed);
+
+        // Due to a bug in java.util.Random clear up to 1.2, we're
+        // doing our own Gaussian variable.
+        __haveNextNextGaussian = false;
+
+        mt = new int[N];
+        
+        mag01 = new int[2];
+        mag01[0] = 0x0;
+        mag01[1] = MATRIX_A;
+
+        mt[0]= (int)(seed & 0xffffffff);
+        for (mti=1; mti<N; mti++) 
+            {
+            mt[mti] = 
+                (1812433253 * (mt[mti-1] ^ (mt[mti-1] >>> 30)) + mti); 
+            /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+            /* In the previous versions, MSBs of the seed affect   */
+            /* only MSBs of the array mt[].                        */
+            /* 2002/01/09 modified by Makoto Matsumoto             */
+            mt[mti] &= 0xffffffff;
+            /* for >32 bit machines */
+            }
+        }
+
+
+    /**
+     * Sets the seed of the MersenneTwister using an array of integers.
+     * Your array must have a non-zero length.  Only the first 624 integers
+     * in the array are used; if the array is shorter than this then
+     * integers are repeatedly used in a wrap-around fashion.
+     */
+
+    synchronized public void setSeed(final int[] array)
+        {
+        if (array.length == 0)
+            throw new IllegalArgumentException("Array length must be greater than zero");
+        int i, j, k;
+        setSeed(19650218);
+        i=1; j=0;
+        k = (N>array.length ? N : array.length);
+        for (; k!=0; k--) 
+            {
+            mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * 1664525)) + array[j] + j; /* non linear */
+            mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
+            i++;
+            j++;
+            if (i>=N) { mt[0] = mt[N-1]; i=1; }
+            if (j>=array.length) j=0;
+            }
+        for (k=N-1; k!=0; k--) 
+            {
+            mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * 1566083941)) - i; /* non linear */
+            mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
+            i++;
+            if (i>=N) 
+                {
+                mt[0] = mt[N-1]; i=1; 
+                }
+            }
+        mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */ 
+        }
+
+
+
+    /**
+     * Returns an integer with <i>bits</i> bits filled with a random number.
+     */
+    synchronized protected int next(final int bits)
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return y >>> (32 - bits);    // hope that's right!
+        }
+    
+    /* If you've got a truly old version of Java, you can omit these
+       two next methods. */
+
+    private synchronized void writeObject(final ObjectOutputStream out)
+        throws IOException
+        {
+        // just so we're synchronized.
+        out.defaultWriteObject();
+        }
+
+    private synchronized void readObject (final ObjectInputStream in) 
+        throws IOException, ClassNotFoundException
+        {
+        // just so we're synchronized.
+        in.defaultReadObject();
+        }    
+
+    /** This method is missing from jdk 1.0.x and below.  JDK 1.1
+        includes this for us, but what the heck.*/
+    public boolean nextBoolean() {return next(1) != 0;}
+
+    /** This generates a coin flip with a probability <tt>probability</tt>
+        of returning true, else returning false. <tt>probability</tt> must
+        be between 0.0 and 1.0, inclusive.  Not as precise a random real
+        event as nextBoolean(double), but twice as fast. To explicitly
+        use this, remember you may need to cast to float first. */
+
+    public boolean nextBoolean (final float probability)
+        {
+        if (probability < 0.0f || probability > 1.0f)
+            throw new IllegalArgumentException ("probability must be between 0.0 and 1.0 inclusive.");
+        if (probability==0.0f) return false;            // fix half-open issues
+        else if (probability==1.0f) return true;        // fix half-open issues
+        return nextFloat() < probability; 
+        }
+
+    /** This generates a coin flip with a probability <tt>probability</tt>
+        of returning true, else returning false. <tt>probability</tt> must
+        be between 0.0 and 1.0, inclusive. */
+
+    public boolean nextBoolean (final double probability)
+        {
+        if (probability < 0.0 || probability > 1.0)
+            throw new IllegalArgumentException ("probability must be between 0.0 and 1.0 inclusive.");
+        if (probability==0.0) return false;             // fix half-open issues
+        else if (probability==1.0) return true; // fix half-open issues
+        return nextDouble() < probability; 
+        }
+        
+    /** This method is missing from JDK 1.1 and below.  JDK 1.2
+        includes this for us, but what the heck. */
+
+    public int nextInt(final int n) 
+        {
+        if (n<=0)
+            throw new IllegalArgumentException("n must be positive, got: " + n);
+        
+        if ((n & -n) == n)
+            return (int)((n * (long)next(31)) >> 31);
+        
+        int bits, val;
+        do 
+            {
+            bits = next(31);
+            val = bits % n;
+            } 
+        while(bits - val + (n-1) < 0);
+        return val;
+        }
+
+    /** This method is for completness' sake. 
+        Returns a long drawn uniformly from 0 to n-1.  Suffice it to say,
+        n must be > 0, or an IllegalArgumentException is raised. */
+    
+    public long nextLong(final long n) 
+        {
+        if (n<=0)
+            throw new IllegalArgumentException("n must be positive, got: " + n);
+        
+        long bits, val;
+        do 
+            {
+            bits = (nextLong() >>> 1);
+            val = bits % n;
+            } 
+        while(bits - val + (n-1) < 0);
+        return val;
+        }
+
+
+    /** A bug fix for versions of JDK 1.1 and below.  JDK 1.2 fixes
+        this for us, but what the heck. */
+    public double nextDouble()
+        {
+        return (((long)next(26) << 27) + next(27))
+            / (double)(1L << 53);
+        }
+
+    /** A bug fix for versions of JDK 1.1 and below.  JDK 1.2 fixes
+        this for us, but what the heck. */
+
+    public float nextFloat()
+        {
+        return next(24) / ((float)(1 << 24));
+        }
+
+    /** A bug fix for all versions of the JDK.  The JDK appears to
+        use all four bytes in an integer as independent byte values!
+        Totally wrong. I've submitted a bug report. */
+
+    public void nextBytes(final byte[] bytes)    
+        {
+        for (int x=0;x<bytes.length;x++) bytes[x] = (byte)next(8);
+        }
+
+    /** For completeness' sake, though it's not in java.util.Random.  */
+    
+    public char nextChar()
+        {
+        // chars are 16-bit UniCode values
+        return (char)(next(16));
+        }
+
+    /** For completeness' sake, though it's not in java.util.Random. */
+    
+    public short nextShort()
+        {
+        return (short)(next(16));
+        }
+
+    /** For completeness' sake, though it's not in java.util.Random.  */
+
+    public byte nextByte()
+        {
+        return (byte)(next(8));
+        }
+
+
+    /** A bug fix for all JDK code including 1.2.  nextGaussian can theoretically
+        ask for the log of 0 and divide it by 0! See Java bug 
+        <a href="http://developer.java.sun.com/developer/bugParade/bugs/4254501.html">
+        http://developer.java.sun.com/developer/bugParade/bugs/4254501.html</a>
+    */
+
+    synchronized public double nextGaussian() 
+        {
+        if (__haveNextNextGaussian) 
+            {
+            __haveNextNextGaussian = false;
+            return __nextNextGaussian;
+            }
+        else 
+            {
+            double v1, v2, s;
+            do 
+                { 
+                v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
+                v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
+                s = v1 * v1 + v2 * v2;
+                } while (s >= 1 || s==0 );
+            double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+            __nextNextGaussian = v2 * multiplier;
+            __haveNextNextGaussian = true;
+            return v1 * multiplier;
+            }
+        }
+    
+    /**
+     * Tests the code.
+     */
+    public static void main(String args[])
+        { 
+        int j;
+
+        MersenneTwister r;
+
+        // CORRECTNESS TEST
+        // COMPARE WITH http://www.math.keio.ac.jp/matumoto/CODES/MT2002/mt19937ar.out
+        
+        r = new MersenneTwister(new int[]{0x123, 0x234, 0x345, 0x456});
+        System.out.println("Output of MersenneTwister with new (2002/1/26) seeding mechanism");
+        for (j=0;j<1000;j++)
+            {
+            // first, convert the int from signed to "unsigned"
+            long l = (long)r.nextInt();
+            if (l < 0 ) l += 4294967296L;  // max int value
+            String s = String.valueOf(l);
+            while(s.length() < 10) s = " " + s;  // buffer
+            System.out.print(s + " ");
+            if (j%5==4) System.out.println();       
+            }
+
+        // SPEED TEST
+
+        final long SEED = 4357;
+
+        int xx; long ms;
+        System.out.println("\nTime to test grabbing 100000000 ints");
+          
+        r = new MersenneTwister(SEED);
+        ms = System.currentTimeMillis();
+        xx=0;
+        for (j = 0; j < 100000000; j++)
+            xx += r.nextInt();
+        System.out.println("Mersenne Twister: " + (System.currentTimeMillis()-ms) + "          Ignore this: " + xx);
+
+        System.out.println("To compare this with java.util.Random, run this same test on MersenneTwisterFast.");
+        System.out.println("The comparison with Random is removed from MersenneTwister because it is a proper");
+        System.out.println("subclass of Random and this unfairly makes some of Random's methods un-inlinable,");
+        System.out.println("so it would make Random look worse than it is.");
+
+        // TEST TO COMPARE TYPE CONVERSION BETWEEN
+        // MersenneTwisterFast.java AND MersenneTwister.java
+
+        
+        System.out.println("\nGrab the first 1000 booleans");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextBoolean() + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+          
+        System.out.println("\nGrab 1000 booleans of increasing probability using nextBoolean(double)");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextBoolean((double)(j/999.0)) + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+          
+        System.out.println("\nGrab 1000 booleans of increasing probability using nextBoolean(float)");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextBoolean((float)(j/999.0f)) + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+          
+        byte[] bytes = new byte[1000];
+        System.out.println("\nGrab the first 1000 bytes using nextBytes");
+        r = new MersenneTwister(SEED);
+        r.nextBytes(bytes);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(bytes[j] + " ");
+            if (j%16==15) System.out.println();
+            }
+        if (!(j%16==15)) System.out.println();
+        
+        byte b;
+        System.out.println("\nGrab the first 1000 bytes -- must be same as nextBytes");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print((b = r.nextByte()) + " ");
+            if (b!=bytes[j]) System.out.print("BAD ");
+            if (j%16==15) System.out.println();
+            }
+        if (!(j%16==15)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 shorts");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextShort() + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 ints");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextInt() + " ");
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 ints of different sizes");
+        r = new MersenneTwister(SEED);
+        int max = 1;
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextInt(max) + " ");
+            max *= 2;
+            if (max <= 0) max = 1;
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 longs");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextLong() + " ");
+            if (j%3==2) System.out.println();
+            }
+        if (!(j%3==2)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 longs of different sizes");
+        r = new MersenneTwister(SEED);
+        long max2 = 1;
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextLong(max2) + " ");
+            max2 *= 2;
+            if (max2 <= 0) max2 = 1;
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+          
+        System.out.println("\nGrab the first 1000 floats");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextFloat() + " ");
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 doubles");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextDouble() + " ");
+            if (j%3==2) System.out.println();
+            }
+        if (!(j%3==2)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 gaussian doubles");
+        r = new MersenneTwister(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextGaussian() + " ");
+            if (j%3==2) System.out.println();
+            }
+        if (!(j%3==2)) System.out.println();
+        
+        }
+    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/MersenneTwisterFast.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/MersenneTwisterFast.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/MersenneTwisterFast.java	(revision 6152)
@@ -0,0 +1,1346 @@
+package ec.util;
+import java.io.*;
+import java.util.*;
+
+/** 
+ * <h3>MersenneTwister and MersenneTwisterFast</h3>
+ * <p><b>Version 16</b>, based on version MT199937(99/10/29)
+ * of the Mersenne Twister algorithm found at 
+ * <a href="http://www.math.keio.ac.jp/matumoto/emt.html">
+ * The Mersenne Twister Home Page</a>, with the initialization
+ * improved using the new 2002/1/26 initialization algorithm
+ * By Sean Luke, October 2004.
+ * 
+ * <p><b>MersenneTwister</b> is a drop-in subclass replacement
+ * for java.util.Random.  It is properly synchronized and
+ * can be used in a multithreaded environment.  On modern VMs such
+ * as HotSpot, it is approximately 1/3 slower than java.util.Random.
+ *
+ * <p><b>MersenneTwisterFast</b> is not a subclass of java.util.Random.  It has
+ * the same public methods as Random does, however, and it is
+ * algorithmically identical to MersenneTwister.  MersenneTwisterFast
+ * has hard-code inlined all of its methods directly, and made all of them
+ * final (well, the ones of consequence anyway).  Further, these
+ * methods are <i>not</i> synchronized, so the same MersenneTwisterFast
+ * instance cannot be shared by multiple threads.  But all this helps
+ * MersenneTwisterFast achieve well over twice the speed of MersenneTwister.
+ * java.util.Random is about 1/3 slower than MersenneTwisterFast.
+ *
+ * <h3>About the Mersenne Twister</h3>
+ * <p>This is a Java version of the C-program for MT19937: Integer version.
+ * The MT19937 algorithm was created by Makoto Matsumoto and Takuji Nishimura,
+ * who ask: "When you use this, send an email to: matumoto@math.keio.ac.jp
+ * with an appropriate reference to your work".  Indicate that this
+ * is a translation of their algorithm into Java.
+ *
+ * <p><b>Reference. </b>
+ * Makato Matsumoto and Takuji Nishimura,
+ * "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform
+ * Pseudo-Random Number Generator",
+ * <i>ACM Transactions on Modeling and. Computer Simulation,</i>
+ * Vol. 8, No. 1, January 1998, pp 3--30.
+ *
+ * <h3>About this Version</h3>
+ *
+ * <p><b>Changes Since V15:</b> Added serialVersionUID to quiet compiler warnings
+ * from Sun's overly verbose compilers as of JDK 1.5.
+ *
+ * <p><b>Changes Since V14:</b> made strictfp, with StrictMath.log and StrictMath.sqrt
+ * in nextGaussian instead of Math.log and Math.sqrt.  This is largely just to be safe,
+ * as it presently makes no difference in the speed, correctness, or results of the
+ * algorithm.
+ *
+ * <p><b>Changes Since V13:</b> clone() method CloneNotSupportedException removed.  
+ *
+ * <p><b>Changes Since V12:</b> clone() method added.  
+ *
+ * <p><b>Changes Since V11:</b> stateEquals(...) method added.  MersenneTwisterFast
+ * is equal to other MersenneTwisterFasts with identical state; likewise
+ * MersenneTwister is equal to other MersenneTwister with identical state.
+ * This isn't equals(...) because that requires a contract of immutability
+ * to compare by value.
+ *
+ * <p><b>Changes Since V10:</b> A documentation error suggested that
+ * setSeed(int[]) required an int[] array 624 long.  In fact, the array
+ * can be any non-zero length.  The new version also checks for this fact.
+ *
+ * <p><b>Changes Since V9:</b> readState(stream) and writeState(stream)
+ * provided.
+ *
+ * <p><b>Changes Since V8:</b> setSeed(int) was only using the first 28 bits
+ * of the seed; it should have been 32 bits.  For small-number seeds the
+ * behavior is identical.
+ *
+ * <p><b>Changes Since V7:</b> A documentation error in MersenneTwisterFast
+ * (but not MersenneTwister) stated that nextDouble selects uniformly from
+ * the full-open interval [0,1].  It does not.  nextDouble's contract is
+ * identical across MersenneTwisterFast, MersenneTwister, and java.util.Random,
+ * namely, selection in the half-open interval [0,1).  That is, 1.0 should
+ * not be returned.  A similar contract exists in nextFloat.
+ *
+ * <p><b>Changes Since V6:</b> License has changed from LGPL to BSD.
+ * New timing information to compare against
+ * java.util.Random.  Recent versions of HotSpot have helped Random increase
+ * in speed to the point where it is faster than MersenneTwister but slower
+ * than MersenneTwisterFast (which should be the case, as it's a less complex
+ * algorithm but is synchronized).
+ * 
+ * <p><b>Changes Since V5:</b> New empty constructor made to work the same
+ * as java.util.Random -- namely, it seeds based on the current time in
+ * milliseconds.
+ *
+ * <p><b>Changes Since V4:</b> New initialization algorithms.  See
+ * (see <a href="http://www.math.keio.ac.jp/matumoto/MT2002/emt19937ar.html"</a>
+ * http://www.math.keio.ac.jp/matumoto/MT2002/emt19937ar.html</a>)
+ *
+ * <p>The MersenneTwister code is based on standard MT19937 C/C++ 
+ * code by Takuji Nishimura,
+ * with suggestions from Topher Cooper and Marc Rieffel, July 1997.
+ * The code was originally translated into Java by Michael Lecuyer,
+ * January 1999, and the original code is Copyright (c) 1999 by Michael Lecuyer.
+ *
+ * <h3>Java notes</h3>
+ * 
+ * <p>This implementation implements the bug fixes made
+ * in Java 1.2's version of Random, which means it can be used with
+ * earlier versions of Java.  See 
+ * <a href="http://www.javasoft.com/products/jdk/1.2/docs/api/java/util/Random.html">
+ * the JDK 1.2 java.util.Random documentation</a> for further documentation
+ * on the random-number generation contracts made.  Additionally, there's
+ * an undocumented bug in the JDK java.util.Random.nextBytes() method,
+ * which this code fixes.
+ *
+ * <p> Just like java.util.Random, this
+ * generator accepts a long seed but doesn't use all of it.  java.util.Random
+ * uses 48 bits.  The Mersenne Twister instead uses 32 bits (int size).
+ * So it's best if your seed does not exceed the int range.
+ *
+ * <p>MersenneTwister can be used reliably 
+ * on JDK version 1.1.5 or above.  Earlier Java versions have serious bugs in
+ * java.util.Random; only MersenneTwisterFast (and not MersenneTwister nor
+ * java.util.Random) should be used with them.
+ *
+ * <h3>License</h3>
+ *
+ * Copyright (c) 2003 by Sean Luke. <br>
+ * Portions copyright (c) 1993 by Michael Lecuyer. <br>
+ * All rights reserved. <br>
+ *
+ * <p>Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * <ul>
+ * <li> Redistributions of source code must retain the above copyright notice, 
+ * this list of conditions and the following disclaimer.
+ * <li> Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution.
+ * <li> Neither the name of the copyright owners, their employers, nor the 
+ * names of its contributors may be used to endorse or promote products 
+ * derived from this software without specific prior written permission.
+ * </ul>
+ * <p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ @version 16
+*/
+
+// Note: this class is hard-inlined in all of its methods.  This makes some of
+// the methods well-nigh unreadable in their complexity.  In fact, the Mersenne
+// Twister is fairly easy code to understand: if you're trying to get a handle
+// on the code, I strongly suggest looking at MersenneTwister.java first.
+// -- Sean
+
+public strictfp class MersenneTwisterFast implements Serializable, Cloneable
+    {
+    // Serialization
+    private static final long serialVersionUID = -8219700664442619525L;  // locked as of Version 15
+    
+    // Period parameters
+    private static final int N = 624;
+    private static final int M = 397;
+    private static final int MATRIX_A = 0x9908b0df;   //    private static final * constant vector a
+    private static final int UPPER_MASK = 0x80000000; // most significant w-r bits
+    private static final int LOWER_MASK = 0x7fffffff; // least significant r bits
+
+
+    // Tempering parameters
+    private static final int TEMPERING_MASK_B = 0x9d2c5680;
+    private static final int TEMPERING_MASK_C = 0xefc60000;
+    
+    private int mt[]; // the array for the state vector
+    private int mti; // mti==N+1 means mt[N] is not initialized
+    private int mag01[];
+    
+    // a good initial seed (of int size, though stored in a long)
+    //private static final long GOOD_SEED = 4357;
+
+    private double __nextNextGaussian;
+    private boolean __haveNextNextGaussian;
+    
+    /* We're overriding all internal data, to my knowledge, so this should be okay */
+    public Object clone()
+        {
+        try
+            {
+            MersenneTwisterFast f = (MersenneTwisterFast)(super.clone());
+            f.mt = (int[])(mt.clone());
+            f.mag01 = (int[])(mag01.clone());
+            return f;
+            }
+        catch (CloneNotSupportedException e) { throw new InternalError(); } // should never happen
+        }
+    
+    public boolean stateEquals(Object o)
+        {
+        if (o==this) return true;
+        if (o == null || !(o instanceof MersenneTwisterFast))
+            return false;
+        MersenneTwisterFast other = (MersenneTwisterFast) o;
+        if (mti != other.mti) return false;
+        for(int x=0;x<mag01.length;x++)
+            if (mag01[x] != other.mag01[x]) return false;
+        for(int x=0;x<mt.length;x++)
+            if (mt[x] != other.mt[x]) return false;
+        return true;
+        }
+
+    /** Reads the entire state of the MersenneTwister RNG from the stream */
+    public void readState(DataInputStream stream) throws IOException
+        {
+        int len = mt.length;
+        for(int x=0;x<len;x++) mt[x] = stream.readInt();
+        
+        len = mag01.length;
+        for(int x=0;x<len;x++) mag01[x] = stream.readInt();
+        
+        mti = stream.readInt();
+        __nextNextGaussian = stream.readDouble();
+        __haveNextNextGaussian = stream.readBoolean();
+        }
+        
+    /** Writes the entire state of the MersenneTwister RNG to the stream */
+    public void writeState(DataOutputStream stream) throws IOException
+        {
+        int len = mt.length;
+        for(int x=0;x<len;x++) stream.writeInt(mt[x]);
+        
+        len = mag01.length;
+        for(int x=0;x<len;x++) stream.writeInt(mag01[x]);
+        
+        stream.writeInt(mti);
+        stream.writeDouble(__nextNextGaussian);
+        stream.writeBoolean(__haveNextNextGaussian);
+        }
+
+    /**
+     * Constructor using the default seed.
+     */
+    public MersenneTwisterFast()
+        {
+        this(System.currentTimeMillis());
+        }
+    
+    /**
+     * Constructor using a given seed.  Though you pass this seed in
+     * as a long, it's best to make sure it's actually an integer.
+     *
+     */
+    public MersenneTwisterFast(final long seed)
+        {
+        setSeed(seed);
+        }
+    
+
+    /**
+     * Constructor using an array of integers as seed.
+     * Your array must have a non-zero length.  Only the first 624 integers
+     * in the array are used; if the array is shorter than this then
+     * integers are repeatedly used in a wrap-around fashion.
+     */
+    public MersenneTwisterFast(final int[] array)
+        {
+        setSeed(array);
+        }
+
+
+    /**
+     * Initalize the pseudo random number generator.  Don't
+     * pass in a long that's bigger than an int (Mersenne Twister
+     * only uses the first 32 bits for its seed).   
+     */
+
+    synchronized public void setSeed(final long seed)
+        {
+        // Due to a bug in java.util.Random clear up to 1.2, we're
+        // doing our own Gaussian variable.
+        __haveNextNextGaussian = false;
+
+        mt = new int[N];
+        
+        mag01 = new int[2];
+        mag01[0] = 0x0;
+        mag01[1] = MATRIX_A;
+
+        mt[0]= (int)(seed & 0xffffffff);
+        for (mti=1; mti<N; mti++) 
+            {
+            mt[mti] = 
+                (1812433253 * (mt[mti-1] ^ (mt[mti-1] >>> 30)) + mti); 
+            /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+            /* In the previous versions, MSBs of the seed affect   */
+            /* only MSBs of the array mt[].                        */
+            /* 2002/01/09 modified by Makoto Matsumoto             */
+            mt[mti] &= 0xffffffff;
+            /* for >32 bit machines */
+            }
+        }
+
+
+    /**
+     * Sets the seed of the MersenneTwister using an array of integers.
+     * Your array must have a non-zero length.  Only the first 624 integers
+     * in the array are used; if the array is shorter than this then
+     * integers are repeatedly used in a wrap-around fashion.
+     */
+
+    synchronized public void setSeed(final int[] array)
+        {
+        if (array.length == 0)
+            throw new IllegalArgumentException("Array length must be greater than zero");
+        int i, j, k;
+        setSeed(19650218);
+        i=1; j=0;
+        k = (N>array.length ? N : array.length);
+        for (; k!=0; k--) 
+            {
+            mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * 1664525)) + array[j] + j; /* non linear */
+            mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
+            i++;
+            j++;
+            if (i>=N) { mt[0] = mt[N-1]; i=1; }
+            if (j>=array.length) j=0;
+            }
+        for (k=N-1; k!=0; k--) 
+            {
+            mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * 1566083941)) - i; /* non linear */
+            mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */
+            i++;
+            if (i>=N) 
+                {
+                mt[0] = mt[N-1]; i=1; 
+                }
+            }
+        mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */ 
+        }
+
+
+    public final int nextInt()
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return y;
+        }
+
+
+
+    public final short nextShort()
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return (short)(y >>> 16);
+        }
+
+
+
+    public final char nextChar()
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return (char)(y >>> 16);
+        }
+
+
+    public final boolean nextBoolean()
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return (boolean)((y >>> 31) != 0);
+        }
+
+
+
+    /** This generates a coin flip with a probability <tt>probability</tt>
+        of returning true, else returning false.  <tt>probability</tt> must
+        be between 0.0 and 1.0, inclusive.   Not as precise a random real
+        event as nextBoolean(double), but twice as fast. To explicitly
+        use this, remember you may need to cast to float first. */
+
+    public final boolean nextBoolean(final float probability)
+        {
+        int y;
+        
+        if (probability < 0.0f || probability > 1.0f)
+            throw new IllegalArgumentException ("probability must be between 0.0 and 1.0 inclusive.");
+        if (probability==0.0f) return false;            // fix half-open issues
+        else if (probability==1.0f) return true;        // fix half-open issues
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return (y >>> 8) / ((float)(1 << 24)) < probability;
+        }
+
+
+    /** This generates a coin flip with a probability <tt>probability</tt>
+        of returning true, else returning false.  <tt>probability</tt> must
+        be between 0.0 and 1.0, inclusive. */
+
+    public final boolean nextBoolean(final double probability)
+        {
+        int y;
+        int z;
+
+        if (probability < 0.0 || probability > 1.0)
+            throw new IllegalArgumentException ("probability must be between 0.0 and 1.0 inclusive.");
+        if (probability==0.0) return false;             // fix half-open issues
+        else if (probability==1.0) return true; // fix half-open issues
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (z >>> 1) ^ mag01[z & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (z >>> 1) ^ mag01[z & 0x1];
+                }
+            z = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (z >>> 1) ^ mag01[z & 0x1];
+            
+            mti = 0;
+            }
+        
+        z = mt[mti++];
+        z ^= z >>> 11;                          // TEMPERING_SHIFT_U(z)
+        z ^= (z << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(z)
+        z ^= (z << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(z)
+        z ^= (z >>> 18);                        // TEMPERING_SHIFT_L(z)
+        
+        /* derived from nextDouble documentation in jdk 1.2 docs, see top */
+        return ((((long)(y >>> 6)) << 27) + (z >>> 5)) / (double)(1L << 53) < probability;
+        }
+
+
+    public final byte nextByte()
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return (byte)(y >>> 24);
+        }
+
+
+    public final void nextBytes(byte[] bytes)
+        {
+        int y;
+        
+        for (int x=0;x<bytes.length;x++)
+            {
+            if (mti >= N)   // generate N words at one time
+                {
+                int kk;
+                final int[] mt = this.mt; // locals are slightly faster 
+                final int[] mag01 = this.mag01; // locals are slightly faster 
+                
+                for (kk = 0; kk < N - M; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                for (; kk < N-1; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+                
+                mti = 0;
+                }
+            
+            y = mt[mti++];
+            y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+            y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+            y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+            y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+            bytes[x] = (byte)(y >>> 24);
+            }
+        }
+
+
+    public final long nextLong()
+        {
+        int y;
+        int z;
+
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (z >>> 1) ^ mag01[z & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (z >>> 1) ^ mag01[z & 0x1];
+                }
+            z = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (z >>> 1) ^ mag01[z & 0x1];
+            
+            mti = 0;
+            }
+        
+        z = mt[mti++];
+        z ^= z >>> 11;                          // TEMPERING_SHIFT_U(z)
+        z ^= (z << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(z)
+        z ^= (z << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(z)
+        z ^= (z >>> 18);                        // TEMPERING_SHIFT_L(z)
+        
+        return (((long)y) << 32) + (long)z;
+        }
+
+
+
+    /** Returns a long drawn uniformly from 0 to n-1.  Suffice it to say,
+        n must be > 0, or an IllegalArgumentException is raised. */
+    public final long nextLong(final long n)
+        {
+        if (n<=0)
+            throw new IllegalArgumentException("n must be positive, got: " + n);
+        
+        long bits, val;
+        do 
+            {
+            int y;
+            int z;
+    
+            if (mti >= N)   // generate N words at one time
+                {
+                int kk;
+                final int[] mt = this.mt; // locals are slightly faster 
+                final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+                for (kk = 0; kk < N - M; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                for (; kk < N-1; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+    
+                mti = 0;
+                }
+    
+            y = mt[mti++];
+            y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+            y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+            y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+            y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+    
+            if (mti >= N)   // generate N words at one time
+                {
+                int kk;
+                final int[] mt = this.mt; // locals are slightly faster 
+                final int[] mag01 = this.mag01; // locals are slightly faster 
+                
+                for (kk = 0; kk < N - M; kk++)
+                    {
+                    z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+M] ^ (z >>> 1) ^ mag01[z & 0x1];
+                    }
+                for (; kk < N-1; kk++)
+                    {
+                    z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+(M-N)] ^ (z >>> 1) ^ mag01[z & 0x1];
+                    }
+                z = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                mt[N-1] = mt[M-1] ^ (z >>> 1) ^ mag01[z & 0x1];
+                
+                mti = 0;
+                }
+            
+            z = mt[mti++];
+            z ^= z >>> 11;                          // TEMPERING_SHIFT_U(z)
+            z ^= (z << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(z)
+            z ^= (z << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(z)
+            z ^= (z >>> 18);                        // TEMPERING_SHIFT_L(z)
+            
+            bits = (((((long)y) << 32) + (long)z) >>> 1);
+            val = bits % n;
+            } while (bits - val + (n-1) < 0);
+        return val;
+        }
+
+    /** Returns a random double in the half-open range from [0.0,1.0).  Thus 0.0 is a valid
+        result but 1.0 is not. */
+    public final double nextDouble()
+        {
+        int y;
+        int z;
+
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (z >>> 1) ^ mag01[z & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (z >>> 1) ^ mag01[z & 0x1];
+                }
+            z = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (z >>> 1) ^ mag01[z & 0x1];
+            
+            mti = 0;
+            }
+        
+        z = mt[mti++];
+        z ^= z >>> 11;                          // TEMPERING_SHIFT_U(z)
+        z ^= (z << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(z)
+        z ^= (z << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(z)
+        z ^= (z >>> 18);                        // TEMPERING_SHIFT_L(z)
+        
+        /* derived from nextDouble documentation in jdk 1.2 docs, see top */
+        return ((((long)(y >>> 6)) << 27) + (z >>> 5)) / (double)(1L << 53);
+        }
+
+
+
+
+
+    public final double nextGaussian()
+        {
+        if (__haveNextNextGaussian)
+            {
+            __haveNextNextGaussian = false;
+            return __nextNextGaussian;
+            } 
+        else 
+            {
+            double v1, v2, s;
+            do 
+                { 
+                int y;
+                int z;
+                int a;
+                int b;
+                    
+                if (mti >= N)   // generate N words at one time
+                    {
+                    int kk;
+                    final int[] mt = this.mt; // locals are slightly faster 
+                    final int[] mag01 = this.mag01; // locals are slightly faster 
+                    
+                    for (kk = 0; kk < N - M; kk++)
+                        {
+                        y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                        }
+                    for (; kk < N-1; kk++)
+                        {
+                        y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                        }
+                    y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                    mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    
+                    mti = 0;
+                    }
+                
+                y = mt[mti++];
+                y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+                y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+                y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+                y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+                
+                if (mti >= N)   // generate N words at one time
+                    {
+                    int kk;
+                    final int[] mt = this.mt; // locals are slightly faster 
+                    final int[] mag01 = this.mag01; // locals are slightly faster 
+                    
+                    for (kk = 0; kk < N - M; kk++)
+                        {
+                        z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+M] ^ (z >>> 1) ^ mag01[z & 0x1];
+                        }
+                    for (; kk < N-1; kk++)
+                        {
+                        z = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+(M-N)] ^ (z >>> 1) ^ mag01[z & 0x1];
+                        }
+                    z = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                    mt[N-1] = mt[M-1] ^ (z >>> 1) ^ mag01[z & 0x1];
+                    
+                    mti = 0;
+                    }
+                
+                z = mt[mti++];
+                z ^= z >>> 11;                          // TEMPERING_SHIFT_U(z)
+                z ^= (z << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(z)
+                z ^= (z << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(z)
+                z ^= (z >>> 18);                        // TEMPERING_SHIFT_L(z)
+                
+                if (mti >= N)   // generate N words at one time
+                    {
+                    int kk;
+                    final int[] mt = this.mt; // locals are slightly faster 
+                    final int[] mag01 = this.mag01; // locals are slightly faster 
+                    
+                    for (kk = 0; kk < N - M; kk++)
+                        {
+                        a = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+M] ^ (a >>> 1) ^ mag01[a & 0x1];
+                        }
+                    for (; kk < N-1; kk++)
+                        {
+                        a = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+(M-N)] ^ (a >>> 1) ^ mag01[a & 0x1];
+                        }
+                    a = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                    mt[N-1] = mt[M-1] ^ (a >>> 1) ^ mag01[a & 0x1];
+                    
+                    mti = 0;
+                    }
+                
+                a = mt[mti++];
+                a ^= a >>> 11;                          // TEMPERING_SHIFT_U(a)
+                a ^= (a << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(a)
+                a ^= (a << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(a)
+                a ^= (a >>> 18);                        // TEMPERING_SHIFT_L(a)
+                
+                if (mti >= N)   // generate N words at one time
+                    {
+                    int kk;
+                    final int[] mt = this.mt; // locals are slightly faster 
+                    final int[] mag01 = this.mag01; // locals are slightly faster 
+                    
+                    for (kk = 0; kk < N - M; kk++)
+                        {
+                        b = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+M] ^ (b >>> 1) ^ mag01[b & 0x1];
+                        }
+                    for (; kk < N-1; kk++)
+                        {
+                        b = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                        mt[kk] = mt[kk+(M-N)] ^ (b >>> 1) ^ mag01[b & 0x1];
+                        }
+                    b = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                    mt[N-1] = mt[M-1] ^ (b >>> 1) ^ mag01[b & 0x1];
+                    
+                    mti = 0;
+                    }
+                
+                b = mt[mti++];
+                b ^= b >>> 11;                          // TEMPERING_SHIFT_U(b)
+                b ^= (b << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(b)
+                b ^= (b << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(b)
+                b ^= (b >>> 18);                        // TEMPERING_SHIFT_L(b)
+                
+                /* derived from nextDouble documentation in jdk 1.2 docs, see top */
+                v1 = 2 *
+                    (((((long)(y >>> 6)) << 27) + (z >>> 5)) / (double)(1L << 53))
+                    - 1;
+                v2 = 2 * (((((long)(a >>> 6)) << 27) + (b >>> 5)) / (double)(1L << 53))
+                    - 1;
+                s = v1 * v1 + v2 * v2;
+                } while (s >= 1 || s==0);
+            double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+            __nextNextGaussian = v2 * multiplier;
+            __haveNextNextGaussian = true;
+            return v1 * multiplier;
+            }
+        }
+    
+    
+    
+    
+
+    /** Returns a random float in the half-open range from [0.0f,1.0f).  Thus 0.0f is a valid
+        result but 1.0f is not. */
+    public final float nextFloat()
+        {
+        int y;
+        
+        if (mti >= N)   // generate N words at one time
+            {
+            int kk;
+            final int[] mt = this.mt; // locals are slightly faster 
+            final int[] mag01 = this.mag01; // locals are slightly faster 
+            
+            for (kk = 0; kk < N - M; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            for (; kk < N-1; kk++)
+                {
+                y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                }
+            y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+            mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+
+            mti = 0;
+            }
+  
+        y = mt[mti++];
+        y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+        y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+        y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+        y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+
+        return (y >>> 8) / ((float)(1 << 24));
+        }
+
+
+
+    /** Returns an integer drawn uniformly from 0 to n-1.  Suffice it to say,
+        n must be > 0, or an IllegalArgumentException is raised. */
+    public final int nextInt(final int n)
+        {
+        if (n<=0)
+            throw new IllegalArgumentException("n must be positive, got: " + n);
+        
+        if ((n & -n) == n)  // i.e., n is a power of 2
+            {
+            int y;
+        
+            if (mti >= N)   // generate N words at one time
+                {
+                int kk;
+                final int[] mt = this.mt; // locals are slightly faster 
+                final int[] mag01 = this.mag01; // locals are slightly faster 
+                
+                for (kk = 0; kk < N - M; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                for (; kk < N-1; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+                
+                mti = 0;
+                }
+            
+            y = mt[mti++];
+            y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+            y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+            y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+            y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+            
+            return (int)((n * (long) (y >>> 1) ) >> 31);
+            }
+        
+        int bits, val;
+        do 
+            {
+            int y;
+            
+            if (mti >= N)   // generate N words at one time
+                {
+                int kk;
+                final int[] mt = this.mt; // locals are slightly faster 
+                final int[] mag01 = this.mag01; // locals are slightly faster 
+                
+                for (kk = 0; kk < N - M; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+M] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                for (; kk < N-1; kk++)
+                    {
+                    y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
+                    mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y & 0x1];
+                    }
+                y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+                mt[N-1] = mt[M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
+                
+                mti = 0;
+                }
+            
+            y = mt[mti++];
+            y ^= y >>> 11;                          // TEMPERING_SHIFT_U(y)
+            y ^= (y << 7) & TEMPERING_MASK_B;       // TEMPERING_SHIFT_S(y)
+            y ^= (y << 15) & TEMPERING_MASK_C;      // TEMPERING_SHIFT_T(y)
+            y ^= (y >>> 18);                        // TEMPERING_SHIFT_L(y)
+        
+            bits = (y >>> 1);
+            val = bits % n;
+            } while(bits - val + (n-1) < 0);
+        return val;
+        }
+    
+
+    /**
+     * Tests the code.
+     */
+    public static void main(String args[])
+        { 
+        int j;
+
+        MersenneTwisterFast r;
+
+        // CORRECTNESS TEST
+        // COMPARE WITH http://www.math.keio.ac.jp/matumoto/CODES/MT2002/mt19937ar.out
+        
+        r = new MersenneTwisterFast(new int[]{0x123, 0x234, 0x345, 0x456});
+        System.out.println("Output of MersenneTwisterFast with new (2002/1/26) seeding mechanism");
+        for (j=0;j<1000;j++)
+            {
+            // first, convert the int from signed to "unsigned"
+            long l = (long)r.nextInt();
+            if (l < 0 ) l += 4294967296L;  // max int value
+            String s = String.valueOf(l);
+            while(s.length() < 10) s = " " + s;  // buffer
+            System.out.print(s + " ");
+            if (j%5==4) System.out.println();       
+            }
+
+        // SPEED TEST
+
+        final long SEED = 4357;
+
+        int xx; long ms;
+        System.out.println("\nTime to test grabbing 100000000 ints");
+          
+        Random rr = new Random(SEED);
+        xx = 0;
+        ms = System.currentTimeMillis();
+        for (j = 0; j < 100000000; j++)
+            xx += rr.nextInt();
+        System.out.println("java.util.Random: " + (System.currentTimeMillis()-ms) + "          Ignore this: " + xx);
+        
+        r = new MersenneTwisterFast(SEED);
+        ms = System.currentTimeMillis();
+        xx=0;
+        for (j = 0; j < 100000000; j++)
+            xx += r.nextInt();
+        System.out.println("Mersenne Twister Fast: " + (System.currentTimeMillis()-ms) + "          Ignore this: " + xx);
+        
+        // TEST TO COMPARE TYPE CONVERSION BETWEEN
+        // MersenneTwisterFast.java AND MersenneTwister.java
+          
+        System.out.println("\nGrab the first 1000 booleans");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextBoolean() + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+          
+        System.out.println("\nGrab 1000 booleans of increasing probability using nextBoolean(double)");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextBoolean((double)(j/999.0)) + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+          
+        System.out.println("\nGrab 1000 booleans of increasing probability using nextBoolean(float)");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextBoolean((float)(j/999.0f)) + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+          
+        byte[] bytes = new byte[1000];
+        System.out.println("\nGrab the first 1000 bytes using nextBytes");
+        r = new MersenneTwisterFast(SEED);
+        r.nextBytes(bytes);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(bytes[j] + " ");
+            if (j%16==15) System.out.println();
+            }
+        if (!(j%16==15)) System.out.println();
+        
+        byte b;
+        System.out.println("\nGrab the first 1000 bytes -- must be same as nextBytes");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print((b = r.nextByte()) + " ");
+            if (b!=bytes[j]) System.out.print("BAD ");
+            if (j%16==15) System.out.println();
+            }
+        if (!(j%16==15)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 shorts");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextShort() + " ");
+            if (j%8==7) System.out.println();
+            }
+        if (!(j%8==7)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 ints");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextInt() + " ");
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 ints of different sizes");
+        r = new MersenneTwisterFast(SEED);
+        int max = 1;
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextInt(max) + " ");
+            max *= 2;
+            if (max <= 0) max = 1;
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 longs");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextLong() + " ");
+            if (j%3==2) System.out.println();
+            }
+        if (!(j%3==2)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 longs of different sizes");
+        r = new MersenneTwisterFast(SEED);
+        long max2 = 1;
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextLong(max2) + " ");
+            max2 *= 2;
+            if (max2 <= 0) max2 = 1;
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+          
+        System.out.println("\nGrab the first 1000 floats");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextFloat() + " ");
+            if (j%4==3) System.out.println();
+            }
+        if (!(j%4==3)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 doubles");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextDouble() + " ");
+            if (j%3==2) System.out.println();
+            }
+        if (!(j%3==2)) System.out.println();
+
+        System.out.println("\nGrab the first 1000 gaussian doubles");
+        r = new MersenneTwisterFast(SEED);
+        for (j = 0; j < 1000; j++)
+            {
+            System.out.print(r.nextGaussian() + " ");
+            if (j%3==2) System.out.println();
+            }
+        if (!(j%3==2)) System.out.println();
+        
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Output.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Output.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Output.java	(revision 6152)
@@ -0,0 +1,869 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+/*
+ * Output.java
+ * Created: Sat Aug  7 15:30:54 1999
+ *
+ */
+
+/**
+ * <p>Outputs and logs system messages, errors, and other various
+ * items printed as a result of a run.
+ *
+ * <p> Output maintains zero or more logs, which contain Writers which
+ * write out stuff.  Each log has an associated verbosity; if request
+ * is made to write text to a log, and the text's maximal verbosity
+ * is lower than the verbosity of the log, the log will not write it.
+ * Each Output instance also has an instance-level global verbosity;
+ * incoming requests to write text are additionally subject to this
+ * verbosity test.  Lastly, the Output class itself has a global
+ * verbosity as well.  This last verbosity is useful for shutting
+ * down writing to all logs in the entire system in a simple way.
+ *
+ * <p>When the system fails for some reason and must be started back
+ * up from a checkpoint, Output's log files may be overwritten.  Output
+ * offers three approaches here.  First, Output can clear the log file
+ * and overwrite it.  Second, Output can append to the existing log file;
+ * because checkpoints are only done occasionally, this may result in
+ * duplicate outputs to a file, so keep this in mind.  Third, Output can
+ * keep certain written text, typically <i>announcements</i>, in memory;
+ * this text gets written out into the checkpoint file, and so it is sound.
+ *
+ * <p>There are several kinds of announcements, in different levels
+ * of importance.
+ *
+ * <ol>
+ * <li> FATAL ERRORs.  These errors cause the system to exit(1) immediately.
+ * <li> Simple ERRORs.  These errors set the "errors" flag to true; at 
+ * the end of a stream of simple errors, the system in general is expected
+ * to exit with a fatal error due to the flag being set.  That's the
+ * protocol anyway.  On restart from a checkpoint, if there were any
+ * simple errors, the system ends with a fatal error automatically.
+ * <li> WARNINGs.  These errors do not cause the system to exit under any
+ * circumstances.
+ * <li> MESSAGEs.  Useful facts printed out for the benefit of the user.
+ * <li> SYSTEM MESSAGEs.  Useful system-level facts printed out for the
+ * benefit of the user.
+ * </ol>
+ *
+ <!--
+ * <p>The default verbosity values for different kinds of announcements are
+ * given below:
+ *
+ <table><tr><td>0</td><td>V_VERBOSE</td><td>(totally verbose)</td>
+ </tr><tr><td>1000</td><td>V_NO_MESSAGES</td><td>(don't print messages or system messages)</td>
+ </tr><tr><td>2000</td><td>V_NO_WARNINGS</td><td>(don't print warnings, messages, or system messages)</td>
+ </tr><tr><td>3000</td><td>V_NO_GENERAL</td><td>(don't print warnings, messages, system messages, or other "general info" stuff that might come along (like statistics maybe))</td>
+ </tr><tr><td>4000</td><td>V_NO_ERRORS</td><td>(don't even print errors)</td>
+ </tr><tr><td>5000</td><td>V_TOTALLY_SILENT</td><td>(be totally silent)</td>
+ </tr></table>
+ *
+ -->
+ 
+ * <p>Output will also store all announcements in memory by default so as to reproduce
+ * them if it's restarted from a checkpoint.  You can change this behavior also by
+ *
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class Output implements Serializable
+    {
+    boolean errors;
+    Vector logs = new Vector();
+    Vector announcements = new Vector();
+    // boolean flush = true;
+    boolean store = true;
+    String filePrefix = "";
+
+    public static final int ALL_LOGS = -1;
+
+    /** Total verbosity */
+    public static final int V_VERBOSE = 0;
+    /** Don't print messages */
+    public static final int V_NO_MESSAGES = 1000;
+    /** Don't print warnings or messages */
+    public static final int V_NO_WARNINGS = 2000;
+    /** The standard verbosity to use if you don't want common reporting (like statistics) */
+    public static final int V_NO_GENERAL = 3000;
+    /** Don't print warnings, messages, or simple errors  */
+    public static final int V_NO_ERRORS = 4000;
+    /** No verbosity at all, not even system messages or fatal errors*/
+    public static final int V_TOTALLY_SILENT = 5000;
+    
+    public void setFilePrefix(String filePrefix) {
+        this.filePrefix = filePrefix;
+        }
+
+    protected void finalize() throws Throwable
+        {
+        // flush the logs
+        close();
+
+        // do super.finalize, just for good style
+        super.finalize();
+        }
+
+    private void exitWithError()
+        {
+        // flush logs first
+        close();
+
+        // exit
+        System.exit(1);
+        }
+
+    /** Closes the logs -- ONLY call this if you are preparing to quit */
+    public synchronized void close()
+        {
+        // just in case
+        flush();
+        
+        Enumeration e = logs.elements();
+        while(e.hasMoreElements())
+            {
+            Log log = (Log)e.nextElement();
+            if (!log.isLoggingToSystemOut)
+                log.writer.close();
+            }
+        }
+
+    /** Flushes the logs */
+    public synchronized void flush()
+        {
+        Enumeration e = logs.elements();
+        while(e.hasMoreElements())
+            {
+            Log log = (Log)e.nextElement();
+            log.writer.flush();
+            }
+        // just in case...
+        System.out.flush();
+        System.err.flush();
+        }
+
+    /** Creates a new, verbose, empty Output object. 
+        @deprecated Verbosity no longer has an effect.
+    */
+    public Output(boolean storeAnnouncementsInMemory, int _verbosity)
+        {
+        this(storeAnnouncementsInMemory);
+        }
+
+    /** Creates a new, verbose, empty Output object. */
+    public Output(boolean storeAnnouncementsInMemory)
+        {
+        errors = false;
+        store = storeAnnouncementsInMemory;
+        }
+
+    /** Sets whether the Output flushes its announcements.
+        @deprecated We now always flush 
+    */
+    public synchronized void setFlush(boolean v)
+        {
+        // flush = v;
+        }
+    
+    /* Returns the Output's flushing behavior. 
+       @deprecated We now always flush 
+    */
+    public synchronized boolean getFlush()
+        {
+        // return flush;
+        return true;
+        }
+    
+    /** Sets whether the Output stores its announcements.*/
+    public synchronized void setStore(boolean v)
+        {
+        store = v;
+        }
+
+    /* Returns the Output's storing behavior. */
+    public synchronized boolean getStore()
+        {
+        return store;
+        }
+    
+    /** Sets the Output object's general verbosity to <i>v</i>. 
+        @deprecated Verbosity no longer has an effect.
+    */
+    public synchronized void setVerbosity(int v)
+        {
+//        verbosity = v;
+        }
+    
+    /** Returns the Output object's general verbosity
+        @deprecated Verbosity no longer has an effect.
+    */
+    public synchronized int getVerbosity()
+        {
+        return V_VERBOSE;
+        }
+
+    /** Creates a new log of minimal verbosity <i>verbosity</i> and adds it 
+        to Output.  This log will write to the file <i>file</i>, and may
+        or may not <i>post announcements</i> to the log. If the log must be
+        reset upon restarting from a checkpoint, it will append to the file
+        or erase the file and start over depending on <i>appendOnRestart</i>.
+        If <i>appendOnRestart</i> is false and <i>postAnnouncements</i> is
+        true, then this log will repost all the announcements on restarting
+        from a checkpoint. Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart.
+        The log can be compressed with gzip, but you cannot appendOnRestart
+        and compress at the same time.
+        @deprecated Verbosity no longer has an effect.
+    */
+
+    public synchronized int addLog(File file,
+        int _verbosity,
+        boolean postAnnouncements,
+        boolean appendOnRestart,
+        boolean gzip) throws IOException
+        {
+        if (filePrefix != null && filePrefix.length()>0)
+            file = new File(file.getParent(),filePrefix+file.getName());
+        logs.addElement(new Log(file,postAnnouncements,appendOnRestart,gzip));
+        return logs.size()-1;
+        }
+        
+    /** Creates a new log of minimal verbosity <i>verbosity</i> and adds it 
+        to Output.  This log will write to the file <i>file</i>, and may
+        or may not <i>post announcements</i> to the log. If the log must be
+        reset upon restarting from a checkpoint, it will append to the file
+        or erase the file and start over depending on <i>appendOnRestart</i>.
+        If <i>appendOnRestart</i> is false and <i>postAnnouncements</i> is
+        true, then this log will repost all the announcements on restarting
+        from a checkpoint. Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. 
+        @deprecated Verbosity no longer has an effect
+    */
+
+    public synchronized int addLog(File file,
+        int _verbosity,
+        boolean postAnnouncements,
+        boolean appendOnRestart) throws IOException
+        {
+        return addLog(file, postAnnouncements, appendOnRestart, false);
+        }
+
+
+    /** Creates a new log <!-- of minimal verbosity V_NO_GENERAL-1 --> and adds it 
+        to Output.  This log will write to the file <i>file</i>, and may
+        or may not <i>post announcements</i> to the log. If the log must be
+        reset upon restarting from a checkpoint, it will append to the file
+        or erase the file and start over depending on <i>appendOnRestart</i>.
+        If <i>appendOnRestart</i> is false and <i>postAnnouncements</i> is
+        true, then this log will repost all the announcements on restarting
+        from a checkpoint. Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart.
+        The log can be compressed with gzip, but you cannot appendOnRestart
+        and compress at the same time.
+    */
+
+    public synchronized int addLog(File file,
+        boolean postAnnouncements,
+        boolean appendOnRestart,
+        boolean gzip) throws IOException
+        {
+        return addLog(file, V_VERBOSE, postAnnouncements, appendOnRestart, gzip);
+        }
+
+
+    /** Creates a new log <!-- of minimal verbosity V_NO_GENERAL-1 --> and adds it 
+        to Output.  This log will write to the file <i>file</i>, and you may
+        not post announcements to the log. If the log must be
+        reset upon restarting from a checkpoint, it will append to the file
+        or erase the file and start over depending on <i>appendOnRestart</i>.
+        Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart.
+        The log can be compressed with gzip, but you cannot appendOnRestart
+        and compress at the same time.*/
+
+    public synchronized int addLog(File file,
+        boolean appendOnRestart,
+        boolean gzip) throws IOException
+        {
+        return addLog(file, false, appendOnRestart, gzip);
+        }
+        
+    /** Creates a new log <!-- of minimal verbosity V_NO_GENERAL-1 --> and adds it 
+        to Output.  This log will write to the file <i>file</i>, and you may
+        not post announcements to the log. If the log must be
+        reset upon restarting from a checkpoint, it will append to the file
+        or erase the file and start over depending on <i>appendOnRestart</i>.
+        Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. */
+
+    public synchronized int addLog(File file,
+        boolean appendOnRestart) throws IOException
+        {
+        return addLog(file, false, appendOnRestart, false);
+        }
+
+
+    /** Creates a new log of minimal verbosity <i>verbosity</i> and adds it 
+        to Output.  This log will write to stdout (descriptor == Log.D_STDOUT) 
+        or stderr (descriptor == Log.D_STDERR), and may or may not
+        <i>post announcements</i> to the log. Returns the position of the 
+        log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. 
+        @deprecated Verbosity no longer has an effect
+    */
+    
+    public synchronized int addLog(int descriptor,
+        int _verbosity,
+        boolean postAnnouncements)
+        {
+        logs.addElement(new Log(descriptor,postAnnouncements));
+        return logs.size()-1;
+        }
+
+    /** Creates a new log and adds it 
+        to Output.  This log will write to stdout (descriptor == Log.D_STDOUT) 
+        or stderr (descriptor == Log.D_STDERR), and may or may not
+        <i>post announcements</i> to the log. Returns the position of the 
+        log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. 
+    */
+    
+    public synchronized int addLog(int descriptor,
+        boolean postAnnouncements)
+        {
+        return addLog(descriptor, V_VERBOSE, postAnnouncements);
+        }
+
+    /** Creates a new log of minimal verbosity <i>verbosity</i> and adds it 
+        to Output.  This log may or may not <i>post announcements</i> to
+        the log, and if it does, it additionally may or may not <i>repost</i>
+        all of its announcements to the log upon a restart.  The log
+        writes to <i>writer</i>, which is reset upon system restart by
+        <i>restarter</i>. Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. 
+        @deprecated Verbosity no longer has an effect
+    */
+
+    public synchronized int addLog(Writer writer,
+        LogRestarter restarter,
+        int _verbosity,
+        boolean postAnnouncements,
+        boolean repostAnnouncements)
+        {
+        logs.addElement(new Log(writer,restarter,postAnnouncements,repostAnnouncements));
+        return logs.size()-1;
+        }
+
+    /** Creates a new log <!-- of minimal verbosity V_NO_GENERAL-1 --> and adds it 
+        to Output.  This log may or may not <i>post announcements</i> to
+        the log, and if it does, it additionally may or may not <i>repost</i>
+        all of its announcements to the log upon a restart.  The log
+        writes to <i>writer</i>, which is reset upon system restart by
+        <i>restarter</i>. Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. 
+    */
+
+    public synchronized int addLog(Writer writer,
+        LogRestarter restarter,
+        boolean postAnnouncements,
+        boolean repostAnnouncements)
+        {
+        logs.addElement(new Log(writer,restarter,postAnnouncements,repostAnnouncements));
+        return logs.size()-1;
+        }
+
+
+    /** Adds the given log to Output.  In general you shouldn't use this
+        method unless you really <i>really</i> need something custom. 
+        Returns the position of the log in Output's 
+        collection of logs -- you should use this to access the log always;
+        never store the log itself, which may go away upon a system restart. */
+
+    public synchronized int addLog(Log l)
+        {
+        logs.addElement(l);
+        return logs.size()-1;
+        }
+
+    /** Returns the number of logs currently posted. */
+    public synchronized int numLogs()
+        {
+        return logs.size();
+        }
+
+    /** Returns the given log. */
+    public synchronized Log log(int x)
+        {
+        return (Log)logs.elementAt(x);
+        }
+
+    /** Removes the given log. */
+    public synchronized Log removeLog(int x)
+        {
+        Log l = log(x);
+        logs.removeElementAt(x);
+        return l;
+        }
+    
+    /** Prints an initial error to System.err.  This is only to
+        be used by ec.Evolve in starting up the system. */
+    public static void initialError(String s)
+        {
+        System.err.println("STARTUP ERROR:\n" + s);
+
+        // just in case...
+        System.out.flush();
+        System.err.flush();
+        System.exit(1);
+        }
+
+    /** Prints an initial error to System.err.  This is only to
+        be used by ec.Evolve in starting up the system. */
+    public static void initialError(String s, Parameter p1)
+        {
+        System.err.println("STARTUP ERROR:\n" + s);
+        if (p1!=null) System.err.println("PARAMETER: " + p1);
+
+        // just in case...
+        System.out.flush();
+        System.err.flush();
+        System.exit(1);
+        }
+
+    /** Prints an initial error to System.err.  This is only to
+        be used by ec.Evolve in starting up the system. */
+    public static void initialError(String s, Parameter p1, Parameter p2)
+        {
+        System.err.println("STARTUP ERROR:\n" + s);
+        if (p1!=null) System.err.println("PARAMETER: " + p1);
+        if (p2!=null && p1!=null) System.err.println("     ALSO: " + p2);
+
+        // just in case...
+        System.out.flush();
+        System.err.flush();
+        System.exit(1);
+        }
+
+    /** Prints an initial message to System.err.  This is only to
+        be used by ec.Evolve in starting up the system.  These messages are not logged. */
+    public static void initialMessage(String s)
+        {
+        System.err.println(s);
+        System.err.flush();
+        }
+
+    /** Posts a system message. */
+    public synchronized void systemMessage(String s)
+        {
+        println(s, V_NO_MESSAGES ,ALL_LOGS, true);
+        }
+
+    /** Posts a fatal error.  This causes the system to exit. */
+    public synchronized void fatal(String s)
+        {
+        println("FATAL ERROR:\n"+s, ALL_LOGS, true);
+        exitWithError();
+        }
+            
+    /** Posts a fatal error.  This causes the system to exit. */
+    public synchronized void fatal(String s, Parameter p1)
+        {
+        println("FATAL ERROR:\n"+s, ALL_LOGS, true);
+        if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+        exitWithError();
+        }
+
+    /** Posts a fatal error.  This causes the system to exit. */
+    public synchronized void fatal(String s, Parameter p1, Parameter p2)
+        {
+        println("FATAL ERROR:\n"+s, ALL_LOGS, true);
+        if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+        if (p2!=null && p1!=null) println("     ALSO: " + p2, ALL_LOGS, true);
+        else println("PARAMETER: " + p2, ALL_LOGS, true);
+        exitWithError();
+        }
+
+    /** Posts a simple error. This causes the error flag to be raised as well. */
+    public synchronized void error(String s)
+        {
+        println("ERROR:\n"+s, ALL_LOGS, true);
+        errors = true;
+        }
+            
+    /** Posts a simple error. This causes the error flag to be raised as well. */
+    public synchronized void error(String s, Parameter p1)
+        {
+        println("ERROR:\n"+s, ALL_LOGS, true);
+        if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+        errors = true;
+        }
+
+    /** Posts a simple error. This causes the error flag to be raised as well. */
+    public synchronized void error(String s, Parameter p1, Parameter p2)
+        {
+        println("ERROR:\n"+s, ALL_LOGS, true);
+        if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+        if (p2!=null && p1!=null) println("     ALSO: " + p2, ALL_LOGS, true);
+        else println("PARAMETER: " + p2, ALL_LOGS, true);
+        errors = true;
+        }
+
+    /** Posts a warning. */
+    public synchronized void warning(String s, Parameter p1, Parameter p2)
+        {
+        println("WARNING:\n"+s, ALL_LOGS, true);
+        if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+        if (p2!=null && p1!=null) println("     ALSO: " + p2, ALL_LOGS, true);
+        else println("PARAMETER: " + p2, ALL_LOGS, true);
+        }
+
+    /** Posts a warning. */
+    public synchronized void warning(String s, Parameter p1)
+        {
+        println("WARNING:\n"+s, ALL_LOGS, true);
+        if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+        }
+
+    /** Posts a warning. */
+    public synchronized void warning(String s)
+        {
+        println("WARNING:\n"+s, ALL_LOGS, true);
+        }
+    
+    java.util.HashSet oneTimeWarnings = new java.util.HashSet();
+    /** Posts a warning one time only. */
+    public synchronized void warnOnce(String s)
+        {
+        if (!oneTimeWarnings.contains(s))
+            {
+            oneTimeWarnings.add(s);
+            println("ONCE-ONLY WARNING:\n"+s, ALL_LOGS, true);
+            }
+        }
+        
+    public synchronized void warnOnce(String s, Parameter p1)
+        {
+        if (!oneTimeWarnings.contains(s))
+            {
+            oneTimeWarnings.add(s);
+            println("ONCE-ONLY WARNING:\n"+s, ALL_LOGS, true);
+            if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+            }
+        }
+        
+    public synchronized void warnOnce(String s, Parameter p1, Parameter p2)
+        {
+        if (!oneTimeWarnings.contains(s))
+            {
+            oneTimeWarnings.add(s);
+            println("ONCE-ONLY WARNING:\n"+s, ALL_LOGS, true);
+            if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
+            if (p2!=null && p1!=null) println("     ALSO: " + p2, ALL_LOGS, true);
+            else println("PARAMETER: " + p2, ALL_LOGS, true);
+            }
+        }
+
+    
+    /** Posts a message. */
+    public synchronized void message(String s)
+        {
+        println(s, ALL_LOGS, true);
+        }
+  
+    /** Forces a file-based log to reopen, erasing its previous contents.
+        non-file logs ignore this. */
+    
+    public synchronized void reopen(int _log) throws IOException
+        {
+        Log oldlog = (Log)logs.elementAt(_log);
+        logs.setElementAt(oldlog.reopen(),_log);
+        }
+    
+    /** Forces one or more file-based logs to reopen, erasing 
+        their previous contents.  non-file logs ignore this. */
+    
+    public synchronized void reopen(int[] _logs) throws IOException
+        {
+        for(int x=0;x<_logs.length;x++)
+            {
+            Log oldlog = (Log)logs.elementAt(_logs[x]);
+            logs.setElementAt(oldlog.reopen(),_logs[x]);
+            }
+        }
+    
+
+    /** Prints a message to a given log, with a certain verbosity.  
+        <i>_announcement</i> indicates that the message is an announcement. 
+        @deprecated Verbosity no longer has an effect
+    */
+
+    synchronized void println(String s,
+        int _verbosity,
+        Log log,
+        boolean _announcement,
+        boolean _reposting) throws OutputException
+        {
+        if (log.writer==null) throw new OutputException("Log with a null writer: " + log);
+        if (!log.postAnnouncements && _announcement) return;  // don't write it
+        // if (log.verbosity >= _verbosity) return;  // don't write it
+        // if (verbosity >= _verbosity) return;  // don't write it
+        // now write it
+        log.writer.println(s);
+        // if (flush) 
+        // always flush
+        log.writer.flush();
+        //...and stash it in memory maybe
+        if (store && _announcement && !_reposting)
+            announcements.addElement(new Announcement(s));
+        }
+
+
+    /** Prints a message to a given log, 
+        with a certain verbosity.  If log==ALL_LOGS, posted to all logs which accept announcements. 
+        @deprecated Verbosity no longer has an effect
+    */
+    synchronized void println(String s,
+        int _verbosity,
+        int log,
+        boolean _announcement) throws OutputException
+        {
+        if (log==ALL_LOGS) for (int x = 0; x<logs.size();x++)
+                               {
+                               Log l = (Log) logs.elementAt(x);
+                               if (l==null) throw new OutputException("Unknown log number" + l);
+                               println(s,_verbosity,l,_announcement,false);
+                               }
+        else
+            {
+            Log l = (Log) logs.elementAt(log);
+            if (l==null) throw new OutputException("Unknown log number" + l);
+            println(s,_verbosity,l,_announcement,false);
+            }
+        }
+
+    /** Prints a message to a given log.  If log==ALL_LOGS, posted to all logs which accept announcements. 
+     */
+    public synchronized void println(String s,
+        int log,
+        boolean _announcement) throws OutputException
+        {
+        println(s, V_VERBOSE, log, _announcement);
+        }
+
+
+    /** Prints a non-announcement message to the given logs, 
+        with a certain verbosity. 
+        @deprecated Verbosity no longer has an effect
+    */
+    public synchronized void println(String s,
+        int _verbosity,
+        int[] _logs) throws OutputException
+        {
+        for(int x=0;x<_logs.length;x++)
+            println(s,V_VERBOSE,(Log)(logs.elementAt(_logs[x])),false,false);
+        }
+
+
+    /** Prints a non-announcement message to the given logs, 
+        with a certain verbosity. 
+        @deprecated Verbosity no longer has an effect
+    */
+    public synchronized void println(String s,
+        int _verbosity,
+        int log) throws OutputException
+        {
+        println(s,V_VERBOSE,(Log)(logs.elementAt(log)),false,false);
+        }
+
+
+    /** Prints a non-announcement message to the given logs, with a verbosity of V_NO_GENERAL. */
+    public synchronized void println(String s,
+        int log) throws OutputException
+        {
+        println(s,V_VERBOSE,log);
+        }
+
+
+    /** Prints a non-announcement message to a given log, with a 
+        certain verbosity. No '\n' is printed.  */
+    protected synchronized void print(String s,
+        int _verbosity,
+        Log log) throws OutputException
+        {
+        if (log.writer==null) throw new OutputException("Log with a null writer: " + log);
+        //if (log.verbosity >= _verbosity) return;  // don't write it
+        //if (verbosity >= _verbosity) return;  // don't write it
+        // now write it
+        log.writer.print(s);
+        // do not flush until you get a println
+        //if (flush) log.writer.flush();
+        }
+
+    /** Prints a non-announcement message to a given log, with a
+        certain verbosity. If log==ALL_LOGS, posted to all logs which accept announcements. 
+        No '\n' is printed.  */
+    public synchronized void print(String s,
+        int _verbosity,
+        int log) throws OutputException
+        {
+        if (log==ALL_LOGS) for (int x = 0; x<logs.size();x++)
+                               {
+                               Log l = (Log) logs.elementAt(x);
+                               if (l==null) throw new OutputException("Unknown log number" + l);
+                               print(s,V_VERBOSE,l);
+                               }
+        else
+            {
+            Log l = (Log) logs.elementAt(log);
+            if (l==null) throw new OutputException("Unknown log number" + l);
+            print(s,V_VERBOSE,l);
+            }
+        }
+
+    /** Prints a non-announcement message to a given log<!--, with a verbosity of V_NO_GENERAL-->.
+        If log==ALL_LOGS, posted to all logs which accept announcements. No '\n' is printed.  */
+    public synchronized void print(String s,
+        int log) throws OutputException
+        {
+        print(s, V_VERBOSE, log);
+        }
+
+    /** Prints a non-announcement message to the given logs, 
+        with a certain verbosity. No '\n' is printed.  
+        @deprecated Verbosity no longer has any effect 
+    */
+    public synchronized void print(String s,
+        int _verbosity,
+        int[] _logs) throws OutputException
+        {
+        for(int x=0;x<_logs.length;x++)
+            print(s,_logs[x]);
+        }
+
+    /** Prints a non-announcement message to the given logs, 
+        with a certain verbosity. No '\n' is printed.  
+    */
+    public synchronized void print(String s,
+        int[] _logs) throws OutputException
+        {
+        print(s, V_VERBOSE, _logs);
+        }
+
+    /** Exits with a fatal error if the error flag has been raised. */
+    public synchronized void exitIfErrors()
+        {
+        if (errors) 
+            {
+            println("SYSTEM EXITING FROM ERRORS\n",ALL_LOGS, true);
+            exitWithError();
+            }
+        }
+
+    /** Clears the error flag. */
+    public synchronized void clearErrors()
+        {
+        errors = false;
+        }
+
+
+    /** Clears out announcements.  Note that this will cause these
+        announcements to be unavailable for reposting after a restart! */
+    public synchronized void clearAnnouncements()
+        {
+        if (announcements!=null)
+            announcements = new Vector();
+        }
+
+    public synchronized void restart() throws IOException
+        {
+        // restart logs, then repost announcements to them
+        int ls = logs.size();
+        for(int x=0;x<ls;x++)
+            {
+            Log l = (Log)(logs.elementAt(x));
+            logs.setElementAt(l = l.restarter.restart(l),x);
+            if (l.repostAnnouncementsOnRestart && store)
+                {    
+                int as = announcements.size();
+                for (int y=0;y<as;y++)
+                    {
+                    Announcement a = (Announcement)(announcements.elementAt(y));
+                    println(a.text,V_VERBOSE,l,true,true);
+                    }
+                }
+            }
+
+        // exit with a fatal error if the errors flag is set. 
+        exitIfErrors();
+        }
+        
+    /** Returns a compressing input stream using JZLib (http://www.jcraft.com/jzlib/).  If JZLib is not available on your system, this method will return null. */
+    public static InputStream makeCompressingInputStream(InputStream in)
+        {
+        // to do this, we're going to use reflection.  But here's the equivalent code:
+        /*
+          return new com.jcraft.jzlib.ZInputStream(in);
+        */
+        try
+            {
+            return (InputStream)(Class.forName("com.jcraft.jzlib.ZInputStream").getConstructor(new Class[] { InputStream.class } ).newInstance(new Object[] { in }));
+            }
+        catch (Exception e) { return null; }  // failed, probably doesn't have JZLib on the system
+        }
+
+    /** Returns a compressing output stream using JZLib (http://www.jcraft.com/jzlib/).  If JZLib is not available on your system, this method will return null. */
+    public static OutputStream makeCompressingOutputStream(OutputStream out)
+        {
+        // to do this, we're going to use reflection.  But here's the equivalent code:
+        /*
+          com.jcraft.jzlib.ZOutputStream stream = new com.jcraft.jzlib.ZOutputStream(out, com.jcraft.jzlib.JZlib.Z_BEST_SPEED);
+          stream.setFlushMode(com.jcraft.jzlib.JZlib.Z_SYNC_FLUSH);
+          return stream;
+        */
+        try
+            {
+            Class outz = Class.forName("com.jcraft.jzlib.JZlib");
+            int Z_BEST_SPEED = outz.getField("Z_BEST_SPEED").getInt(null);
+            int Z_SYNC_FLUSH = outz.getField("Z_SYNC_FLUSH").getInt(null);
+            
+            Class outc = Class.forName("com.jcraft.jzlib.ZOutputStream");
+            Object outi = outc.getConstructor(new Class[] { OutputStream.class, Integer.TYPE }).newInstance(new Object[] { out, new Integer(Z_BEST_SPEED) });
+            outc.getMethod("setFlushMode", new Class[] { Integer.TYPE }).invoke(outi, new Object[] { new Integer(Z_SYNC_FLUSH) });
+            return (OutputStream) outi;
+            }
+        catch (Exception e) { return null; } // failed, probably doesn't have JZLib on the system
+        }
+
+
+    class Announcement implements Serializable
+        {
+        /** The announcement's...anouncement.*/
+        public String text;
+
+        /** Creates a new announcement with text <i>t</i> and verbosity value <i>v</i> */
+        public Announcement (String t)
+            {
+            text = t;
+            }
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/OutputException.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/OutputException.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/OutputException.java	(revision 6152)
@@ -0,0 +1,27 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/*
+ * OutputException.java
+ * Created: Sat Aug  7 12:06:49 1999
+ */
+
+
+/**
+ *
+ * Thrown whenever a problem occurs when attempting to output to a Log.
+ *
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class OutputException extends RuntimeException
+    {
+    public OutputException(String s) { super(s); }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/ParamClassLoadException.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/ParamClassLoadException.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/ParamClassLoadException.java	(revision 6152)
@@ -0,0 +1,32 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * ParamClassLoadException.java
+ * 
+ * Created: Tue Aug 10 21:22:08 1999
+ * By: Sean Luke
+ */
+
+/**
+ * This exception is thrown by the Parameter Database when it fails to
+ * locate and load a class specified by a given parameter as requested.
+ * Most commonly this results in the program exiting with an error, so
+ * it is defined as a RuntimeException so you don't have to catch it
+ * or declare that you throw it.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class ParamClassLoadException extends RuntimeException
+    {
+    public ParamClassLoadException(String s)
+        { super("\n"+s); }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Parameter.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Parameter.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Parameter.java	(revision 6152)
@@ -0,0 +1,149 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.io.Serializable;
+
+/*
+ * Parameter.java
+ * Created: Sat Aug  7 12:06:49 1999
+ */
+
+/**
+ *
+ * <p>A Parameter is an object which the ParameterDatabase class
+ * uses as a key to associate with strings, forming a key-value pair.
+ * Parameters are designed to be hierarchical in nature, consisting
+ * of "path items" separated by a path separator.
+ * Parameters are created either from a single path item, from an array
+ * of path items, or both.  For example, a parameter with the path
+ * foo.bar.baz might be created from 
+ * <tt>new Parameter(new String[] {"foo","bar","baz"})</tt>
+ * 
+ * <p>Parameters are not mutable -- but once a parameter is created, path 
+ * items may be pushed an popped from it, forming a new parameter.
+ * For example, if a parameter p consists of the path foo.bar.baz,
+ * p.pop() results in a new parameter whose path is foo.bar
+ * This pushing and popping isn't cheap, so be sparing.
+ *
+ * <p>Because this system internally uses "." as its path separator, you should
+ * not use that character in parts of the path that you provide; however
+ * if you need some other path separator, you can change the delimiter in
+ * the code trivially.
+ * In fact, you can create a new Parameter with a path foo.bar.baz simply
+ * by calling <tt>new Parameter("foo.bar.baz")</tt> but you'd better know
+ * what you're doing.
+ *
+ * <p>Additionally, parameters must not contain "#", "=", non-ascii values,
+ * or whitespace.  Yes, a parameter path item may be empty.
+ *
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+
+public class Parameter implements Serializable
+    {
+    public String param;
+    public static final char delimiter = '.';
+
+    /** Creates a new parameter by joining the path items in s into a single path. */
+    public Parameter(String[] s) throws ec.util.BadParameterException
+        {
+        if (s.length==0)
+            throw new BadParameterException("Parameter created with length 0");
+        for (int x=0;x<s.length;x++)
+            {
+            if (s[x]==null)
+                throw new BadParameterException("Parameter created with null string");
+            if ( x == 0) param = s[x];
+            else param += ( delimiter + s[x] );
+            }
+        }
+
+
+    /** Creates a new parameter from the single path item in s. */
+    public Parameter (String s) throws BadParameterException
+        {
+        if (s==null)
+            throw new BadParameterException("Parameter created with null string");
+        param = s;
+        }
+
+
+    /** Creates a new parameter from the path item in s, plus the path items in s2.  s2 may be null or empty, but not s */
+    public Parameter(String s, String[] s2)
+        {
+        if (s==null)
+            throw new BadParameterException("Parameter created with null string");
+        param = s;
+        for (int x=0;x<s2.length;x++)
+            {
+            if (s2[x]==null)
+                throw new BadParameterException("Parameter created with null string");
+            else param += ( delimiter + s2[x] );
+            }
+        }
+
+
+
+    /** Returns a new parameter with s added to the end of the current path items. */ 
+    public Parameter push(String s)
+        {
+        if (s==null)
+            throw new BadParameterException("Parameter pushed with null string");
+        return new Parameter ( param + delimiter + s );
+        }
+
+
+    /** Returns a new parameter with the path items in s added to the end of the current path items. */ 
+    public Parameter push(String[] s)
+        {
+        return new Parameter(param,s);
+        }
+
+
+
+    /** Returns a new parameter with one path item popped off the end.  If this would result in a parameter with an empty collection of path items, null is returned. */ 
+    public Parameter pop()
+        {
+        int x = param.lastIndexOf(delimiter);
+        if (x==-1) // there's nothing left.
+            return null;
+        else return new Parameter(param.substring(0,x));
+        }
+
+    /** Returns a new parameter with n path items popped off the end.  If this would result in a parameter with an empty collection of path items, null is returned. */ 
+    public Parameter popn(int n)
+        {
+        String s = param;
+
+        for (int y=0;y<n;y++)
+            {
+            int x = s.lastIndexOf(delimiter);
+            if (x==-1) // there's nothing left
+                return null;
+            else s = param.substring(0,x);
+            }
+        return new Parameter(s);
+        }
+
+
+    /** Returns the path item at the far end of the parameter. */ 
+    public String top ()
+        {
+        int x = param.lastIndexOf(delimiter);
+        if (x==-1) return param;
+        else return param.substring(x+1);
+        }
+    
+    public String toString()
+        {
+        return param;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabase.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabase.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabase.java	(revision 6152)
@@ -0,0 +1,2577 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+
+/* 
+
+ * ParameterDatabase.java
+ * Created: Sat Aug  7 12:09:19 1999
+ */
+
+/**
+ * 
+ * <p>
+ * This extension of the Properties class allows you to set, get, and delete
+ * Parameters in a hierarchical tree-like database. The database consists of a
+ * list of Parameters, plus an array of "parent databases" which it falls back
+ * on when it can't find the Parameter you're looking for. Parents may also have
+ * arrays of parents, and so on..
+ * 
+ * <p>
+ * The parameters are loaded from a Java property-list file, which is basically
+ * a collection of parameter=value pairs, one per line. Empty lines and lines
+ * beginning with # are ignored. These parameters and their values are
+ * <b>case-sensitive </b>, and whitespace is trimmed I believe.
+ * 
+ * <p>
+ * An optional set of parameters, "parent. <i>n </i>", where <i>n </i> are
+ * consecutive integers starting at 0, define the filenames of the database's
+ * parents.
+ * 
+ * <p>
+ * An optional set of parameters, "print-params", specifies whether or not
+ * parameters should be printed as they are used (through one of the get(...)
+ * methods). If print-params is unset, or set to false or FALSE, nothing is
+ * printed. If set to non-false, then the parameters are printed prepended with a "P:"
+ * when their values are requested,  "E:" when their existence is tested.  Prior to the
+ * "P:" or "E:" you may see a "!" (meaning that the parameter isn't in the database),
+ * or a "&lt;" (meaning that the parameter was a default parameter which was never
+ * looked up because the primary parameter contained the value).
+ * 
+ * <p>
+ * <p>
+ * When you create a ParameterDatabase using new ParameterDatabase(), it is
+ * created thus:
+ * 
+ * <p>
+ * <table border=0 cellpadding=0 cellspacing=0>
+ * <tr>
+ * <td><tt>DATABASE:</tt></td>
+ * <td><tt>&nbsp;database</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>FROM:</tt></td>
+ * <td><tt>&nbsp;(empty)</tt></td>
+ * </tr>
+ * </table>
+ * 
+ * 
+ * <p>
+ * When you create a ParameterDatabase using new ParameterDatabase( <i>file
+ * </i>), it is created by loading the database file, and its parent file tree,
+ * thus:
+ * 
+ * <p>
+ * <table border=0 cellpadding=0 cellspacing=0>
+ * <tr>
+ * <td><tt>DATABASE:</tt></td>
+ * <td><tt>&nbsp;database</tt></td>
+ * <td><tt>&nbsp;-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>FROM:</tt></td>
+ * <td><tt>&nbsp;(empty)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;(file)</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.0)</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.0)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent1</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.1)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent1</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.1)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * </table>
+ * 
+ * 
+ * <p>
+ * When you create a ParameterDatabase using new ParameterDatabase( <i>file,argv
+ * </i>), the preferred way, it is created thus:
+ * 
+ * 
+ * <p>
+ * <table border=0 cellpadding=0 cellspacing=0>
+ * <tr>
+ * <td><tt>DATABASE:</tt></td>
+ * <td><tt>&nbsp;database</tt></td>
+ * <td><tt>&nbsp;-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent0</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>FROM:</tt></td>
+ * <td><tt>&nbsp;(empty)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>(argv)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;(file)</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.0)</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.0)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent1</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.1)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;parent1</tt></td>
+ * <td><tt>&nbsp;+-&gt;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;|</tt></td>
+ * <td><tt>&nbsp;(parent.1)</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * <tr>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;....</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * <td><tt>&nbsp;</tt></td>
+ * </tr>
+ * </table>
+ * 
+ * 
+ * <p>
+ * ...that is, the actual top database is empty, and stores parameters added
+ * programmatically; its parent is a database formed from arguments passed in on
+ * the command line; <i>its </i> parent is the parameter database which actually
+ * loads from foo. This allows you to programmatically add parameters which
+ * override those in foo, then delete them, thus bringing foo's parameters back
+ * in view.
+ * 
+ * <p>
+ * Once a parameter database is loaded, you query it with the <tt>get</tt>
+ * methods. The database, then its parents, are searched until a match is found
+ * for your parameter. The search rules are thus: (1) the root database is
+ * searched first. (2) If a database being searched doesn't contain the data, it
+ * searches its parents recursively, starting with parent 0, then moving up,
+ * until all searches are exhausted or something was found. (3) No database is
+ * searched twice.
+ *
+ * <p>The various <tt>get</tt> methods all take two parameters.  The first
+ * parameter is fetched and retrieved first.  If that fails, the second one
+ * (known as the <i>default parameter</i>) is fetched and retrieved.  You
+ * can pass in <tt>null</tt> for the default parameter if you don't have one.
+ *
+ * <p>You can test a parameter for existence with the <tt>exists</tt> methods.
+ * 
+ * <p>
+ * You can set a parameter (in the topmost database <i>only </i> with the
+ * <tt>set</tt> command. The <tt>remove</tt> command removes a parameter
+ * from the topmost database only. The <tt>removeDeeply</tt> command removes
+ * that parameter from every database.
+ * 
+ * <p>
+ * The values stored in a parameter database must not contain "#", "=",
+ * non-ascii values, or whitespace.
+ * 
+ * <p>
+ * <b>Note for JDK 1.1 </b>. Finally recovering from stupendous idiocy, JDK 1.2
+ * included parseDouble() and parseFloat() commands; now you can READ A FLOAT
+ * FROM A STRING without having to create a Float object first! Anyway, you will
+ * need to modify the getFloat() method below if you're running on JDK 1.1, but
+ * understand that large numbers of calls to the method may be inefficient.
+ * Sample JDK 1.1 code is given with those methods, but is commented out.
+ * 
+ * 
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class ParameterDatabase extends Properties implements Serializable 
+    {
+    public static final String C_HERE = "$";
+    public static final String UNKNOWN_VALUE = "";
+    public static final String PRINT_PARAMS = "print-params";
+    public static final int PS_UNKNOWN = -1;
+    public static final int PS_NONE = 0;
+    public static final int PS_PRINT_PARAMS = 1;
+    public int printState = PS_UNKNOWN;
+    Vector parents;
+    File directory;
+    String filename;
+    boolean checked;
+    Hashtable gotten;
+    Hashtable accessed;
+    Vector listeners;
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a full Class name, and the class must be a descendent of but not
+     * equal to <i>mustCastTosuperclass </i>. Loads the class and returns an
+     * instance (constructed with the default constructor), or throws a
+     * ParamClassLoadException if there is no such Class. If the parameter is
+     * not found, the defaultParameter is used. The parameter chosen is marked
+     * "used".
+     */
+    public Object getInstanceForParameter(Parameter parameter, Parameter defaultParameter, Class mustCastTosuperclass) throws ParamClassLoadException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        Parameter p;
+        if (_exists(parameter))
+            p = parameter;
+        else if (_exists(defaultParameter))
+            p = defaultParameter;
+        else
+            throw new ParamClassLoadException(
+                "No class name provided.\nPARAMETER: "
+                + parameter
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter));
+        try 
+            {
+            Class c = Class.forName(get(p));
+            if (!mustCastTosuperclass.isAssignableFrom(c))
+                throw new ParamClassLoadException("The class "
+                    + c.getName()
+                    + "\ndoes not cast into the superclass "
+                    + mustCastTosuperclass.getName()
+                    + "\nPARAMETER: "
+                    + parameter
+                    + (defaultParameter == null ? "" : "\n     ALSO: "
+                        + defaultParameter));
+            if (mustCastTosuperclass == c)
+                throw new ParamClassLoadException("The class "
+                    + c.getName()
+                    + "\nmust not be the same as the required superclass "
+                    + mustCastTosuperclass.getName()
+                    + "\nPARAMETER: "
+                    + parameter
+                    + (defaultParameter == null ? "" : "\n     ALSO: "
+                        + defaultParameter));
+            return c.newInstance();
+            } 
+        catch (ClassNotFoundException e) 
+            {
+            throw new ParamClassLoadException("Class not found: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n" + e);
+            } 
+        catch (IllegalArgumentException e) 
+            {
+            throw new ParamClassLoadException("Could not load class: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n" + e);
+            } 
+        catch (InstantiationException e) 
+            {
+            throw new ParamClassLoadException(
+                "The requested class is an interface or an abstract class: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n"
+                + e);
+            } 
+        catch (IllegalAccessException e) 
+            {
+            throw new ParamClassLoadException(
+                "The requested class cannot be initialized with the default initializer: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n"
+                + e);
+            }
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a full Class name, and the class must be a descendent, or equal
+     * to, <i>mustCastTosuperclass </i>. Loads the class and returns an instance
+     * (constructed with the default constructor), or throws a
+     * ParamClassLoadException if there is no such Class. The parameter chosen
+     * is marked "used".
+     */
+    public Object getInstanceForParameterEq(Parameter parameter,
+        Parameter defaultParameter, Class mustCastTosuperclass)
+        throws ParamClassLoadException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        Parameter p;
+        if (_exists(parameter))
+            p = parameter;
+        else if (_exists(defaultParameter))
+            p = defaultParameter;
+        else
+            throw new ParamClassLoadException(
+                "No class name provided.\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter));
+        try
+            {
+            Class c = Class.forName(get(p));
+            if (!mustCastTosuperclass.isAssignableFrom(c))
+                throw new ParamClassLoadException("The class "
+                    + c.getName()
+                    + "\ndoes not cast into the superclass "
+                    + mustCastTosuperclass.getName()
+                    + "\nPARAMETER: "
+                    + parameter
+                    + "\n     ALSO: "
+                    + (defaultParameter == null ? "" : "\n     ALSO: "
+                        + defaultParameter));
+            return c.newInstance();
+            } 
+        catch (ClassNotFoundException e) 
+            {
+            throw new ParamClassLoadException("Class not found: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n" + e);
+            } 
+        catch (IllegalArgumentException e) 
+            {
+            throw new ParamClassLoadException("Could not load class: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n" + e);
+            } 
+        catch (InstantiationException e) 
+            {
+            throw new ParamClassLoadException(
+                "The requested class is an interface or an abstract class: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n"
+                + e);
+            } 
+        catch (IllegalAccessException e) 
+            {
+            throw new ParamClassLoadException(
+                "The requested class cannot be initialized with the default initializer: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n"
+                + e);
+            }
+        }
+
+    /**
+     * Searches down through databases to find a given parameter. The value
+     * associated with this parameter must be a full Class name, and the class
+     * must be a descendent of but not equal to <i>mustCastTosuperclass </i>.
+     * Loads and returns the associated Class, or throws a
+     * ParamClassLoadException if there is no such Class. If the parameter is
+     * not found, the defaultParameter is used. The parameter chosen is marked
+     * "used".
+     */
+    public Object getClassForParameter(Parameter parameter,
+        Parameter defaultParameter, Class mustCastTosuperclass)
+        throws ParamClassLoadException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        Parameter p;
+        if (_exists(parameter))
+            p = parameter;
+        else if (_exists(defaultParameter))
+            p = defaultParameter;
+        else
+            throw new ParamClassLoadException(
+                "No class name provided.\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter));
+        try
+            {
+            Class c = Class.forName(get(p));
+            if (!mustCastTosuperclass.isAssignableFrom(c))
+                throw new ParamClassLoadException("The class "
+                    + c.getName()
+                    + "\ndoes not cast into the superclass "
+                    + mustCastTosuperclass.getName()
+                    + "\nPARAMETER: "
+                    + parameter
+                    + "\n     ALSO: "
+                    + (defaultParameter == null ? "" : "\n     ALSO: "
+                        + defaultParameter));
+            return c;
+            } 
+        catch (ClassNotFoundException e) 
+            {
+            throw new ParamClassLoadException("Class not found: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n" + e);
+            } 
+        catch (IllegalArgumentException e) 
+            {
+            throw new ParamClassLoadException("Could not load class: "
+                + get(p)
+                + "\nPARAMETER: "
+                + parameter
+                + "\n     ALSO: "
+                + (defaultParameter == null ? "" : "\n     ALSO: "
+                    + defaultParameter) + "\nEXCEPTION: \n\n" + e);
+            }
+        }
+
+    /**
+     * Searches down through databases to find a given parameter; If the
+     * parameter does not exist, defaultValue is returned. If the parameter
+     * exists, and it is set to "false" (case insensitive), false is returned.
+     * Else true is returned. The parameter chosen is marked "used" if it
+     * exists.
+     */
+    public boolean getBoolean(Parameter parameter,
+        Parameter defaultParameter, boolean defaultValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getBoolean(parameter, defaultValue);
+        else
+            return getBoolean(defaultParameter, defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter; If the
+     * parameter does not exist, defaultValue is returned. If the parameter
+     * exists, and it is set to "false" (case insensitive), false is returned.
+     * Else true is returned. The parameter chosen is marked "used" if it
+     * exists.
+     */
+    boolean getBoolean(Parameter parameter, boolean defaultValue) 
+        {
+        if (!_exists(parameter))
+            return defaultValue;
+        return (!get(parameter).equalsIgnoreCase("false"));
+        }
+
+    /**
+     * Parses an integer from a string, either in decimal or (if starting with
+     * an x) in hex
+     */
+    // we assume that the string has been trimmed already
+    /*protected*/ int parseInt(String string)
+        throws NumberFormatException 
+        {
+        char c;
+        if (string != null && string.length() > 0
+            && ((string.charAt(0) == (c = 'x')) || c == 'X')) 
+            {
+            // it's a hex int, load it as hex
+            return Integer.parseInt(string.substring(1), 16);
+            } 
+        else
+            {
+            try
+                {
+                // it's decimal
+                return Integer.parseInt(string);
+                }
+            catch (NumberFormatException e)
+                {
+                // maybe it's a double ending in .0, which should be okay
+                try 
+                    {
+                    double d = Double.parseDouble(string);
+                    if (d == (int) d) return (int) d;  // looking fine
+                    else throw e;
+                    }
+                catch (NumberFormatException e2)
+                    {
+                    throw e;
+                    }
+                }
+            }
+        }
+
+    /**
+     * Parses a long from a string, either in decimal or (if starting with an x)
+     * in hex
+     */
+    // we assume that the string has been trimmed already
+    /*protected*/ long parseLong(String string)
+        throws NumberFormatException 
+        {
+        char c;
+        if (string != null && string.length() > 0
+            && ((string.charAt(0) == (c = 'x')) || c == 'X')) 
+            {
+            // it's a hex int, load it as hex
+            return Long.parseLong(string.substring(1), 16);
+            } 
+        else
+            { 
+            try
+                {
+                // it's decimal
+                return Long.parseLong(string);
+                }
+            catch (NumberFormatException e)
+                {
+                // maybe it's a double ending in .0, which should be okay
+                try 
+                    {
+                    double d = Double.parseDouble(string);
+                    if (d == (long) d) return (long) d;  // looking fine
+                    else throw e;
+                    }
+                catch (NumberFormatException e2)
+                    {
+                    throw e;
+                    }
+                }
+            }
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be an integer. It returns the value, else throws a
+     * NumberFormatException exception if there is an error in parsing the
+     * parameter. The parameter chosen is marked "used" if it exists. Integers
+     * may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    /*protected*/ int getInt(Parameter parameter)
+        throws NumberFormatException 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                return parseInt(get(parameter));
+                } 
+            catch (NumberFormatException e) 
+                {
+                throw new NumberFormatException("Bad integer ("
+                    + get(parameter) + " ) for parameter " + parameter);
+                }
+            } 
+        else
+            throw new NumberFormatException(
+                "Integer does not exist for parameter " + parameter);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be an integer. It returns the value, else throws a
+     * NumberFormatException exception if there is an error in parsing the
+     * parameter. The parameter chosen is marked "used" if it exists. Integers
+     * may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    public int getInt(Parameter parameter, Parameter defaultParameter)
+        throws NumberFormatException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getInt(parameter);
+        else if (_exists(defaultParameter))
+            return getInt(defaultParameter);
+        else
+            throw new NumberFormatException(
+                "Integer does not exist for either parameter " + parameter
+                + "\nor\n" + defaultParameter);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be an integer >= minValue. It returns the value, or minValue-1 if
+     * the value is out of range or if there is an error in parsing the
+     * parameter. The parameter chosen is marked "used" if it exists. Integers
+     * may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    public int getInt(Parameter parameter, Parameter defaultParameter,
+        int minValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getInt(parameter, minValue);
+        else
+            return getInt(defaultParameter, minValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be an integer >= minValue. It returns the value, or minValue-1 if
+     * the value is out of range or if there is an error in parsing the
+     * parameter. The parameter chosen is marked "used" if it exists. Integers
+     * may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    /*protected*/ int getInt(Parameter parameter, int minValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                int i = parseInt(get(parameter));
+                if (i < minValue)
+                    return minValue - 1;
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return minValue - 1;
+                }
+            } 
+        else
+            return minValue - 1;
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * an integer. If there is an error in parsing the parameter, then default
+     * is returned. The parameter chosen is marked "used" if it exists. Integers
+     * may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    public int getIntWithDefault(Parameter parameter,
+        Parameter defaultParameter, int defaultValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getIntWithDefault(parameter, defaultValue);
+        else
+            return getIntWithDefault(defaultParameter, defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * an integer. If there is an error in parsing the parameter, then default
+     * is returned. The parameter chosen is marked "used" if it exists. Integers
+     * may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    int getIntWithDefault(Parameter parameter, int defaultValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                return parseInt(get(parameter));
+                } 
+            catch (NumberFormatException e) 
+                {
+                return defaultValue;
+                }
+            } 
+        else
+            return defaultValue;
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be an integer >= minValue and <= maxValue. It returns the value, or
+     * minValue-1 if the value is out of range or if there is an error in
+     * parsing the parameter. The parameter chosen is marked "used" if it
+     * exists. Integers may be in decimal or (if preceded with an X or x) in
+     * hexadecimal.
+     */
+    public int getIntWithMax(Parameter parameter,
+        Parameter defaultParameter, int minValue, int maxValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getIntWithMax(parameter, minValue, maxValue);
+        else
+            return getIntWithMax(defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be an integer >= minValue and <= maxValue. It returns the value, or
+     * minValue-1 if the value is out of range or if there is an error in
+     * parsing the parameter. The parameter chosen is marked "used" if it
+     * exists. Integers may be in decimal or (if preceded with an X or x) in
+     * hexadecimal.
+     */
+    int getIntWithMax(Parameter parameter, int minValue, int maxValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                int i = parseInt(get(parameter));
+                if (i < minValue)
+                    return minValue - 1;
+                if (i > maxValue)
+                    return minValue - 1;
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return minValue - 1;
+                }
+            } 
+        else
+            return minValue - 1;
+        }
+
+
+    float getFloat(Parameter parameter) throws NumberFormatException
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                // For JDK 1.2 and later, this is more efficient...
+                // float i = Float.parseFloat(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+                return Float.valueOf(get(parameter)).floatValue(); // what stupidity...
+                } 
+            catch (NumberFormatException e) 
+                {
+                throw new NumberFormatException("Bad float ("
+                    + get(parameter) + " ) for parameter " + parameter);
+                }
+            } 
+        else
+            throw new NumberFormatException(
+                "Float does not exist for parameter " + parameter);
+        }
+
+    /*
+     * Searches down through databases to find a given parameter, whose value
+     * must be a float. It returns the value, else throws a
+     * NumberFormatException exception if there is an error in parsing the
+     * parameter. The parameter chosen is marked "used" if it exists.
+     */
+    public float getFloat(Parameter parameter, Parameter defaultParameter)
+        throws NumberFormatException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getFloat(parameter);
+        else if (_exists(defaultParameter))
+            return getFloat(defaultParameter);
+        else
+            throw new NumberFormatException(
+                "Float does not exist for either parameter " + parameter
+                + "\nor\n" + defaultParameter);
+        }
+        
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a float >= minValue. If not, this method returns minvalue-1, else
+     * it returns the parameter value. The parameter chosen is marked "used" if
+     * it exists.
+     */
+
+    public float getFloat(Parameter parameter,
+        Parameter defaultParameter, double minValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getFloat(parameter, minValue);
+        else
+            return getFloat(defaultParameter, minValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a float >= minValue. If not, this method returns minvalue-1, else
+     * it returns the parameter value. The parameter chosen is marked "used" if
+     * it exists.
+     */
+
+    float getFloat(Parameter parameter, double minValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                float i = Float.valueOf(get(parameter)).floatValue(); // what stupidity...
+
+                // For JDK 1.2 and later, this is more efficient...
+                // float i = Float.parseFloat(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+
+                if (i < minValue)
+                    return (float) (minValue - 1);
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return (float) (minValue - 1);
+                }
+            } 
+        else
+            return (float) (minValue - 1);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * a float. If there is an error in parsing the parameter, then default is
+     * returned. The parameter chosen is marked "used" if it exists.
+     */
+    public float getFloatWithDefault(Parameter parameter,
+        Parameter defaultParameter, double defaultValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getFloatWithDefault(parameter, defaultValue);
+        else
+            return getFloatWithDefault(defaultParameter, defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * a float. If there is an error in parsing the parameter, then default is
+     * returned. The parameter chosen is marked "used" if it exists.
+     */
+    float getFloatWithDefault(Parameter parameter, double defaultValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                // For JDK 1.2 and later, this is more efficient...
+                // return Float.parseFloat(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+                return Float.valueOf(get(parameter)).floatValue(); // what stupidity...
+                } 
+            catch (NumberFormatException e) 
+                {
+                return (float) (defaultValue);
+                }
+            } 
+        else
+            return (float) (defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a float >= minValue and <= maxValue. If not, this method returns
+     * minvalue-1, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists.
+     */
+
+    public float getFloatWithMax(Parameter parameter,
+        Parameter defaultParameter, double minValue, double maxValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getFloat(parameter, minValue, maxValue);
+        else
+            return getFloat(defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a float >= minValue and <= maxValue. If not, this method returns
+     * minvalue-1, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists.
+     *
+     * @deprecated Use getFloatWithMax instead
+     */
+
+    public float getFloat(Parameter parameter,
+        Parameter defaultParameter, double minValue, double maxValue) 
+        {
+        return getFloatWithMax(parameter, defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a float >= minValue and <= maxValue. If not, this method returns
+     * minvalue-1, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists.
+     */
+
+    float getFloat(Parameter parameter, double minValue, double maxValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                float i = Float.valueOf(get(parameter)).floatValue(); // what stupidity...
+
+                // For JDK 1.2 and later, this is more efficient...
+                // float i = Float.parseFloat(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+
+                if (i < minValue)
+                    return (float) (minValue - 1);
+                if (i > maxValue)
+                    return (float) (minValue - 1);
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return (float) (minValue - 1);
+                }
+            } 
+        else
+            return (float) (minValue - 1);
+        }
+
+    double getDouble(Parameter parameter) throws NumberFormatException
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                // For JDK 1.2 and later, this is more efficient...
+                // double i = Double.parseDouble(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+                return Double.valueOf(get(parameter)).doubleValue(); // what stupidity...
+                } 
+            catch (NumberFormatException e) 
+                {
+                throw new NumberFormatException("Bad double ("
+                    + get(parameter) + " ) for parameter " + parameter);
+                }
+            } 
+        else
+            throw new NumberFormatException(
+                "Double does not exist for parameter " + parameter);
+        }
+
+    /*
+     * Searches down through databases to find a given parameter, whose value
+     * must be an double. It returns the value, else throws a
+     * NumberFormatException exception if there is an error in parsing the
+     * parameter. The parameter chosen is marked "used" if it exists. 
+     */
+    public double getDouble(Parameter parameter, Parameter defaultParameter)
+        throws NumberFormatException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getDouble(parameter);
+        else if (_exists(defaultParameter))
+            return getDouble(defaultParameter);
+        else
+            throw new NumberFormatException(
+                "Double does not exist for either parameter " + parameter
+                + "\nor\n" + defaultParameter);
+        }
+        
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a double >= minValue. If not, this method returns minvalue-1,
+     * else it returns the parameter value. The parameter chosen is marked
+     * "used" if it exists.
+     */
+
+    public double getDouble(Parameter parameter,
+        Parameter defaultParameter, double minValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getDouble(parameter, minValue);
+        else
+            return getDouble(defaultParameter, minValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a double >= minValue. If not, this method returns minvalue-1,
+     * else it returns the parameter value. The parameter chosen is marked
+     * "used" if it exists.
+     */
+
+    double getDouble(Parameter parameter, double minValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                double i = Double.valueOf(get(parameter)).doubleValue(); // what stupidity...
+
+                // For JDK 1.2 and later, this is more efficient...
+                // double i = Double.parseDouble(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+
+                if (i < minValue)
+                    return (double) (minValue - 1);
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return (double) (minValue - 1);
+                }
+            } 
+        else
+            return (double) (minValue - 1);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a double >= minValue and <= maxValue. If not, this method returns
+     * minvalue-1, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists.
+     */
+
+    public double getDoubleWithMax(Parameter parameter,
+        Parameter defaultParameter, double minValue, double maxValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getDouble(parameter, minValue, maxValue);
+        else
+            return getDouble(defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a double >= minValue and <= maxValue. If not, this method returns
+     * minvalue-1, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists.
+     *
+     * @deprecated use getDoubleWithMax instead
+     */
+
+    public double getDouble(Parameter parameter,
+        Parameter defaultParameter, double minValue, double maxValue) 
+        {
+        return getDoubleWithMax(parameter, defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a double >= minValue and <= maxValue. If not, this method returns
+     * minvalue-1, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists.
+     */
+
+    double getDouble(Parameter parameter, double minValue, double maxValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                double i = Double.valueOf(get(parameter)).doubleValue(); // what stupidity...
+
+                // For JDK 1.2 and later, this is more efficient...
+                // double i = Double.parseDouble(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+
+                if (i < minValue)
+                    return (double) (minValue - 1);
+                if (i > maxValue)
+                    return (double) (minValue - 1);
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return (double) (minValue - 1);
+                }
+            } 
+        else
+            return (double) (minValue - 1);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * a float. If there is an error in parsing the parameter, then default is
+     * returned. The parameter chosen is marked "used" if it exists.
+     */
+    public double getDoubleWithDefault(Parameter parameter,
+        Parameter defaultParameter, double defaultValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getDoubleWithDefault(parameter, defaultValue);
+        else
+            return getDoubleWithDefault(defaultParameter, defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * a float. If there is an error in parsing the parameter, then default is
+     * returned. The parameter chosen is marked "used" if it exists.
+     */
+    double getDoubleWithDefault(Parameter parameter, double defaultValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                // For JDK 1.2 and later, this is more efficient...
+                // return Double.parseDouble(get(parameter));
+                // ...but we can't use it and still be compatible with JDK 1.1
+                return Double.valueOf(get(parameter)).doubleValue(); // what stupidity...
+                } 
+            catch (NumberFormatException e) 
+                {
+                return defaultValue;
+                }
+            } 
+        else
+            return defaultValue;
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a long. It returns the value, else throws a NumberFormatException
+     * exception if there is an error in parsing the parameter. The parameter
+     * chosen is marked "used" if it exists. Longs may be in decimal or (if
+     * preceded with an X or x) in hexadecimal.
+     */
+    /*protected*/ long getLong(Parameter parameter)
+        throws NumberFormatException 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                return parseLong(get(parameter));
+                } 
+            catch (NumberFormatException e) 
+                {
+                throw new NumberFormatException("Bad long (" + get(parameter)
+                    + " ) for parameter " + parameter);
+                }
+            } 
+        else
+            throw new NumberFormatException(
+                "Long does not exist for parameter " + parameter);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a long. It returns the value, else throws a NumberFormatException
+     * exception if there is an error in parsing the parameter. The parameter
+     * chosen is marked "used" if it exists. Longs may be in decimal or (if
+     * preceded with an X or x) in hexadecimal.
+     */
+    public long getLong(Parameter parameter, Parameter defaultParameter)
+        throws NumberFormatException 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getLong(parameter);
+        else if (_exists(defaultParameter))
+            return getLong(defaultParameter);
+        else
+            throw new NumberFormatException(
+                "Long does not exist for either parameter " + parameter
+                + "\nor\n" + defaultParameter);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a long >= minValue. If not, this method returns errValue, else it
+     * returns the parameter value. The parameter chosen is marked "used" if it
+     * exists. Longs may be in decimal or (if preceded with an X or x) in
+     * hexadecimal.
+     */
+
+    public long getLong(Parameter parameter, Parameter defaultParameter,
+        long minValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getLong(parameter, minValue);
+        else
+            return getLong(defaultParameter, minValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a long >= minValue. If not, this method returns errValue, else it
+     * returns the parameter value. The parameter chosen is marked "used" if it
+     * exists. Longs may be in decimal or (if preceded with an X or x) in
+     * hexadecimal.
+     */
+    long getLong(Parameter parameter, long minValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                long i = parseLong(get(parameter));
+                if (i < minValue)
+                    return minValue - 1;
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return minValue - 1;
+                }
+            } 
+        else
+            return (minValue - 1);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * a long. If there is an error in parsing the parameter, then default is
+     * returned. The parameter chosen is marked "used" if it exists. Longs may
+     * be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    public long getLongWithDefault(Parameter parameter,
+        Parameter defaultParameter, long defaultValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getLongWithDefault(parameter, defaultValue);
+        else
+            return getLongWithDefault(defaultParameter, defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, which must be
+     * a long. If there is an error in parsing the parameter, then default is
+     * returned. The parameter chosen is marked "used" if it exists. Longs may
+     * be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    long getLongWithDefault(Parameter parameter, long defaultValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                return parseLong(get(parameter));
+                } 
+            catch (NumberFormatException e) 
+                {
+                return defaultValue;
+                }
+            } 
+        else
+            return defaultValue;
+        }
+
+    /**
+     * Searches down through databases to find a given parameter, whose value
+     * must be a long >= minValue and = < maxValue. If not, this method returns
+     * errValue, else it returns the parameter value. The parameter chosen is
+     * marked "used" if it exists. Longs may be in decimal or (if preceded with
+     * an X or x) in hexadecimal.
+     */
+    public long getLongWithMax(Parameter parameter,
+        Parameter defaultParameter, long minValue, long maxValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getLong(parameter, minValue, maxValue);
+        else
+            return getLong(defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Use getLongWithMax(...) instead. Searches down through databases to find
+     * a given parameter, whose value must be a long >= minValue and = <
+     * maxValue. If not, this method returns errValue, else it returns the
+     * parameter value. The parameter chosen is marked "used" if it exists.
+     * Longs may be in decimal or (if preceded with an X or x) in hexadecimal.
+     */
+    long getLongWithMax(Parameter parameter, long minValue, long maxValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            try
+                {
+                long i = parseLong(get(parameter));
+                if (i < minValue)
+                    return minValue - 1;
+                if (i > maxValue)
+                    return minValue - 1;
+                return i;
+                } 
+            catch (NumberFormatException e) 
+                {
+                return minValue - 1;
+                }
+            } 
+        else
+            return (minValue - 1);
+        }
+
+    /**
+     * Use getLongWithMax(...) instead. Searches down through databases to find
+     * a given parameter, whose value must be a long >= minValue and = <
+     * maxValue. If not, this method returns errValue, else it returns the
+     * parameter value. The parameter chosen is marked "used" if it exists.
+     * Longs may be in decimal or (if preceded with an X or x) in hexadecimal.
+     * 
+     * @deprecated
+     */
+    public long getLong(Parameter parameter, Parameter defaultParameter,
+        long minValue, long maxValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        return getLongWithMax(parameter, defaultParameter, minValue, maxValue);
+        }
+
+    /**
+     * Use getLongWithMax(...) instead. Searches down through databases to find
+     * a given parameter, whose value must be a long >= minValue and = <
+     * maxValue. If not, this method returns errValue, else it returns the
+     * parameter value. The parameter chosen is marked "used" if it exists.
+     * 
+     * @deprecated
+     */
+    long getLong(Parameter parameter, long minValue, long maxValue) 
+        {
+        return getLongWithMax(parameter, minValue, maxValue);
+        }
+
+    /**
+     * Searches down through the databases to find a given parameter, whose
+     * value must be an absolute or relative path name. If it is absolute, a
+     * File is made based on the path name. If it is relative, a file is made by
+     * resolving the path name with respect to the directory in which the file
+     * was which defined this ParameterDatabase in the ParameterDatabase
+     * hierarchy. If the parameter is not found, this returns null. The File is
+     * not checked for validity. The parameter chosen is marked "used" if it
+     * exists.
+     */
+
+    public File getFile(Parameter parameter, Parameter defaultParameter) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getFile(parameter);
+        else
+            return getFile(defaultParameter);
+        }
+
+    /**
+     * Searches down through the databases to find a given parameter, whose
+     * value must be an absolute or relative path name. If the parameter begins
+     * with a "$", a file is made based on the relative path name and returned
+     * directly. Otherwise, if it is absolute, a File is made based on the path
+     * name, or if it is relative, a file is made by resolving the path name
+     * with respect to the directory in which the file was which defined this
+     * ParameterDatabase in the ParameterDatabase hierarchy. If the parameter is
+     * not found, this returns null. The File is not checked for validity. The
+     * parameter chosen is marked "used" if it exists.
+     */
+
+    File getFile(Parameter parameter) 
+        {
+        if (_exists(parameter)) 
+            {
+            String p = get(parameter);
+            if (p == null)
+                return null;
+            if (p.startsWith(C_HERE))
+                return new File(p.substring(C_HERE.length()));
+            else {
+                File f = new File(p);
+                if (f.isAbsolute())
+                    return f;
+                else
+                    return new File(directoryFor(parameter), p);
+                }
+            } 
+        else
+            return null;
+        }
+
+    /**
+     * Searches down through databases to find a given parameter. Returns the
+     * parameter's value (trimmed) or null if not found or if the trimmed result
+     * is empty. The parameter chosen is marked "used" if it exists.
+     */
+
+    public synchronized String getString(Parameter parameter,
+        Parameter defaultParameter) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getString(parameter);
+        else
+            return getString(defaultParameter);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter. Returns the
+     * parameter's value (trimmed) or null if not found or if the trimmed result
+     * is empty. The parameter chosen is marked "used" if it exists.
+     */
+
+    /*protected*/ synchronized String getString(Parameter parameter) 
+        {
+        if (_exists(parameter))
+            return get(parameter);
+        else
+            return null;
+        }
+
+    /**
+     * Searches down through databases to find a given parameter. Returns the
+     * parameter's value trimmed of whitespace, or defaultValue.trim() if the
+     * result is not found or the trimmed result is empty.
+     */
+    public String getStringWithDefault(Parameter parameter,
+        Parameter defaultParameter, String defaultValue) 
+        {
+        printGotten(parameter, defaultParameter, false);
+        if (_exists(parameter))
+            return getStringWithDefault(parameter, defaultValue);
+        else
+            return getStringWithDefault(defaultParameter, defaultValue);
+        }
+
+    /**
+     * Searches down through databases to find a given parameter. Returns the
+     * parameter's value trimmed of whitespace, or defaultValue.trim() if the
+     * result is not found or the trimmed result is empty.
+     */
+    /*protected*/ String getStringWithDefault(Parameter parameter,
+        String defaultValue) 
+        {
+        if (_exists(parameter)) 
+            {
+            String result = get(parameter);
+            if (result == null) 
+                {
+                if (defaultValue == null)
+                    return null;
+                else
+                    result = defaultValue.trim();
+                } 
+            else {
+                result = result.trim();
+                if (result.length() == 0) 
+                    {
+                    if (defaultValue == null)
+                        return null;
+                    else
+                        result = defaultValue.trim();
+                    }
+                }
+            return result;
+            } 
+        else {
+            if (defaultValue == null)
+                return null;
+            else
+                return defaultValue.trim();
+            }
+        }
+
+    /** Clears the checked flag */
+    /*protected*/ synchronized void uncheck() 
+        {
+        if (!checked)
+            return; // we already unchecked this path -- this is dangerous if
+                    // parents are used without children
+        checked = false;
+        int size = parents.size();
+        for (int x = 0; x < size; x++)
+            ((ParameterDatabase) (parents.elementAt(x))).uncheck();
+        }
+    
+    /**
+     * Sets a parameter in the topmost database to a given value, trimmed of
+     * whitespace.
+     */
+    public synchronized void set(Parameter parameter, String value) 
+        {
+        String tmp = value.trim();
+        put(parameter.param, tmp);
+        // fireParameterSet(parameter, tmp);
+        }
+
+    /**
+     * Prints out all the parameters marked as used, plus their values. If a
+     * parameter was listed as "used" but not's actually in the database, the
+     * value printed is UNKNOWN_VALUE (set to "?????")
+     */
+
+    public synchronized void listGotten(PrintWriter p) 
+        {
+        Vector vec = new Vector();
+        Enumeration e = gotten.keys();
+        while (e.hasMoreElements())
+            vec.addElement(e.nextElement());
+
+        // sort the keys
+        Object[] array = new Object[vec.size()];
+        vec.copyInto(array);
+
+        java.util.Collections.sort(vec);
+
+        // Uncheck and print each item
+        for (int x = 0; x < array.length; x++) 
+            {
+            String s = (String) (array[x]);
+            String v = null;
+            if (s != null) 
+                {
+                v = (String) (_get(s));
+                uncheck();
+                }
+            if (v == null)
+                v = UNKNOWN_VALUE;
+            p.println(s + " = " + v);
+            }
+        p.flush();
+        }
+
+    /** Prints out all the parameters NOT marked as used, plus their values. */
+
+    public synchronized void listNotGotten(PrintWriter p) 
+        {
+        Vector vec = new Vector();
+
+        Hashtable all = new Hashtable();
+        _list(null, false, null, all); // grab all the nonshadowed keys
+        Enumeration e = gotten.keys();
+        while (e.hasMoreElements())
+            all.remove(e.nextElement());
+        e = all.keys();
+        while (e.hasMoreElements())
+            vec.addElement(e.nextElement());
+
+        // sort the keys
+        Object[] array = new Object[vec.size()];
+        vec.copyInto(array);
+
+        java.util.Collections.sort(vec);
+
+        // Uncheck and print each item
+        for (int x = 0; x < array.length; x++) 
+            {
+            String s = (String) (array[x]);
+            String v = null;
+            if (s != null) 
+                {
+                v = (String) (_get(s));
+                uncheck();
+                }
+            if (v == null)
+                v = UNKNOWN_VALUE;
+            p.println(s + " = " + v);
+            }
+        p.flush();
+        }
+
+    /** Prints out all the parameters NOT marked as used, plus their values. */
+
+    public synchronized void listNotAccessed(PrintWriter p) 
+        {
+        Vector vec = new Vector();
+
+        Hashtable all = new Hashtable();
+        _list(null, false, null, all); // grab all the nonshadowed keys
+        Enumeration e = accessed.keys();
+        while (e.hasMoreElements())
+            all.remove(e.nextElement());
+        e = all.keys();
+        while (e.hasMoreElements())
+            vec.addElement(e.nextElement());
+
+        // sort the keys
+        Object[] array = new Object[vec.size()];
+        vec.copyInto(array);
+
+        java.util.Collections.sort(vec);
+
+        // Uncheck and print each item
+        for (int x = 0; x < array.length; x++) 
+            {
+            String s = (String) (array[x]);
+            String v = null;
+            if (s != null) 
+                {
+                v = (String) (_get(s));
+                uncheck();
+                }
+            if (v == null)
+                v = UNKNOWN_VALUE;
+            p.println(s + " = " + v);
+            }
+        p.flush();
+        }
+
+    /**
+     * Prints out all the parameters marked as accessed ("gotten" by some
+     * getFoo(...) method), plus their values. If this method ever prints
+     * UNKNOWN_VALUE ("?????"), that's a bug.
+     */
+
+    public synchronized void listAccessed(PrintWriter p) 
+        {
+        Vector vec = new Vector();
+        Enumeration e = accessed.keys();
+        while (e.hasMoreElements())
+            vec.addElement(e.nextElement());
+
+        // sort the keys
+        Object[] array = new Object[vec.size()];
+        vec.copyInto(array);
+
+        java.util.Collections.sort(vec);
+
+        // Uncheck and print each item
+        for (int x = 0; x < array.length; x++) 
+            {
+            String s = (String) (array[x]);
+            String v = null;
+            if (s != null) 
+                {
+                v = (String) (_get(s));
+                uncheck();
+                }
+            if (v == null)
+                v = UNKNOWN_VALUE;
+            p.println(s + " = " + v);
+            }
+        p.flush();
+        }
+
+    /** Returns true if parameter exist in the database
+        @ deprecated use exists(Parameter, null) 
+    */
+    public synchronized boolean exists(Parameter parameter) 
+        {
+        printGotten(parameter, null, true);
+        return _exists(parameter);
+        }
+
+
+    /*protected*/ synchronized boolean _exists(Parameter parameter) 
+        {
+        if (parameter == null) return false;
+        String result = _get(parameter.param);
+        uncheck();
+        
+        accessed.put(parameter.param, Boolean.TRUE);
+        return (result != null);
+        }
+
+    /**
+     * Returns true if either parameter or defaultParameter exists in the
+     * database
+     */
+    public synchronized boolean exists(Parameter parameter,
+        Parameter defaultParameter) 
+        {
+        printGotten(parameter, defaultParameter, true);
+        if (exists(parameter))
+            return true;
+        if (exists(defaultParameter))
+            return true;
+        return false;
+        }
+
+
+/*
+  P: Successfully retrieved parameter
+  !P: Unsuccessfully retrieved parameter
+  <P: Would have retrieved parameter
+
+  E: Successfully tested for existence of parameter
+  !E: Unsuccessfully tested for existence of parameter
+  <E: Would have tested for exidstence of parameter
+*/
+
+    /*protected*/ void printGotten(Parameter parameter, Parameter defaultParameter, boolean exists)
+        {
+        if (printState == PS_UNKNOWN)
+            {
+            Parameter p = new Parameter(PRINT_PARAMS);
+            String jp = get(p);
+            // System.err.println(jp);
+            if (jp == null || jp.equalsIgnoreCase("false"))
+                printState = PS_NONE;
+            else
+                printState = PS_PRINT_PARAMS;
+            // System.err.println(printState);
+            uncheck();
+            printGotten(p,null,false);
+            }
+
+        if (printState == PS_PRINT_PARAMS)
+            {
+            String p = "P: ";
+            if (exists) p = "E: ";
+            
+            if (parameter==null && defaultParameter == null) 
+                return;
+                
+            else if (parameter == null)
+                {
+                String result = _get(defaultParameter.param);
+                uncheck();
+                if (result == null)
+                    // null parameter, didn't find defaultParameter
+                    System.err.println("\t!" + p +defaultParameter.param);
+                else 
+                    // null parameter, found defaultParameter
+                    System.err.println("\t " + p +defaultParameter.param + " = " + result);
+                }
+            
+            else if (defaultParameter == null)
+                {
+                String result = _get(parameter.param);
+                uncheck();
+                if (result == null)
+                    // null defaultParameter, didn't find parameter
+                    System.err.println("\t!" + p +parameter.param);
+                else 
+                    // null defaultParameter, found parameter
+                    System.err.println("\t " + p +parameter.param+ " = " + result);
+                }
+            
+            else
+                {
+                String result = _get(parameter.param);
+                uncheck();
+                if (result == null)
+                    {
+                    // didn't find parameter
+                    System.err.println("\t!" + p +parameter.param);
+                    result = _get(defaultParameter.param);
+                    uncheck();
+                    if (result == null)
+                        // didn't find defaultParameter
+                        System.err.println("\t!" + p +defaultParameter.param);
+                    else 
+                        // found defaultParameter
+                        System.err.println("\t " + p +defaultParameter.param+ " = " + result);
+                    }
+                else 
+                    {
+                    // found parameter
+                    System.err.println("\t " + p +parameter.param+ " = " + result);
+                    System.err.println("\t<" + p +defaultParameter.param);
+                    }
+                }
+            }
+        }
+
+    /*protected*/ synchronized String get(Parameter parameter) 
+        {
+        String result = _get(parameter.param);
+        uncheck();
+
+        // set hashtable appropriately
+        if (parameter != null)
+            accessed.put(parameter.param, Boolean.TRUE);
+        if (parameter != null)
+            gotten.put(parameter.param, Boolean.TRUE);
+        return result;
+        }
+
+    /** Private helper function */
+    synchronized String _get(String parameter) 
+        {
+        if (parameter == null)
+            {
+            return null;
+            }
+        if (checked)
+            return null; // we already searched this path
+        checked = true;
+        String result = getProperty(parameter);
+        if (result == null) 
+            {
+            int size = parents.size();
+            for (int x = 0; x < size; x++) 
+                {
+                result = ((ParameterDatabase) (parents.elementAt(x)))._get(parameter);
+                if (result != null)
+                    {
+                    return result;
+                    }
+                }
+            } 
+        else  // preprocess
+            {
+            result = result.trim();
+            if (result.length() == 0)
+                result = null;
+            }
+        return result;
+        }
+
+    /*protected*/ Set _getShadowedValues(Parameter parameter, Set vals) 
+        {
+        if (parameter == null) 
+            {
+            return vals;
+            }
+        
+        if (checked) 
+            {
+            return vals;
+            }
+        
+        checked = true;
+        String result = getProperty(parameter.param);
+        if (result != null) 
+            {
+            result = result.trim();
+            if (result.length() != 0)
+                vals.add(result);
+            }
+        
+        int size = parents.size();
+        for (int i = 0; i < size; ++i) 
+            {
+            ((ParameterDatabase)parents.elementAt(i))._getShadowedValues(parameter,vals);
+            }
+
+        return vals;
+        }
+
+    public Set getShadowedValues(Parameter parameter) 
+        {
+        Set vals = new HashSet();
+        vals = _getShadowedValues(parameter, vals);
+        uncheck();
+        return vals;
+        }
+    
+    /**
+     * Searches down through databases to find the directory for the database
+     * which holds a given parameter. Returns the directory name or null if not
+     * found.
+     */
+
+    public File directoryFor(Parameter parameter) 
+        {
+        File result = _directoryFor(parameter);
+        uncheck();
+        return result;
+        }
+    
+    /** Private helper function */
+    synchronized File _directoryFor(Parameter parameter) 
+        {
+        if (checked)
+            return null; // we already searched this path
+        checked = true;
+        File result = null;
+        String p = getProperty(parameter.param);
+        if (p == null) 
+            {
+            int size = parents.size();
+            for (int x = 0; x < size; x++) 
+                {
+                result = ((ParameterDatabase) (parents.elementAt(x)))
+                    ._directoryFor(parameter);
+                if (result != null)
+                    return result;
+                }
+            return result;
+            } 
+        else
+            return directory;
+        }
+    
+    /** Returns a String describing the location of the ParameterDatabase holding
+        this parameter, or "" if there is none. */
+    public String getLocation(Parameter parameter)
+        {
+        File file = fileFor(parameter);
+        if (file == null) return "";
+        try { return file.getCanonicalPath(); }
+        catch (IOException e) { return ""; }
+        }
+        
+    /**
+     * Searches down through databases to find the parameter file 
+     * which holds a given parameter. Returns the filename or null if not
+     * found.
+     *
+     * @deprecated You probably want to use getLocation
+     */
+
+    public File fileFor(Parameter parameter) 
+        {
+        File result = _fileFor(parameter);
+        uncheck();
+        return result;
+        }
+
+    synchronized File _fileFor(Parameter parameter) 
+        {
+        if (checked)
+            return null;
+        
+        checked = true;
+        File result = null;
+        String p = getProperty(parameter.param);
+        if (p==null) 
+            {
+            int size = parents.size();
+            for(int i = 0; i < size; ++i) 
+                {
+                result = ((ParameterDatabase)parents.elementAt(i))._fileFor(parameter);
+                if (result != null)
+                    return result;
+                }
+            return result;
+            }
+        else
+            return new File(directory,filename);
+        }
+
+    /** Removes a parameter from the topmost database. */
+    public synchronized void remove(Parameter parameter) 
+        {
+        if (parameter.param.equals(PRINT_PARAMS)) printState = PS_UNKNOWN;
+        remove(parameter.param);
+        }
+
+    /** Removes a parameter from the database and all its parent databases. */
+    public synchronized void removeDeeply(Parameter parameter) 
+        {
+        _removeDeeply(parameter);
+        uncheck();
+        }
+
+    /** Private helper function */
+    synchronized void _removeDeeply(Parameter parameter) 
+        {
+        if (checked)
+            return; // already removed from this path
+        checked = true;
+        remove(parameter);
+        int size = parents.size();
+        for (int x = 0; x < size; x++)
+            ((ParameterDatabase) (parents.elementAt(x)))
+                .removeDeeply(parameter);
+        }
+
+    public void addParent(ParameterDatabase database)
+        {
+        parents.addElement(database);
+        }
+
+    /** Creates an empty parameter database. */
+    public ParameterDatabase() 
+        {
+        super();
+        accessed = new Hashtable();
+        gotten = new Hashtable();
+        directory = new File(new File("").getAbsolutePath()); // uses the user
+                                                              // path
+        filename = "";
+        parents = new Vector();
+        checked = false; // unnecessary
+        listeners = new Vector();
+        }
+    
+    /** Creates a new parameter database from the given Dictionary.  
+        Both the keys and values will be run through toString() before adding to the dataase.   
+        Keys are parameters.  Values are the values of the parameters.  
+        Beware that a ParameterDatabase is itself a Dictionary; but if you pass one in here you 
+        will only get the lowest-level elements.  If parent.n are defined, parents will 
+        be attempted to be loaded -- that's the reason for the FileNotFoundException and IOException.  */
+    public ParameterDatabase(java.util.Dictionary map) throws FileNotFoundException, IOException 
+        {
+        this();
+        java.util.Enumeration keys = map.keys();
+        while(keys.hasMoreElements())
+            {
+            Object obj = keys.nextElement();
+            set(new Parameter(""+obj),""+map.get(obj));
+            }
+
+        // load parents
+        for (int x = 0;; x++) 
+            {
+            String s = getProperty("parent." + x);
+            if (s == null)
+                return; // we're done
+
+            if (new File(s).isAbsolute()) // it's an absolute file definition
+                parents.addElement(new ParameterDatabase(new File(s)));
+            else throw new FileNotFoundException("Attempt to load a relative file, but there's no parent file: " + s);
+            }
+        }
+
+    /** Creates a new parameter database loaded from the given string describing a file in a jar,
+        in the context of a resource location (a class).
+        This approach uses resourceLocation.getResourceAsStream() to load the parameter file.
+        If parent.n are defined, parents will be attempted to be loaded -- that's 
+        the reason for the FileNotFoundException and IOException. */
+
+    public ParameterDatabase(String pathNameInJar, Class jarResourceLocation) throws FileNotFoundException, IOException 
+        {
+        this();
+        load(jarResourceLocation.getResourceAsStream(pathNameInJar));
+
+        listeners = new Vector();
+
+        // load parents
+        for (int x = 0;; x++) 
+            {
+            String s = getProperty("parent." + x);
+            if (s == null)
+                return; // we're done
+
+            String path = new File(new File(pathNameInJar).getParent(), s).toString();
+
+            parents.addElement(new ParameterDatabase(path, jarResourceLocation));
+            }
+        }
+
+
+    /** Creates a new parameter database loaded from the given stream.  Non-relative parents are not permitted.
+        If parent.n are defined, parents will be attempted to be loaded -- that's 
+        the reason for the FileNotFoundException and IOException. */
+
+    public ParameterDatabase(java.io.InputStream stream) throws FileNotFoundException, IOException 
+        {
+        this();
+        load(stream);
+
+        listeners = new Vector();
+
+        // load parents
+        for (int x = 0;; x++) 
+            {
+            String s = getProperty("parent." + x);
+            if (s == null)
+                return; // we're done
+
+            if (new File(s).isAbsolute()) // it's an absolute file definition
+                parents.addElement(new ParameterDatabase(new File(s)));
+            else throw new FileNotFoundException("Attempt to load a relative file, but there's no parent file: " + s);
+            }
+        }
+
+
+    /**
+     * Creates a new parameter database tree from a given database file and its
+     * parent files.
+     */
+    public ParameterDatabase(File filename)
+        throws FileNotFoundException, IOException 
+        {
+        this();
+        this.filename = filename.getName();
+        directory = new File(filename.getParent()); // get the directory
+                                                    // filename is in
+        load(new FileInputStream(filename));
+
+        listeners = new Vector();
+
+        // load parents
+        for (int x = 0;; x++) 
+            {
+            String s = getProperty("parent." + x);
+            if (s == null)
+                return; // we're done
+
+            if (new File(s).isAbsolute()) // it's an absolute file definition
+                parents.addElement(new ParameterDatabase(new File(s)));
+            else
+                // it's relative to my path
+                parents.addElement(new ParameterDatabase(new File(filename
+                            .getParent(), s)));
+            }
+        }
+
+    /**
+     * Creates a new parameter database from a given database file and argv
+     * list. The top-level database is completely empty, pointing to a second
+     * database which contains the parameter entries stored in args, which
+     * points to a tree of databases constructed using
+     * ParameterDatabase(filename).
+     */
+
+    public ParameterDatabase(File filename, String[] args)
+        throws FileNotFoundException, IOException 
+        {
+        this();
+        this.filename = filename.getName();
+        directory = new File(filename.getParent()); // get the directory
+                                                    // filename is in
+
+        // Create the Parameter Database tree for the files
+        ParameterDatabase files = new ParameterDatabase(filename);
+
+        // Create the Parameter Database for the arguments
+        ParameterDatabase a = new ParameterDatabase();
+        a.parents.addElement(files);
+        for (int x = 0; x < args.length - 1; x++) 
+            {
+            if (args[x].equals("-p"))
+                {
+                String s = args[x+1].trim();
+                if (s.length() == 0) continue;  // failure
+                int eq = s.indexOf('=');  // look for the '='
+                if (eq <= 0) continue; // '=' isn't there, or it's the first char: failure                      
+                put(s.substring(0,eq), s.substring(eq+1));  // add the parameter
+                }
+            }
+
+        // Set me up
+        parents.addElement(a);
+        listeners = new Vector();
+        }
+
+    /**
+     * Prints out all the parameters in the database. Useful for debugging. If
+     * listShadowed is true, each parameter is printed with the parameter
+     * database it's located in. If listShadowed is false, only active
+     * parameters are listed, and they're all given in one big chunk.
+     */
+    //public void list(PrintStream p, boolean listShadowed) 
+    //    {
+    //     list(new PrintWriter(p), listShadowed);
+    //    }
+
+    /**
+     * Prints out all the parameters in the database, but not shadowed
+     * parameters.
+     */
+    // public void list(PrintStream p) 
+    //     {
+    //     list(new PrintWriter(p), false);
+    //     }
+
+    /**
+     * Prints out all the parameters in the database, but not shadowed
+     * parameters.
+     */
+    public void list(PrintWriter p) 
+        {
+        list(p, false);
+        }
+
+    /**
+     * Prints out all the parameters in the database. Useful for debugging. If
+     * listShadowed is true, each parameter is printed with the parameter
+     * database it's located in. If listShadowed is false, only active
+     * parameters are listed, and they're all given in one big chunk.
+     */
+    public void list(PrintWriter p, boolean listShadowed) 
+        {
+        if (listShadowed)
+            _list(p, listShadowed, "root", null);
+        else {
+            Hashtable gather = new Hashtable();
+            _list(null, listShadowed, "root", gather);
+
+            Vector vec = new Vector();
+            Enumeration e = gather.keys();
+            while (e.hasMoreElements())
+                vec.addElement(e.nextElement());
+
+            // sort the keys
+//            Object[] array = new Object[vec.size()];
+//            vec.copyInto(array);
+//
+            java.util.Collections.sort(vec);
+
+            // Uncheck and print each item
+            for (int x = 0; x < /* array.length;*/ vec.size(); x++) 
+                {
+                String s = (String) /* (array[x]); */ vec.get(x);
+                String v = null;
+                if (s != null)
+                    v = (String) gather.get(s);
+                if (v == null)
+                    v = UNKNOWN_VALUE;
+                if (p!=null) p.println(s + " = " + v);
+                }
+            }
+        if (p!=null) p.flush();
+        }
+
+    /** Private helper function. */
+    void _list(PrintWriter p, boolean listShadowed,
+        String prefix, Hashtable gather) 
+        {
+        if (listShadowed) 
+            {
+            // Print out my header
+            if (p!=null) p.println("\n########" + prefix);
+            super.list(p);
+            int size = parents.size();
+            for (int x = 0; x < size; x++)
+                ((ParameterDatabase) (parents.elementAt(x)))._list(p,
+                    listShadowed, prefix + "." + x, gather);
+            } 
+        else {
+            // load in reverse order so things get properly overwritten
+            int size = parents.size();
+            for (int x = size - 1; x >= 0; x--)
+                ((ParameterDatabase) (parents.elementAt(x)))._list(p,
+                    listShadowed, prefix, gather);
+            Enumeration e = keys();
+            while (e.hasMoreElements()) 
+                {
+                String key = (String) (e.nextElement());
+                gather.put(key, get(key));
+                }
+            }
+        if (p!=null) p.flush();
+        }
+
+    public String toString() 
+        {
+        String s = super.toString();
+        if (parents.size() > 0) 
+            {
+            s += " : (";
+            for (int x = 0; x < parents.size(); x++) 
+                {
+                if (x > 0)
+                    s += ", ";
+                s += parents.elementAt(x);
+                }
+            s += ")";
+            }
+        return s;
+        }
+
+    /**
+     * Builds a TreeModel from the available property keys.   
+     * @return
+     */
+    public TreeModel buildTreeModel() 
+        {
+        String sep = System.getProperty("file.separator");
+        ParameterDatabaseTreeNode root = new ParameterDatabaseTreeNode(
+            this.directory.getAbsolutePath() + sep + this.filename);
+        ParameterDatabaseTreeModel model = new ParameterDatabaseTreeModel(root);
+
+        _buildTreeModel(model, root);
+
+        model.sort(root, new Comparator() 
+            {
+            public int compare(Object o1, Object o2) 
+                {
+                ParameterDatabaseTreeNode t1 = (ParameterDatabaseTreeNode)o1;
+                ParameterDatabaseTreeNode t2 = (ParameterDatabaseTreeNode)o2;
+                
+                return ((Comparable)t1.getUserObject()).compareTo(t2.getUserObject());
+                }
+            });
+
+        // In order to add elements to the tree model, the leaves need to be
+        // visible. This is because some properties have values *and* sub-
+        // properties. Otherwise, if the nodes representing these properties did
+        // not yet have children, then they would be invisible and the tree model
+        // would be unable to add child nodes to them.
+        model.setVisibleLeaves(false);
+        
+//        addListener(new ParameterDatabaseAdapter() {
+//           public void parameterSet(ParameterDatabaseEvent evt) {
+//               model.setVisibleLeaves(true);
+//               _addNodeForParameter(model, root, evt.getParameter().param);
+//               model.setVisibleLeaves(false);
+//           }
+//        });
+
+        return model;
+        }
+
+    void _buildTreeModel(DefaultTreeModel model,
+        DefaultMutableTreeNode root) 
+        {
+        Enumeration e = keys();
+        while (e.hasMoreElements()) 
+            {
+            _addNodeForParameter(model, root, (String)e.nextElement());
+            }
+
+        int size = parents.size();
+        for (int i = 0; i < size; ++i) 
+            {
+            ParameterDatabase parentDB = (ParameterDatabase) parents
+                .elementAt(i);
+            parentDB._buildTreeModel(model, root);
+            }
+        }
+
+    /**
+     * @param model
+     * @param root
+     * @param e
+     */
+    void _addNodeForParameter(DefaultTreeModel model, DefaultMutableTreeNode root, String key) 
+        {
+        if (key.indexOf("parent.") == -1) 
+            {
+            /* 
+             * TODO split is new to 1.4.  To maintain 1.2 compatability we need
+             * to use a different approach.  Just use a string tokenizer.
+             */ 
+            StringTokenizer tok = new StringTokenizer(key,".");
+            String[] path = new String[tok.countTokens()];
+            int t = 0;
+            while(tok.hasMoreTokens()) 
+                {
+                path[t++] = tok.nextToken();
+                }
+            DefaultMutableTreeNode parent = root;
+
+            for (int i = 0; i < path.length; ++i) 
+                {
+                int children = model.getChildCount(parent);
+                if (children > 0) 
+                    {
+                    int c = 0;
+                    for (; c < children; ++c) 
+                        {
+                        DefaultMutableTreeNode child = 
+                            (DefaultMutableTreeNode) parent.getChildAt(c);
+                        if (child.getUserObject().equals(path[i])) 
+                            {
+                            parent = child;
+                            break;
+                            }
+                        }
+
+                    if (c == children) 
+                        {
+                        DefaultMutableTreeNode child = 
+                            new ParameterDatabaseTreeNode(path[i]);
+                        model.insertNodeInto(child, parent, 
+                            parent.getChildCount());
+                        parent = child;
+                        }
+                    }
+                // If the parent has no children, just add the node.
+                else {
+                    DefaultMutableTreeNode child = 
+                        new ParameterDatabaseTreeNode(path[i]);
+                    model.insertNodeInto(child, parent, 0);
+                    parent = child;
+                    }
+                }
+            }
+        }
+    
+    /** Test the ParameterDatabase */
+    public static void main(String[] args)
+        throws FileNotFoundException, IOException 
+        {
+        ParameterDatabase pd = new ParameterDatabase(new File(args[0]), args);
+        pd.set(new Parameter("Hi there"), "Whatever");
+        pd.set(new Parameter(new String[] { "1", "2", "3" }), " Whatever ");
+        pd.set(new Parameter(new String[] { "a", "b", "c" }).pop().push("d"),
+            "Whatever");
+
+        System.err.println("\n\n PRINTING ALL PARAMETERS \n\n");
+        pd.list(new PrintWriter(System.err, true), true);
+        System.err.println("\n\n PRINTING ONLY VALID PARAMETERS \n\n");
+        pd.list(new PrintWriter(System.err, true), false);
+        }
+
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseEvent.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseEvent.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseEvent.java	(revision 6152)
@@ -0,0 +1,65 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 9, 2005 8:36:42 AM
+ * 
+ * By: spaus
+ */
+package ec.util;
+
+import java.util.EventObject;
+
+/**
+ * @author spaus
+ */
+public class ParameterDatabaseEvent
+    extends EventObject {
+
+    public static final int SET = 0;
+    public static final int ACCESSED = 1;
+    
+    private final Parameter parameter;
+    private final String value;
+    private final int type;
+
+    /**
+     * For ParameterDatabase events.
+     * 
+     * @param source the ParameterDatabase
+     * @param parameter the Parameter associated with the event
+     * @param value the value of the Parameter associated with the event
+     * @param type the type of the event
+     */
+    public ParameterDatabaseEvent(Object source, Parameter parameter, String value, int type) {
+        super(source);
+        this.parameter = parameter;
+        this.value = value;
+        this.type = type;
+        }
+    
+    /**
+     * @return the Parameter associated with the event
+     */
+    public Parameter getParameter() {
+        return parameter;
+        }
+    
+    /**
+     * @return the value of the Parameter associated with the event.
+     */
+    public String getValue() {
+        return value;
+        }
+    
+    /**
+     * @return the type of the event.
+     */
+    public int getType() {
+        return type;
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseTreeModel.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseTreeModel.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseTreeModel.java	(revision 6152)
@@ -0,0 +1,92 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 6, 2005 7:12:32 PM
+ * 
+ * By: spaus
+ */
+package ec.util;
+
+import java.util.Comparator;
+
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+
+/**
+ * @author spaus
+ */
+public class ParameterDatabaseTreeModel
+    extends DefaultTreeModel {
+
+    private boolean visibleLeaves;
+    
+    /**
+     * @param root
+     */
+    public ParameterDatabaseTreeModel(TreeNode root) {
+        super(root);
+        visibleLeaves = true;
+        }
+
+    /**
+     * @param root
+     * @param asksAllowsChildren
+     */
+    public ParameterDatabaseTreeModel(TreeNode root, boolean asksAllowsChildren) {
+        super(root, asksAllowsChildren);
+        visibleLeaves = true;
+        }
+
+    /**
+     * @param visibleLeaves
+     */
+    public void setVisibleLeaves(boolean visibleLeaves) {
+        this.visibleLeaves = visibleLeaves;
+        }
+    
+    /**
+     * @return
+     */
+    public boolean getVisibleLeaves() {
+        return visibleLeaves;
+        }
+    
+    /* (non-Javadoc)
+     * @see javax.swing.tree.TreeModel#getChild(java.lang.Object, int)
+     */
+    public Object getChild(Object parent, int index) {
+        if (!visibleLeaves) {
+            if (parent instanceof ParameterDatabaseTreeNode) {
+                return ((ParameterDatabaseTreeNode)parent).getChildAt(index,visibleLeaves);
+                }
+            }
+        
+        return ((TreeNode)parent).getChildAt(index);
+        }
+    
+    /* (non-Javadoc)
+     * @see javax.swing.tree.TreeModel#getChildCount(java.lang.Object)
+     */
+    public int getChildCount(Object parent) {
+        if (!visibleLeaves) {
+            if (parent instanceof ParameterDatabaseTreeNode) {
+                return ((ParameterDatabaseTreeNode)parent).getChildCount(visibleLeaves);
+                }
+            }
+        
+        return ((TreeNode)parent).getChildCount();
+        }
+    
+    /**
+     * @param parent
+     * @param comp
+     */
+    public void sort(Object parent, Comparator comp) {
+        ((ParameterDatabaseTreeNode)parent).sort(comp);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseTreeNode.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseTreeNode.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/ParameterDatabaseTreeNode.java	(revision 6152)
@@ -0,0 +1,125 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+/*
+ * Created on Apr 5, 2005 8:24:19 PM
+ * 
+ * By: spaus
+ */
+package ec.util;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeNode;
+
+/**
+ * @author spaus
+ */
+class ParameterDatabaseTreeNode
+    extends DefaultMutableTreeNode
+    implements Comparable {
+
+    /**
+     * 
+     */
+    public ParameterDatabaseTreeNode() {
+        super();
+        }
+
+    /**
+     * @param userObject
+     */
+    public ParameterDatabaseTreeNode(Object userObject) {
+        super(userObject);
+        }
+
+    /**
+     * @param userObject
+     * @param allowsChildren
+     */
+    public ParameterDatabaseTreeNode(Object userObject, boolean allowsChildren) {
+        super(userObject, allowsChildren);
+        }
+    
+    /**
+     * @param index
+     * @param visibleLeaves
+     * @return
+     */
+    public Object getChildAt(int index, boolean visibleLeaves) {
+        if (children == null) {
+            throw new ArrayIndexOutOfBoundsException("node has no children");
+            }
+
+        if (!visibleLeaves) {
+            int nonLeafIndex = -1;
+            Enumeration e = children.elements();
+            while (e.hasMoreElements()) {
+                TreeNode n = (TreeNode)e.nextElement();
+                if (!n.isLeaf()) {
+                    if (++nonLeafIndex == index)
+                        return n;
+                    }
+                }
+            
+            throw new ArrayIndexOutOfBoundsException("index = "+index+", children = "+getChildCount(visibleLeaves));
+            }
+        
+        return super.getChildAt(index);
+        }
+    
+    /**
+     * @param visibleLeaves
+     * @return
+     */
+    public int getChildCount(boolean visibleLeaves) {
+        if (!visibleLeaves) {
+            int nonLeafCount = 0;
+            Enumeration e = children.elements();
+            while (e.hasMoreElements()) {
+                TreeNode n = (TreeNode)e.nextElement();
+                if (!n.isLeaf()) ++nonLeafCount;
+                }
+            
+            return nonLeafCount;
+            }
+        
+        return super.getChildCount();
+        }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo(Object o) {
+        ParameterDatabaseTreeNode n = (ParameterDatabaseTreeNode)o;
+
+        return ((Comparable)userObject).compareTo(n.userObject);
+        }
+    
+    /**
+     * @param comp
+     */
+    public void sort(Comparator comp) {
+        if (children == null) 
+            return;
+        
+        Object[] childArr = children.toArray();
+        Arrays.sort(childArr, comp);
+        children = new Vector(Arrays.asList(childArr));
+        
+        Enumeration e = children.elements();
+        while (e.hasMoreElements()) {
+            ParameterDatabaseTreeNode n = 
+                (ParameterDatabaseTreeNode)e.nextElement();
+            n.sort(comp);
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/QuickSort.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/QuickSort.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/QuickSort.java	(revision 6152)
@@ -0,0 +1,843 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * QuickSort.java
+ * 
+ * Created: Wed Nov  3 14:54:24 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Implementations of various center-pivot QuickSort routines in Java,
+ * and (if you really want 'em) Insertion Sort routines as well.  This code
+ * is derived from the QuickSort example in the <a href="ftp://ftp.prenhall.com/pub/esm/computer_science.s-041/shaffer/ds/code/JAVA/code/javacode.zip">
+ * source code </a> accompanying <i>A Practical Introduction to Data Structures 
+ * and Algorithm Analysis, Java Edition</i>, by Clifford Shaffer.
+ * Here's the original header:
+ *
+ * <p>
+ * Source code example for "A Practical Introduction
+ * to Data Structures and Algorithm Analysis"
+ * by Clifford A. Shaffer, Prentice Hall, 1998.
+ * Copyright 1998 by Clifford A. Shaffer
+ *
+ * <p>Sorting main function for testing correctness of sort algorithm.
+ * To use: <sortname> [+/-] <size_of_array> <threshold>
+ *  + means increasing values, - means decreasing value and no
+ *    parameter means random values;
+ * where <size_of_array> controls the number of objects to be sorted;
+ * and <threshold> controls the threshold parameter for certain sorts, e.g.,
+ *   cutoff point for quicksort sublists.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+
+
+
+
+public class QuickSort 
+    {
+    static final int THRESHOLD = 0;  // might want to tweak this
+    static final int MAXSTACKSIZE = 1000;
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(byte[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(byte[] array) 
+        {
+        byte tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(byte[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        byte pivot;
+        int pivotindex, l, r;
+        byte tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(short[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(short[] array) 
+        {
+        short tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(short[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        short pivot;
+        int pivotindex, l, r;
+        short tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(char[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(char[] array) 
+        {
+        char tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(char[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+
+        int top = -1;
+        char pivot;
+        int pivotindex, l, r;
+        char tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(int[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(int[] array) 
+        {
+        int tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(int[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        int pivot;
+        int pivotindex, l, r;
+        int tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(long[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(long[] array) 
+        {
+        long tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(long[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+
+        int top = -1;
+        long pivot;
+        int pivotindex, l, r;
+        long tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(float[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(float[] array) 
+        {
+        float tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(float[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+
+        int top = -1;
+        float pivot;
+        int pivotindex, l, r;
+        float tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(double[] array) 
+        {
+        qsort_h(array, 0, array.length-1);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(double[] array) 
+        {
+        double tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (array[j]<array[j-1]); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(double[] array, int oi, int oj) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        double pivot;
+        int pivotindex, l, r;
+        double tmp;
+
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+      
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (array[++l] < pivot);
+                while ((r!=0) && (array[--r] > pivot));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array);             // Final Insertion Sort
+        }
+
+
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(Object[] array, SortComparator comp) 
+        {
+        qsort_h(array, 0, array.length-1, comp);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(Object[] array, SortComparator comp) 
+        {
+        Object tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (comp.lt(array[j],array[j-1])); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(Object[] array, int oi, int oj, SortComparator comp) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        Object pivot;
+        int pivotindex, l, r;
+        Object tmp;
+        
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+        
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+            
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (comp.lt(array[++l],pivot));
+                while ((r!=0) && (comp.gt(array[--r],pivot)));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array,comp);             // Final Insertion Sort
+        }
+
+
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(long[] array, SortComparatorL comp) 
+        {
+        qsort_h(array, 0, array.length-1, comp);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(long[] array, SortComparatorL comp) 
+        {
+        long tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (comp.lt(array[j],array[j-1])); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(long[] array, int oi, int oj, SortComparatorL comp) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        long pivot;
+        int pivotindex, l, r;
+        long tmp;
+        
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+        
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+            
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (comp.lt(array[++l],pivot));
+                while ((r!=0) && (comp.gt(array[--r],pivot)));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array,comp);             // Final Insertion Sort
+        }
+
+
+    /** Non-Recursive QuickSort */
+    static public void qsort(int[] array, SortComparatorL comp) 
+        {
+        qsort_h(array, 0, array.length-1, comp);
+        }
+    
+    
+    
+    /** Insertion Sort */
+    static public void inssort(int[] array, SortComparatorL comp)
+        {
+        int tmp;
+
+        for (int i=1; i<array.length; i++) // Insert i'th record
+            for (int j=i; (j>0) && (comp.lt(array[j],array[j-1])); j--)
+                //DSutil.swap(array, j, j-1);
+                { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; }
+        }
+    
+    static private void qsort_h(int[] array, int oi, int oj, SortComparatorL comp) 
+        {
+        int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+        int top = -1;
+        int pivot;
+        int pivotindex, l, r;
+        int tmp;
+        
+        stack[++top] = oi;  // Initialize stack
+        stack[++top] = oj;
+        
+        while (top > 0)    // While there are unprocessed subarrays
+            {
+            // Pop stack
+            int j = stack[top--];
+            int i = stack[top--];
+            
+            // Findpivot
+            pivotindex = (i+j)/2;
+            pivot = array[pivotindex];
+            //DSutil.swap(array, pivotindex, j); // Stick pivot at end
+            tmp = array[pivotindex]; array[pivotindex] = array[j]; array[j] = tmp; 
+            // Partition
+            l = i-1;
+            r = j;
+            do 
+                {
+                while (comp.lt(array[++l],pivot));
+                while ((r!=0) && (comp.gt(array[--r],pivot)));
+                //DSutil.swap(array, l, r);
+                tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+                } while (l < r);
+            //DSutil.swap(array, l, r);  // Undo final swap
+            tmp = array[l]; array[l] = array[r]; array[r] = tmp;
+            //DSutil.swap(array, l, j);  // Put pivot value in place
+            tmp = array[l]; array[l] = array[j]; array[j] = tmp;
+            
+            // Put new subarrays onto stack if they are small
+            if ((l-i) > THRESHOLD)   // Left partition
+                { 
+                stack[++top] = i;
+                stack[++top] = l-1;
+                }
+            if ((j-l) > THRESHOLD) // Right partition 
+                {   
+                stack[++top] = l+1;
+                stack[++top] = j;
+                }
+            }
+        inssort(array,comp);             // Final Insertion Sort
+        }
+    }
+    
+
+
+/* The original code
+   
+// Non-Recursive QuickSort
+static public void qsort(Elem[] array) 
+{
+qsort(array, 0, array.length-1);
+}
+   
+static public int MAXSTACKSIZE = 1000;
+   
+// Insertion Sort
+static void inssort(Elem[] array) 
+{
+Elem tmp;
+   
+for (int i=1; i<array.length; i++) // Insert i'th record
+for (int j=i; (j>0) && (array[j].key()<array[j-1].key()); j--)
+DSUtil.swap(array, j, j-1);
+}
+   
+static private void qsort_h(Elem[] array, int oi, int oj) 
+{
+int[] stack = new int[MAXSTACKSIZE]; // Stack for array bounds
+int listsize = oj-oi+1;
+int top = -1;
+int pivot;
+int pivotindex, l, r;
+Elem tmp;
+   
+stack[++top] = oi;  // Initialize stack
+stack[++top] = oj;
+   
+while (top > 0)    // While there are unprocessed subarrays
+{
+// Pop stack
+int j = stack[top--];
+int i = stack[top--];
+   
+// Findpivot
+pivotindex = (i+j)/2;
+pivot = array[pivotindex].key();
+DSUtil.swap(array, pivotindex, j); // Stick pivot at end
+// Partition
+l = i-1;
+r = j;
+do 
+{
+while (array[++l].key() < pivot);
+while ((r!=0) && (array[--r].key() > pivot));
+DSutil.swap(array, l, r);
+} while (l < r);
+DSUtil.swap(array, l, r);  // Undo final swap
+DSUtil.swap(array, l, j);  // Put pivot value in place
+   
+// Put new subarrays onto stack if they are small
+if ((l-i) > THRESHOLD)   // Left partition
+{ 
+stack[++top] = i;
+stack[++top] = l-1;
+}
+if ((j-l) > THRESHOLD) // Right partition 
+{   
+stack[++top] = l+1;
+stack[++top] = j;
+}
+}
+inssort(array);             // Final Insertion Sort
+}
+*/
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/README	(revision 6152)
@@ -0,0 +1,191 @@
+This package contains auxillary utility classes and functions used by ECJ, but
+which can easily be used by other Java libraries and are not specific to ECJ.
+
+
+LOGGING FACILITY
+----------------
+
+When ECJ was first developed (in 1998) there was no Java logging facility, no
+log4j, etc.  So I rolled my own, largely a copy of the one in lil-gp.  The 
+facility has proven fairly robust, so we've kept it over the years.  The
+facility has a basic class:
+
+	ec.util.Output
+
+... which does most of the logging work.  Output holds one or more *logs*,
+defined by
+
+	ec.util.Log
+
+... which are largely (but not required to be) wrappers around streams to
+standard out, standard err, or various files.  Output then allows you to print
+to these logs, or to issue "announcements" to them.  An announcement is 
+different from an ordinary print statement in that it is also stored in memory 
+permanently, and so gets checkpointed.  When a log is restarted from 
+checkpoint, all of its announcements can be reissued to the log; that's how 
+ECJ prints all of its stuff out to the terminal again when restarting from 
+checkpoint.  Beware that because announcements are stored in memory as well as
+printed out, if you issue too many of them, you'll fill up memory excessively.
+Announcements are all subclasses 
+
+	ec.util.Announcement
+
+Logs restart themselves from checkpoint using a small class:
+
+	ec.util.LogRestarter
+
+When output generates exceptions, usually pertaining to writing to Logs, it
+does so with an OutputException
+
+	ec.util.OutputExcption
+
+
+
+RANDOM NUMBER GENERATORS
+------------------------
+
+ECJ's random number generator is a Java implementation of the Mersenne Twister
+random number generator which I wrote in 1998.  It's still a popular
+implementation of the Mersenne Twister algorithm, largely because it's quite
+fast.  ECJ has two versions of the algorithm but only uses one:
+MersenneTwisterFast:
+
+	ec.util.MersenneTwister
+	
+	A drop-in subclass replacement for java.util.Random which uses the
+	Mersenne Twister algorithm instead.
+
+	ec.util.MersenneTwisterFast
+
+	Algorithmically identical to ec.util.MersenneTwister, but without
+	synchronization, and with a lot of hard-code-inlined methods.  As
+	a result much harder to read and understand, but over twice as fast.
+
+
+PARAMETER DATABASE	
+------------------
+
+ECJ's parameter database facility was also built from scratch at a time when
+Java had no other built-in facilities available.  The parameter database is
+built on top of Java's Properties class, but adds the additional functionality
+of multiple files with inheritance, plus command-line properties and dynamic
+properties.  The primary class is
+
+	ec.util.ParameterDatabase
+
+... which loads properties from various files and stores them internally for
+you to query at runtime.  To query for a property, you create a Parameter
+(a wrapper for String, used instead of String for entirely historical reasons).
+You then issue the Parameter to the ParameterDatabase and get the corresponding
+value.  Parameters are defined with:
+
+	ec.util.Parameter
+
+When there is an exception upon creating a Parameter, a BadParameterException
+is thrown:
+
+	ec.util.BadParameterException
+
+When you use a Parameter to attempt to load and and initialize a class from
+the ParameterDatabase, and something failed on that attempt, a 
+ParamClassLoadException is called:
+
+	ec.util.ParamClassLoadException
+
+The GUI facility of ECJ has additional classes meant to access parameters
+programmatically in Swing.  Generally you wouldn't play with these:
+
+	ec.util.ParameterDatabaseEvent
+	ec.util.ParameterDatabaseTreeModel
+	ec.util.ParameterDatabaseTreeNode	
+	ec.util.ReflectedObject
+
+
+
+READING, WRITING, CHECKPOINTING, AND NETWORKING
+-----------------------------------------------
+
+Many ECJ objects (notably Individuals) have the ability to write themselves
+out to a stream in a fashion that is both readable by humans (more or less)
+*and* can be read back in a way that maintains integrity.  To do this they
+rely on ECJ's "Code" facility to encode and decode basic data elements.  To 
+encode data, you can use the Code class:
+
+	ec.util.Code
+
+To decode data, you use the Code class in conjunction with a special object
+which gives you additional information about the decoded data.  This special
+object is called a DecodeReturn:
+
+	ec.util.DecodeReturn
+
+In certain rare situations ECJ finds that it needs to be able to hook a
+DataOutputStream directly to a DataInputStream.  Surprisingly, Java cannot
+provide this facility without using two threads (to enable the PipedInputStream
+and PipedOutputStream).  ECJ's solution is a buffered single-thread pipe called
+DataPipe:
+
+	ec.util.DataPipe
+
+ECJ implements checkpointing of runs via Java's serialization facility.  The
+cover class which handles this work is called Checkpoint:
+
+	ec.util.Checkpoint
+
+Last, a long-standing bug in Java prevents proper lookup of localhost sockets.
+This is fixed using a class from Jakarta called LocalHost:
+
+	ec.util.LocalHost
+
+
+
+MANIPULATING ARRAYS
+-------------------
+
+Largely for historical reasons, ECJ has its own quicksort facilities.  We keep
+these facilities because, quite surprisingly, Java's current sorting facilities
+are very much insufficient.  ECJ's basic class for sorting is QuickSort:
+
+	ec.util.QuickSort
+
+QuickSort relies on a special Comparator object for determining whether two
+objects are greater or less than one another.  This is mostly for historical
+reasons.  There is also a special version of this object for longs:
+
+	ec.util.SortComparator
+	ec.util.SortComparatorL
+
+ECJ can convert arrays of floats, doubles, or arbitrary objects, into
+distributions and then select random numbers under them (treating the
+values in the arrays as actual prenormalized probabilities).  The primary class
+for this is RandomChoice:
+
+	ec.util.RandomChoice
+
+RandomChoice can work with arrays of Objects as long as there's a provided
+object a RandomChoiceChooser, which provides the "probability" value for a
+given Object.  There are two versions of RandomChoiceChooser, one which 
+assumes probabilities are floats, and the other which assumes they are doubles
+(again, mostly for historical reasons):
+
+	ec.util.RandomChoiceChooser
+	ec.util.RandomChoiceChooserD
+
+
+
+SIMPLE LEXING (TOKENIZING)
+--------------------------
+
+ECJ's Grammatical Evolution facility needs to lex simple rulesets, one per line,
+from a file.  The following class makes regular-expression-based lexing simpler:
+
+	ec.util.Lexer
+
+
+
+ECJ'S VERSION
+-------------
+
+Information regarding the current version of ECJ is located in:
+
+	ec.util.Version
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoice.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoice.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoice.java	(revision 6152)
@@ -0,0 +1,648 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * RandomChoice.java
+ * 
+ * Created: January 5, 2001
+ * By: Sean Luke
+ *
+ */
+
+/**
+ * RandomChoice organizes arrays of floats into distributions which can
+ * be used to pick randomly from.  You can provide three kinds of arrays:
+ * 
+ <ul>
+ <li> An array of floats
+ <li> An array of doubles
+ <li> An array of arbitrary objects, plus a RandomChoiceChooser which knows
+ how to get and set the appropriate "float" value of objects in this array.
+ </ul>
+ *
+ * <p>Before the RandomChoice can pick randomly from your array, it must first
+ * organize it.  It does this by doing the following.  First, it normalizes the
+ * values in the array.  Then it modifies them to their sums.  That is, each item i
+ * in the array is set to the sum of the original values for items 0...i.  If you
+ * cannot allow your objects to be modified, then this is not the class for you.
+ *
+ * <p>An array is valid if (1) it has no negative values and (2) not all of its
+ * values are zero.  This RandomChoice code <i>should</i> (I hope) guarantee that
+ * an element of zero probability is never returned.  RandomChoice uses a binary
+ * search to find your index, followed by linear probing (marching up or down
+ * the list) to find the first non-zero probability item in the vacinity of that
+ * index.  As long as there are not a whole lot of zero-valued items in a row,
+ * RandomChoice is efficient.
+ *
+ * You organize your array with organizeDistribution().  Then you can have the
+ * RandomChoice pick random items from the array and return their indexes to you.
+ * You do this by calling pickFromDistribution(), passing it a random floating
+ * point value between 0.0 and 1.0.  You call organizeDistribution() only once;
+ * after which you may call pickFromDistribution() as many times as you like.
+ * You should not modify the array thereafter.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class RandomChoice  
+    {
+
+    /** Same as organizeDistribution(probabilities,  <b>false</b>); */
+    public static void organizeDistribution(final float[] probabilities)
+        {
+        organizeDistribution(probabilities, false);
+        }
+
+    /** Normalizes probabilities, then converts them into continuing
+        sums.  This prepares them for being usable in pickFromDistribution.
+        If the probabilities are all 0, then selection is uniform, unless allowAllZeros
+        is false, in which case an ArithmeticException is thrown.  If any of them are negative,
+        or if the distribution is empty, then an ArithmeticException is thrown.
+        For example, 
+        {0.6, 0.4, 0.2, 0.8} -> {0.3, 0.2, 0.1, 0.4} -> {0.3, 0.5, 0.6, 1.0} */
+
+    public static void organizeDistribution(final float[] probabilities, final boolean allowAllZeros)
+        {
+        // first normalize
+        double sum=0.0;
+        if (probabilities.length == 0)
+            throw new ArithmeticException("Distribution has no elements");
+            
+        for(int x=0;x<probabilities.length;x++)
+            {
+            if (probabilities[x]<0.0)
+                throw new ArithmeticException("Distribution has negative probabilities");
+            sum += probabilities[x];
+            }
+        
+        if (sum==0.0)
+            if (!allowAllZeros)
+                throw new ArithmeticException("Distribution has all zero probabilities");
+            else
+                {
+                for(int x=0;x<probabilities.length;x++)
+                    probabilities[x] = 1.0f;
+                sum = probabilities.length;
+                }
+        
+        for(int x=0;x<probabilities.length;x++)
+            probabilities[x] /= sum;
+
+        // now sum
+        sum=0.0;
+        for(int x=0;x<probabilities.length;x++)
+            {
+            sum += probabilities[x];
+            probabilities[x] = (float)sum;
+            }
+        
+        // now we need to work backwards setting 0 values
+        int x;
+        for(x=probabilities.length-1; x > 0; x--)
+            if (probabilities[x]==probabilities[x-1])  // we're 0.0
+                probabilities[x] = 1.0f;
+            else break; 
+        probabilities[x] = 1.0f;
+        }
+
+    /** Same as organizeDistribution(probabilities,  <b>false</b>); */
+    public static void organizeDistribution(final double[] probabilities)
+        {
+        organizeDistribution(probabilities, false);
+        }
+
+    /** Normalizes probabilities, then converts them into continuing
+        sums.  This prepares them for being usable in pickFromDistribution.
+        If the probabilities are all 0, then selection is uniform, unless allowAllZeros
+        is false, in which case an ArithmeticException is thrown.  If any of them are negative,
+        or if the distribution is empty, then an ArithmeticException is thrown.
+        For example, 
+        {0.6, 0.4, 0.2, 0.8} -> {0.3, 0.2, 0.1, 0.4} -> {0.3, 0.5, 0.6, 1.0} */
+
+    public static void organizeDistribution(final double[] probabilities, final boolean allowAllZeros)
+        {
+        // first normalize
+        double sum=0.0;
+
+        if (probabilities.length == 0)
+            throw new ArithmeticException("Distribution has no elements");
+
+        for(int x=0;x<probabilities.length;x++)
+            {
+            if (probabilities[x]<0.0)
+                throw new ArithmeticException("Distribution has negative probabilities");
+            sum += probabilities[x];
+            }
+
+        if (sum==0.0)
+            if (!allowAllZeros)
+                throw new ArithmeticException("Distribution has all zero probabilities");
+            else
+                {
+                for(int x=0;x<probabilities.length;x++)
+                    probabilities[x] = 1.0;
+                sum = probabilities.length;
+                }
+        
+        for(int x=0;x<probabilities.length;x++)
+            probabilities[x] /= sum;
+
+        // now sum
+        sum=0.0;
+        for(int x=0;x<probabilities.length;x++)
+            {
+            sum += probabilities[x];
+            probabilities[x] = sum;
+            }
+        
+        // now we need to work backwards setting 0 values
+        int x;
+        for(x=probabilities.length-1; x > 0; x--)
+            if (probabilities[x]==probabilities[x-1])  // we're 0.0
+                probabilities[x] = 1.0;
+            else break; 
+        probabilities[x] = 1.0;
+
+        }
+
+    /** Same as organizeDistribution(objs, chooser, <b>false</b>); */
+    public static void organizeDistribution(final Object[] objs, 
+        final RandomChoiceChooser chooser)
+        {
+        organizeDistribution(objs,chooser, false);
+        }
+
+    /** Normalizes the probabilities associated
+        with an array of objects, then converts them into continuing
+        sums.  This prepares them for being usable in pickFromDistribution.
+        If the probabilities are all 0, then selection is uniform, unless allowAllZeros
+        is false, in which case an ArithmeticException is thrown.  If any of them are negative,
+        or if the distribution is empty, then an ArithmeticException is thrown.
+        For example, 
+        {0.6, 0.4, 0.2, 0.8} -> {0.3, 0.2, 0.1, 0.4} -> {0.3, 0.5, 0.6, 1.0} 
+        The probabilities are retrieved and set using chooser.*/
+
+    public static void organizeDistribution(final Object[] objs, 
+        final RandomChoiceChooser chooser, final boolean allowAllZeros)
+        {
+        // first normalize
+        double sum=0.0;
+
+        if (objs.length == 0)
+            throw new ArithmeticException("Distribution has no elements");
+
+        for(int x=0;x<objs.length;x++)
+            {
+            if (chooser.getProbability(objs[x])<0.0)
+                throw new ArithmeticException("Distribution has negative probabilities");
+            sum += chooser.getProbability(objs[x]);
+            }
+
+        if (sum==0.0)
+            if (!allowAllZeros)
+                throw new ArithmeticException("Distribution has all zero probabilities");
+            else
+                {
+                for(int x=0;x<objs.length;x++)
+                    chooser.setProbability(objs[x], 1.0f);
+                sum = objs.length;
+                }
+
+        for(int x=0;x<objs.length;x++)
+            chooser.setProbability(objs[x],
+                (float)(chooser.getProbability(objs[x]) / sum));
+
+        // now sum
+        sum=0.0;
+        for(int x=0;x<objs.length;x++)
+            {
+            sum += chooser.getProbability(objs[x]);
+            chooser.setProbability(objs[x],(float)sum);
+            }
+
+        // now we need to work backwards setting 0 values
+        int x;
+        for(x=objs.length-1; x > 0; x--)
+            if (chooser.getProbability(objs[x])==
+                chooser.getProbability(objs[x-1]))  // we're 0.0
+                chooser.setProbability(objs[x],1.0f);
+            else break; 
+        chooser.setProbability(objs[x],1.0f);
+        }
+    
+    /** Same as organizeDistribution(objs, chooser, <b>false</b>); */
+    public static void organizeDistribution(final Object[] objs, 
+        final RandomChoiceChooserD chooser)
+        {
+        organizeDistribution(objs,chooser, false);
+        }
+
+    /** Normalizes the probabilities associated
+        with an array of objects, then converts them into continuing
+        sums.  This prepares them for being usable in pickFromDistribution.
+        If the probabilities are all 0, then selection is uniform, unless allowAllZeros
+        is false, in which case an ArithmeticException is thrown.  If any of them are negative,
+        or if the distribution is empty, then an ArithmeticException is thrown.
+        For example, 
+        {0.6, 0.4, 0.2, 0.8} -> {0.3, 0.2, 0.1, 0.4} -> {0.3, 0.5, 0.6, 1.0} 
+        The probabilities are retrieved and set using chooser.*/
+
+    public static void organizeDistribution(final Object[] objs, 
+        final RandomChoiceChooserD chooser, final boolean allowAllZeros)
+        {
+        // first normalize
+        double sum=0.0;
+
+        if (objs.length == 0)
+            throw new ArithmeticException("Distribution has no elements");
+
+        for(int x=0;x<objs.length;x++)
+            {
+            if (chooser.getProbability(objs[x])<0.0)
+                throw new ArithmeticException("Distribution has negative probabilities");
+            sum += chooser.getProbability(objs[x]);
+            }
+
+        if (sum==0.0)
+            if (!allowAllZeros)
+                throw new ArithmeticException("Distribution has all zero probabilities");
+            else
+                {
+                for(int x=0;x<objs.length;x++)
+                    chooser.setProbability(objs[x], 1.0);
+                sum = objs.length;
+                }
+
+        for(int x=0;x<objs.length;x++)
+            chooser.setProbability(objs[x],
+                (double)(chooser.getProbability(objs[x]) / sum));
+
+        // now sum
+        sum=0.0;
+        for(int x=0;x<objs.length;x++)
+            {
+            sum += chooser.getProbability(objs[x]);
+            chooser.setProbability(objs[x],(double)sum);
+            }
+
+        // now we need to work backwards setting 0 values
+        int x;
+        for(x=objs.length-1; x > 0; x--)
+            if (chooser.getProbability(objs[x])==
+                chooser.getProbability(objs[x-1]))  // we're 0.0
+                chooser.setProbability(objs[x],1.0);
+            else break; 
+        chooser.setProbability(objs[x],1.0);
+        }
+
+
+    // allows us to have zero-probability values
+    private static final int exemptZeroes(final float[] probabilities, int index)
+        {
+        //System.out.println(index);
+        if (probabilities[index]==0.0f) // I need to scan forward because I'm in a left-trail
+            // scan forward
+            { while(index < probabilities.length-1 && probabilities[index]==0.0f) index++; }
+        else
+            // scan backwards
+            { while(index > 0 && probabilities[index]==probabilities[index-1]) index--; }
+        return index;
+        }
+
+    // allows us to have zero-probability values
+    private static final int exemptZeroes(final double[] probabilities, int index)
+        {
+        //System.out.println(index);
+        if (probabilities[index]==0.0) // I need to scan forward because I'm in a left-trail
+            // scan forward
+            { while(index < probabilities.length-1 && probabilities[index]==0.0) index++; }
+        else
+            // scan backwards
+            { while(index > 0 && probabilities[index]==probabilities[index-1]) index--; }
+        return index;
+        }
+
+
+    // allows us to have zero-probability values
+    private static final int exemptZeroes(final Object[] objs, 
+        final RandomChoiceChooser chooser, int index)
+        {
+        //System.out.println(index);
+        if (chooser.getProbability(objs[index])==0.0f) // I need to scan forward because I'm in a left-trail
+            // scan forward
+            { while(index < objs.length-1 && chooser.getProbability(objs[index])==0.0f) index++; }
+        else
+            // scan backwards
+            { while(index > 0 && chooser.getProbability(objs[index])==
+                    chooser.getProbability(objs[index-1])) index--; }
+        return index;
+        }
+
+
+    // allows us to have zero-probability values
+    private static final int exemptZeroes(final Object[] objs, 
+        final RandomChoiceChooserD chooser, int index)
+        {
+        //System.out.println(index);
+        if (chooser.getProbability(objs[index])==0.0) // I need to scan forward because I'm in a left-trail
+            // scan forward
+            { while(index < objs.length-1 && chooser.getProbability(objs[index])==0.0) index++; }
+        else
+            // scan backwards
+            { while(index > 0 && chooser.getProbability(objs[index])==
+                    chooser.getProbability(objs[index-1])) index--; }
+        return index;
+        }
+
+
+    public static final int CHECKBOUNDARY = 8;
+        
+    /** Picks a random item from an array of probabilities,
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < CHECKBOUNDARY,
+        then a linear search is used, else a binary search is used. */
+
+    public static int pickFromDistribution(final float[] probabilities,
+        final float prob)
+        {
+        return pickFromDistribution(probabilities, prob, CHECKBOUNDARY);
+        }
+
+    
+    /** Picks a random item from an array of probabilities,
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < checkboundary,
+        then a linear search is used, else a binary search is used.
+        @deprecated
+    */
+    public static int pickFromDistribution(final float[] probabilities,
+        final float prob, final int checkboundary)
+        {
+        if (prob<0.0f || prob>1.0f)
+            throw new ArithmeticException("Invalid probability for pickFromDistribution (must be 0.0<=x<=1.0)");
+        else if (probabilities.length==1) // quick 
+            return 0;
+        else if (probabilities.length<checkboundary)
+            {
+            // simple linear scan
+            for(int x=0;x<probabilities.length-1;x++)
+                if (probabilities[x]>prob)
+                    return exemptZeroes(probabilities,x); 
+            return exemptZeroes(probabilities,probabilities.length-1);
+            }
+        else
+            {
+            // binary search
+            int top = probabilities.length-1;
+            int bottom = 0;
+            int cur;
+
+            while(top!=bottom)
+                {
+                cur = (top + bottom) / 2; // integer division
+
+                if (probabilities[cur] > prob)
+                    if (cur==0 || probabilities[cur-1] <= prob)
+                        return exemptZeroes(probabilities,cur);
+                    else // step down
+                        top = cur;
+                else if (cur==probabilities.length-1) // oops
+                    return exemptZeroes(probabilities,cur);
+                else if (bottom==cur) // step up
+                    bottom++;  // (8 + 9)/2 = 8
+                else
+                    bottom = cur;  // (8 + 10) / 2 = 9
+                }
+            return exemptZeroes(probabilities,bottom);  // oops
+            }
+        }
+
+
+
+    /** Picks a random item from an array of probabilities,
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < CHECKBOUNDARY,
+        then a linear search is used, else a binary search is used. */
+
+    public static int pickFromDistribution(final double[] probabilities,
+        final double prob)
+        {
+        return pickFromDistribution(probabilities, prob, CHECKBOUNDARY);
+        }
+
+    
+    /** Picks a random item from an array of probabilities,
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < checkboundary,
+        then a linear search is used, else a binary search is used.
+        @deprecated
+    */
+    
+    public static int pickFromDistribution(final double[] probabilities,
+        final double prob, final int checkboundary)
+        {
+        if (prob<0.0 || prob>1.0)
+            throw new ArithmeticException("Invalid probability for pickFromDistribution (must be 0.0<=x<=1.0)");
+        if (probabilities.length==1) // quick 
+            return 0;
+        else if (probabilities.length<checkboundary)
+            {
+            // simple linear scan
+            for(int x=0;x<probabilities.length-1;x++)
+                if (probabilities[x]>prob)
+                    return exemptZeroes(probabilities,x); 
+            return exemptZeroes(probabilities,probabilities.length-1);
+            }
+        else
+            {
+            // binary search
+            int top = probabilities.length-1;
+            int bottom = 0;
+            int cur;
+
+            while(top!=bottom)
+                {
+                cur = (top + bottom) / 2; // integer division
+
+                if (probabilities[cur] > prob)
+                    if (cur==0 || probabilities[cur-1] <= prob)
+                        return exemptZeroes(probabilities,cur);
+                    else // step down
+                        top = cur;
+                else if (cur==probabilities.length-1) // oops
+                    return exemptZeroes(probabilities,cur);
+                else if (bottom==cur) // step up
+                    bottom++;  // (8 + 9)/2 = 8
+                else
+                    bottom = cur;  // (8 + 10) / 2 = 9
+                }
+            return exemptZeroes(probabilities,bottom);  // oops
+            }
+        }
+
+
+    /** Picks a random item from an array of objects, each with an
+        associated probability that is accessed by taking an object
+        and passing it to chooser.getProbability(obj).  The objects'
+        probabilities are 
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < CHECKBOUNDARY,
+        then a linear search is used, else a binary search is used. */
+    
+    public static int pickFromDistribution(final Object[] objs, 
+        final RandomChoiceChooser chooser,
+        final float prob)
+        {
+        return pickFromDistribution(objs, chooser, prob, CHECKBOUNDARY);
+        }
+
+    /** Picks a random item from an array of objects, each with an
+        associated probability that is accessed by taking an object
+        and passing it to chooser.getProbability(obj).  The objects'
+        probabilities are 
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < checkboundary,
+        then a linear search is used, else a binary search is used.
+        @deprecated
+    */
+    
+    public static int pickFromDistribution(final Object[] objs, 
+        final RandomChoiceChooser chooser,
+        final float prob, final int checkboundary)
+        {
+        if (prob<0.0f || prob>1.0f)
+            throw new ArithmeticException("Invalid probability for pickFromDistribution (must be 0.0<=x<=1.0)");
+        if (objs.length==1) // quick 
+            return 0;
+        else if (objs.length<checkboundary)
+            {
+            // simple linear scan
+            for(int x=0;x<objs.length-1;x++)
+                if (chooser.getProbability(objs[x]) >prob)
+                    return exemptZeroes(objs,chooser,x); 
+            return exemptZeroes(objs,chooser,objs.length-1);
+            }
+        else
+            {
+            // binary search
+            int top = objs.length-1;
+            int bottom = 0;
+            int cur;
+
+            while(top!=bottom)
+                {
+                cur = (top + bottom) / 2; // integer division
+
+                if (chooser.getProbability(objs[cur]) > prob)
+                    if (cur==0 || chooser.getProbability(objs[cur-1]) <= prob)
+                        return exemptZeroes(objs,chooser,cur);
+                    else // step down
+                        top = cur;
+                else if (cur==objs.length-1) // oops
+                    return exemptZeroes(objs,chooser,cur);
+                else if (bottom==cur) // step up
+                    bottom++;  // (8 + 9)/2 = 8
+                else
+                    bottom = cur;  // (8 + 10) / 2 = 9
+                }
+            return exemptZeroes(objs,chooser,bottom);  // oops
+            }
+        }
+
+
+    /** Picks a random item from an array of objects, each with an
+        associated probability that is accessed by taking an object
+        and passing it to chooser.getProbability(obj).  The objects'
+        probabilities are 
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < CHECKBOUNDARY,
+        then a linear search is used, else a binary search is used. */
+    
+    public static int pickFromDistribution(final Object[] objs, 
+        final RandomChoiceChooserD chooser,
+        final double prob)
+        {
+        return pickFromDistribution(objs, chooser, prob, CHECKBOUNDARY);
+        }
+                
+    /** Picks a random item from an array of objects, each with an
+        associated probability that is accessed by taking an object
+        and passing it to chooser.getProbability(obj).  The objects'
+        probabilities are 
+        normalized and summed as follows:  For example,
+        if four probabilities are {0.3, 0.2, 0.1, 0.4}, then
+        they should get normalized and summed by the outside owners
+        as: {0.3, 0.5, 0.6, 1.0}.  If probabilities.length < checkboundary,
+        then a linear search is used, else a binary search is used.
+        @deprecated
+    */
+    
+    public static int pickFromDistribution(final Object[] objs, 
+        final RandomChoiceChooserD chooser,
+        final double prob, final int checkboundary)
+        {
+        if (prob<0.0 || prob>1.0)
+            throw new ArithmeticException("Invalid probability for pickFromDistribution (must be 0.0<=x<=1.0)");
+        if (objs.length==1) // quick 
+            return 0;
+        else if (objs.length<checkboundary)
+            {
+            // simple linear scan
+            for(int x=0;x<objs.length-1;x++)
+                if (chooser.getProbability(objs[x]) >prob)
+                    return exemptZeroes(objs,chooser,x); 
+            return exemptZeroes(objs,chooser,objs.length-1);
+            }
+        else
+            {
+            // binary search
+            int top = objs.length-1;
+            int bottom = 0;
+            int cur;
+
+            while(top!=bottom)
+                {
+                cur = (top + bottom) / 2; // integer division
+
+                if (chooser.getProbability(objs[cur]) > prob)
+                    if (cur==0 || chooser.getProbability(objs[cur-1]) <= prob)
+                        return exemptZeroes(objs,chooser,cur);
+                    else // step down
+                        top = cur;
+                else if (cur==objs.length-1) // oops
+                    return exemptZeroes(objs,chooser,cur);
+                else if (bottom==cur) // step up
+                    bottom++;  // (8 + 9)/2 = 8
+                else
+                    bottom = cur;  // (8 + 10) / 2 = 9
+                }
+            return exemptZeroes(objs,chooser,bottom);  // oops
+            }
+        }
+
+    }
+
+
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoiceChooser.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoiceChooser.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoiceChooser.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * RandomChoiceChooser.java
+ * 
+ * Created: Tue Feb  8 15:04:39 2000
+ * By: Sean Luke
+ */
+
+/**
+ * Used by RandomChoice to pick objects by probability from a distribution.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface RandomChoiceChooser
+    {
+    /** Returns obj's probability */
+    public float getProbability(final Object obj);
+    /** Sets obj's probability */
+    public void setProbability(final Object obj, final float prob);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoiceChooserD.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoiceChooserD.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/RandomChoiceChooserD.java	(revision 6152)
@@ -0,0 +1,30 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * RandomChoiceChooserD.java
+ * 
+ * Created: Sat Jan 13 22:40:09 EST 2001
+ * By: Sean Luke
+ */
+
+/**
+ * Used by RandomChoice to pick objects by probability from a distribution.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface RandomChoiceChooserD
+    {
+    /** Returns obj's probability */
+    public double getProbability(final Object obj);
+    /** Sets obj's probability */
+    public void setProbability(final Object obj, final double prob);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/ReflectedObject.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/ReflectedObject.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/ReflectedObject.java	(revision 6152)
@@ -0,0 +1,314 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.lang.reflect.*;
+import javax.swing.tree.*;
+import javax.swing.event.*;
+
+public class ReflectedObject implements TreeModel
+    {
+    Class type;     // the class or TYPE of the object
+    Object obj;     // the object.  Primitive objects are cast into their wrapper types
+    String name;    // the name of the instance variable holding the object.  Top-level objects have a name of "->"
+    Object uniq;    // a unique identifier for this particular instance variable (used to make getIndexOfChild() possible, ick)
+    static ReflectedObject unknown = new ReflectedObject(null)
+        {
+        public String toString() { return "<unknown>"; }
+        };
+    
+    public ReflectedObject(Object o)
+        {
+        this(o,(o==null ? Object.class : o.getClass()),null,null);
+        }
+        
+    protected ReflectedObject(Object o, Class t, String n, Object u)
+        {
+        obj = o;
+        type = t;
+        name = n;
+        uniq = u;
+        }
+    
+    public String toString()
+        {
+        String field = (name == null ? "" : name + ": ");
+        try {
+            if (obj == null) return field + "null";
+            else if (type.isArray()) return field + type.getName() + ", length=" + Array.getLength(obj);
+            return field+type.getName()+" "+obj.toString();
+            } catch (Exception e) {
+            e.printStackTrace();
+            return field + type.getName() + " <error>";
+            }
+        }
+        
+    public int getNumChildren()
+        {
+        return getNumFields() + getNumProperties();
+        }
+    
+    public ReflectedObject getChild(int index)
+        {
+        int f = getNumFields();
+        if (index < f) return getField(index);
+        else return getProperty(index - f);
+        }
+    
+    public ReflectedObject[] getChildren()
+        {
+        ReflectedObject[] fields = getFields();
+        ReflectedObject[] props = getProperties();
+        ReflectedObject o[] = new ReflectedObject[fields.length + props.length];
+        System.arraycopy(fields,0,o,0,fields.length);
+        System.arraycopy(props,0,o,fields.length,props.length);
+        return o;
+        }
+
+    public int getNumFields()
+        {
+        try
+            {
+            if (obj == null || type.isPrimitive()) return 0;
+            else if (type.isArray())
+                {
+                return Array.getLength(obj);
+                }
+            else
+                {
+                return type.getFields().length;
+                }
+            }
+        catch (IllegalArgumentException e) { e.printStackTrace(); throw new RuntimeException("Unexpected Exception: " + e); }
+        }
+    
+    public ReflectedObject getField(int index)
+        {
+        try
+            {
+            if (obj == null || type.isPrimitive() || index < 0) return null;
+            else if (type.isArray())
+                {
+                int len = Array.getLength(obj);
+                if (index > len) return null;
+                return new ReflectedObject(Array.get(obj,index), type.getComponentType(),""+index, ""+index);
+                }
+            else
+                {
+                Field[] f = type.getFields();
+                int len = f.length;
+                if (index > len) return null;
+                return new ReflectedObject(f[index].get(obj), 
+                        (f[index].get(obj) == null || f[index].getType().isPrimitive() ? 
+                        f[index].getType() : f[index].get(obj).getClass()), 
+                    f[index].getName(), f[index]);
+                }
+            }
+        catch (IllegalArgumentException e) { e.printStackTrace(); throw new RuntimeException("Unexpected Exception: " + e); }
+        catch (IllegalAccessException e) { e.printStackTrace(); throw new RuntimeException("Unexpected Exception: " + e); }
+        }
+    
+    public ReflectedObject[] getFields()
+        {
+        try
+            {
+            if (obj == null || type.isPrimitive()) return new ReflectedObject[0];
+            else if (type.isArray())
+                {
+                int len = Array.getLength(obj);
+                ReflectedObject[] ref = new ReflectedObject[len];
+                for(int x = 0; x < len; x++)    
+                    ref[x] = new ReflectedObject(Array.get(obj,x), type.getComponentType(),""+x,""+x);
+                return ref;
+                }
+            else
+                {
+                Field[] f = type.getFields();
+                int len = f.length;
+                ReflectedObject[] ref = new ReflectedObject[len];
+                for(int x=0;x<len; x++)
+                    ref[x] = new ReflectedObject(f[x].get(obj), 
+                        (f[x].get(obj) == null || f[x].getType().isPrimitive() ? f[x].getType() : f[x].get(obj).getClass()), 
+                        f[x].getName(), f[x]);
+                return ref;
+                }
+            }
+        catch (IllegalArgumentException e) { e.printStackTrace(); throw new RuntimeException("Unexpected Exception: " + e); }
+        catch (IllegalAccessException e) { e.printStackTrace(); throw new RuntimeException("Unexpected Exception: " + e); }
+        }
+    
+    public boolean equals(Object obj)
+        {
+        if (obj == null) return false;
+        if (!(obj instanceof ReflectedObject)) return false;
+        if (uniq == null && ((ReflectedObject)obj).uniq == null) return true;
+        if (uniq == null || ((ReflectedObject)obj).uniq == null) return false;
+        return ((ReflectedObject)obj).uniq.equals(uniq);
+        }
+        
+    // tree model stuff
+    public Object getRoot() { return this; }
+    public Object getChild(Object parent, int index)
+        {
+        return ((ReflectedObject)parent).getChild(index);
+        }
+    public int getChildCount(Object parent)
+        {
+        return ((ReflectedObject)parent).getNumChildren();
+        }
+    // This could get grotesquely expensive!
+    public int getIndexOfChild(Object parent, Object child)
+        {
+        ReflectedObject[] children = ((ReflectedObject)parent).getChildren();
+        for(int x=0;x<children.length;x++)
+            if (children[x].equals(child)) return x;
+        throw new IndexOutOfBoundsException("No such child " + child + " in parent " + ((ReflectedObject)parent).toString());
+        }
+    public boolean isLeaf(Object parent)
+        {
+        return getChildCount(parent) == 0;
+        }
+    public void valueForPathChanged(TreePath path, Object newValue)
+        {
+        // do nothing
+        }
+    public void addTreeModelListener(TreeModelListener l)
+        {
+        // do nothing
+        }
+    public void removeTreeModelListener(TreeModelListener l)
+        {
+        // do nothing
+        }
+        
+    // Java Bean Properties
+    int getNumProperties()
+        {
+        if (obj==null) return 0;
+        int count = 0;
+        
+        // generate the properties
+        try
+            {
+            Class c = obj.getClass();
+            Method[] m = (c.getMethods());
+            for(int x = 0 ; x < m.length; x++)
+                {
+                if (m[x].getName().startsWith("get") || m[x].getName().startsWith("is")) // corrrect syntax?
+                    {
+                    int modifier = m[x].getModifiers();
+                    if (m[x].getParameterTypes().length == 0 &&
+                        Modifier.isPublic(modifier) &&
+                        m[x].getReturnType() != Void.TYPE) // no arguments, and public, non-void, non-abstract?
+                        {
+                        count++;
+                        }
+                    }
+                }
+            }
+        catch (Exception e)
+            {
+            count = 0;
+            e.printStackTrace();
+            }
+        return count;
+        }
+
+    ReflectedObject getProperty(int index)
+        {
+        if (obj==null) return null;
+        int count = 0;
+        
+        // generate the properties
+        try
+            {
+            Class c = obj.getClass();
+            Method[] m = (c.getMethods());
+            for(int x = 0 ; x < m.length; x++)
+                {
+                if (m[x].getName().startsWith("get") || m[x].getName().startsWith("is")) // corrrect syntax?
+                    {
+                    int modifier = m[x].getModifiers();
+                    if (m[x].getParameterTypes().length == 0 &&
+                        Modifier.isPublic(modifier) &&
+                        m[x].getReturnType() != Void.TYPE) // no arguments, and public, non-void, non-abstract?
+                        {
+                        if (count==index)
+                            {
+                            Object o = null;
+                            try
+                                {
+                                o = m[x].invoke(obj, new Object[0]);
+                                }
+                            catch (InvocationTargetException e)
+                                {
+                                return unknown;
+                                }
+                            return new ReflectedObject(o, o == null || m[x].getReturnType().isPrimitive() ? 
+                                m[x].getReturnType() : o.getClass(),
+                                "Property " + m[x].getName(), "Property " + m[x].getName());
+                            }
+                        count++;
+                        }
+                    }
+                }
+            }
+        catch (Exception e)
+            {
+            e.printStackTrace();
+            }
+        return unknown;
+        }
+ 
+    
+    ReflectedObject[] getProperties()
+        {
+        if (obj==null) return new ReflectedObject[0];
+        int len = getNumProperties();
+        int count = 0;
+        
+        ReflectedObject[] refs = new ReflectedObject[len];
+        
+        // generate the properties
+        try
+            {
+            Class c = obj.getClass();
+            Method[] m = (c.getMethods());
+            for(int x = 0 ; x < m.length; x++)
+                {
+                if (m[x].getName().startsWith("get") || m[x].getName().startsWith("is")) // corrrect syntax?
+                    {
+                    int modifier = m[x].getModifiers();
+                    if (m[x].getParameterTypes().length == 0 &&
+                        Modifier.isPublic(modifier) &&
+                        m[x].getReturnType() != Void.TYPE) // no arguments, and public, non-void, non-abstract?
+                        {
+                        Object o = null;
+                        try
+                            {
+                            o = m[x].invoke(obj, new Object[0]);
+                            refs[count] = new ReflectedObject(o, o == null || m[x].getReturnType().isPrimitive() ? 
+                                m[x].getReturnType() : o.getClass(),
+                                "Property " + m[x].getName(), "Property " + m[x].getName());
+                            }
+                        catch (InvocationTargetException e)
+                            {
+                            refs[count] = unknown;
+                            }
+                        count++;
+                        }
+                    }
+                }
+            }
+        catch (Exception e)
+            {
+            e.printStackTrace();
+            }
+        return refs;
+        }
+          
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/SortComparator.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/SortComparator.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/SortComparator.java	(revision 6152)
@@ -0,0 +1,31 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * SortComparator.java
+ * 
+ * Created: Wed Nov  3 16:10:02 1999
+ * By: Sean Luke
+ */
+
+/**
+ * The interface for passing objects to ec.util.QuickSort
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface SortComparator 
+    {
+    /** Returns true if a < b, else false */
+    public boolean lt(Object a, Object b);
+
+    /** Returns true if a > b, else false */
+    public boolean gt(Object a, Object b);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/SortComparatorL.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/SortComparatorL.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/SortComparatorL.java	(revision 6152)
@@ -0,0 +1,31 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+
+/* 
+ * SortComparatorL.java
+ * 
+ * Created: Wed Nov  3 16:10:02 1999
+ * By: Sean Luke
+ */
+
+/**
+ * The interface for passing objects to ec.util.QuickSort
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public interface SortComparatorL 
+    {
+    /** Returns true if a < b, else false */
+    public boolean lt(long a, long b);
+
+    /** Returns true if a > b, else false */
+    public boolean gt(long a, long b);
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/util/Version.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/util/Version.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/util/Version.java	(revision 6152)
@@ -0,0 +1,70 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.util;
+import java.util.*;
+
+/* 
+ * Version.java
+ * 
+ * Created: Wed Aug 11 19:44:46 1999
+ * By: Sean Luke
+ */
+
+/**
+ * Version is a static class which stores version information for this
+ * evolutionary computation system.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ */
+
+public class Version
+    {
+    public static final String name = "ECJ";
+    public static final String version = "20";
+    public static final String copyright = "2010";
+    public static final String author = "Sean Luke";
+    public static final String contributors = "L. Panait, G. Balan, S. Paus, Z. Skolicki, R. Kicinger, E. Popovici,";
+    public static final String contributors2 = "K. Sullivan, J. Harrison, J. Bassett, R. Hubley, A. Desai, A. Chircop,";
+    public static final String contributors3 = "J. Compton, W. Haddon, S. Donnelly, B. Jamil, J. Zelibor, E. Kangas,";
+    public static final String contributors4 = "F. Abidi, H. Mooers, and J. O'Beirne";
+    public static final String authorEmail0 = "ecj-help";
+    public static final String authorEmail1 = "cs.gmu.edu";
+    public static final String authorEmail2 = "(better: join ECJ-INTEREST at URL above)";
+    public static final String authorURL = "http://cs.gmu.edu/~eclab/projects/ecj/";
+    public static final String date = "December 15, 2010";
+    public static final String minimumJavaVersion = "1.4";
+
+    public static final String message()
+        {
+        Properties p = System.getProperties();
+        String javaVersion = p.getProperty("java.version");
+        String javaVM = p.getProperty("java.vm.name");
+        String javaVMVersion = p.getProperty("java.vm.version");
+        if (javaVM!=null) javaVersion = javaVersion + " / " + javaVM;
+        if (javaVM!=null && javaVMVersion!=null) javaVersion = javaVersion + "-" + javaVMVersion;
+        
+    
+        return 
+            "\n| " + name + 
+            "\n| An evolutionary computation system (version " + version + ")" +
+            //"\n| Copyright " + copyright + */ " By " + author +
+            "\n| By " + author + 
+            "\n| Contributors: " + contributors +
+            "\n|               " + contributors2 +
+            "\n|               " + contributors3 +
+            "\n|               " + contributors4 +
+            "\n| URL: " + authorURL +
+            "\n| Mail: " + authorEmail0 + "@" + authorEmail1 +
+            "\n|       " + authorEmail2 + 
+            "\n| Date: " + date +
+            "\n| Current Java: " + javaVersion +
+            "\n| Required Minimum Java: " + minimumJavaVersion +
+            "\n\n";
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/BitVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/BitVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/BitVectorIndividual.java	(revision 6152)
@@ -0,0 +1,307 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * BitVectorIndividual.java
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ */
+
+/**
+ * BitVectorIndividual is a VectorIndividual whose genome is an array of booleans.
+ * The default mutation method simply flips bits with <tt>mutationProbability</tt>.
+ *
+ * <P><b>From ec.Individual:</b>  
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+ <p><b>Default Base</b><br>
+ vector.bit-vect-ind
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class BitVectorIndividual extends VectorIndividual
+    {
+    public static final String P_BITVECTORINDIVIDUAL = "bit-vect-ind";
+    public boolean[] genome;
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_BITVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        BitVectorIndividual myobj = (BitVectorIndividual) (super.clone());
+        
+        // must clone the genome
+        myobj.genome = (boolean[])(genome.clone());
+        
+        return myobj;
+        } 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+
+        VectorSpecies s = (VectorSpecies)species;  // where my default info is stored
+        genome = new boolean[s.genomeSize];
+        }
+
+    public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
+        {
+        VectorSpecies s = (VectorSpecies)species;  // where my default info is stored
+        BitVectorIndividual i = (BitVectorIndividual) ind;
+        boolean tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output.fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch(s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                for(int x=0;x<point*s.chunksize;x++)
+                    { 
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x]; 
+                    genome[x] = tmp; 
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT: 
+                int point0 = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                if (point0 > point) { int p = point0; point0 = point; point = p; }
+                for(int x=point0*s.chunksize;x<point*s.chunksize;x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for(int x=0;x<genome.length/s.chunksize;x++) 
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for(int y=x*s.chunksize;y<(x+1)*s.chunksize;y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            }
+        }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0; point1 = points[0];
+        for(int x=0;x<pieces.length;x++)
+            {
+            pieces[x] = new boolean[point1-point0];
+            System.arraycopy(genome,point0,pieces[x],0,point1-point0);
+            point0 = point1;
+            if (x >=pieces.length-2)
+                point1 = genome.length;
+            else point1 = points[x+1];
+            }
+        }
+    
+    /** Joins the n pieces and sets the genome to their concatenation.*/
+    public void join(Object[] pieces)
+        {
+        int sum=0;
+        for(int x=0;x<pieces.length;x++)
+            sum += ((boolean[])(pieces[x])).length;
+        
+        int runningsum = 0;
+        boolean[] newgenome = new boolean[sum];
+        for(int x=0;x<pieces.length;x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum, ((boolean[])(pieces[x])).length);
+            runningsum += ((boolean[])(pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /** Destructively mutates the individual in some default manner.  The default form
+        does a bit-flip with a probability depending on parameters. */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        VectorSpecies s = (VectorSpecies)species;  // where my default info is stored
+        if (s.mutationProbability>0.0)
+            for(int x=0;x<genome.length;x++)
+                if (state.random[thread].nextBoolean(s.mutationProbability))
+                    genome[x] = !genome[x];
+        }
+        
+    /** Initializes the individual by randomly flipping the bits */
+    public void reset(EvolutionState state, int thread)
+        {
+        for(int x=0;x<genome.length;x++)
+            genome[x] = state.random[thread].nextBoolean();
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = ( hash << 1 | hash >>> 31 ) ^ genome.hashCode();
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            if( genome[i] )
+                s = s + " 1";
+            else
+                s = s + " 0";
+            }
+        return s;
+        }
+        
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append( Code.encode( genome.length ) );
+        for( int i = 0 ; i < genome.length ; i++ )
+            s.append( Code.encode( genome[i] ) );
+        return s.toString();
+        }
+                
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line.  The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode( d );
+        int lll = (int)(d.l);
+
+        genome = new boolean[ lll ];
+
+        // read in the genes
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            Code.decode( d );
+            genome[i] = (boolean)(d.l!=0);
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false; // SimpleRuleIndividuals are special.
+        BitVectorIndividual i = (BitVectorIndividual)ind;
+        if( genome.length != i.genome.length )
+            return false;
+        for( int j = 0 ; j < genome.length ; j++ )
+            if( genome[j] != i.genome[j] )
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        { return genome; }
+    public void setGenome(Object gen)
+        { genome = (boolean[]) gen; }
+    public int genomeLength()
+        { return genome.length; }
+
+    public void setGenomeLength(int len)
+        {
+        boolean[] newGenome = new boolean[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for(int x=0;x<genome.length;x++)
+            dataOutput.writeBoolean(genome[x]);  // inefficient: booleans are written out as bytes
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome==null || genome.length != len)
+            genome = new boolean[len];
+        for(int x=0;x<genome.length;x++)
+            genome[x] = dataInput.readBoolean();
+        }
+
+    /** Implements distance as hamming distance. */
+    public double distanceTo(Individual otherInd)
+        {
+        if (!(otherInd instanceof BitVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        BitVectorIndividual other = (BitVectorIndividual) otherInd;
+        boolean[] otherGenome = other.genome;
+        double hammingDistance =0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            if(genome[i] ^ otherGenome[i])  //^ is xor
+                hammingDistance++;
+            }
+
+        return hammingDistance;
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/ByteVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/ByteVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/ByteVectorIndividual.java	(revision 6152)
@@ -0,0 +1,384 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * ByteVectorIndividual.java
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ */
+
+/**
+ * ByteVectorIndividual is a VectorIndividual whose genome is an array of bytes.
+ * Gene values may range from species.mingene(x) to species.maxgene(x), inclusive.
+ * The default mutation method randomizes genes to new values in this range,
+ * with <tt>species.mutationProbability</tt>.
+
+ * <P><b>From ec.Individual:</b>  
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+ <p><b>Default Base</b><br>
+ vector.byte-vect-ind
+
+ * @author Liviu Panait
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class ByteVectorIndividual extends VectorIndividual
+    {
+    public static final String P_BYTEVECTORINDIVIDUAL = "byte-vect-ind";
+    public byte[] genome;
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_BYTEVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        ByteVectorIndividual myobj = (ByteVectorIndividual) (super.clone());
+
+        // must clone the genome
+        myobj.genome = (byte[])(genome.clone());
+        
+        return myobj;
+        } 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+
+        // since IntegerVectorSpecies set its constraint values BEFORE it called
+        // super.setup(...) [which in turn called our setup(...)], we know that
+        // stuff like genomeSize has already been set...
+        
+        Parameter def = defaultBase();
+        
+        if (!(species instanceof IntegerVectorSpecies)) 
+            state.output.fatal("ByteVectorIndividual requires an IntegerVectorSpecies", base, def);
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        
+        genome = new byte[s.genomeSize];
+        }
+        
+    public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        ByteVectorIndividual i = (ByteVectorIndividual) ind;
+        byte tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output.fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch(s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                for(int x=0;x<point*s.chunksize;x++)
+                    { 
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x]; 
+                    genome[x] = tmp; 
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT: 
+                int point0 = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                if (point0 > point) { int p = point0; point0 = point; point = p; }
+                for(int x=point0*s.chunksize;x<point*s.chunksize;x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for(int x=0;x<genome.length/s.chunksize;x++) 
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for(int y=x*s.chunksize;y<(x+1)*s.chunksize;y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            case VectorSpecies.C_LINE_RECOMB:
+            {
+            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                min = s.minGene(x);
+                max = s.maxGene(x);
+                t = (long) Math.floor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                u = (long) Math.floor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                if (!(t < min || t > max || u < min || u > max))
+                    {
+                    genome[x] = (byte) t;
+                    i.genome[x] = (byte) u; 
+                    }
+                }
+            }
+            break;
+            case VectorSpecies.C_INTERMED_RECOMB:
+            {
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                do
+                    {
+                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    min = s.minGene(x);
+                    max = s.maxGene(x);
+                    t = (long) Math.floor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                    u = (long) Math.floor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                    } while (t < min || t > max || u < min || u > max);
+                genome[x] = (byte) t;
+                i.genome[x] = (byte) u; 
+                }
+            }
+            break;
+            }
+        }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0; point1 = points[0];
+        for(int x=0;x<pieces.length;x++)
+            {
+            pieces[x] = new byte[point1-point0];
+            System.arraycopy(genome,point0,pieces[x],0,point1-point0);
+            point0 = point1;
+            if (x >=pieces.length-2)
+                point1 = genome.length;
+            else point1 = points[x+1];
+            }
+        }
+    
+    /** Joins the n pieces and sets the genome to their concatenation.*/
+    public void join(Object[] pieces)
+        {
+        int sum=0;
+        for(int x=0;x<pieces.length;x++)
+            sum += ((byte[])(pieces[x])).length;
+        
+        int runningsum = 0;
+        byte[] newgenome = new byte[sum];
+        for(int x=0;x<pieces.length;x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum, ((byte[])(pieces[x])).length);
+            runningsum += ((byte[])(pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /** Destructively mutates the individual in some default manner.  The default form
+        simply randomizes genes to a uniform distribution from the min and max of the gene values. */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        if (s.mutationProbability>0.0)
+            for(int x=0;x<genome.length;x++)
+                if (state.random[thread].nextBoolean(s.mutationProbability))
+                    genome[x] = (byte)((int)s.minGene(x) + state.random[thread].nextInt((int)s.maxGene(x)-(int)s.minGene(x)+1));
+        }
+        
+    
+
+    /** Initializes the individual by randomly choosing Bytes uniformly from mingene to maxgene. */
+    public void reset(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        for(int x=0;x<genome.length;x++)
+            genome[x] = (byte)((int)s.minGene(x) + state.random[thread].nextInt((int)s.maxGene(x)-(int)s.minGene(x)+1));
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = ( hash << 1 | hash >>> 31 );
+        for(int x=0;x<genome.length;x++)
+            hash = ( hash << 1 | hash >>> 31 ) ^ genome[x];
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for( int i = 0 ; i < genome.length ; i++ )
+            s = s + " " + genome[i];
+        return s;
+        }
+        
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append( Code.encode( genome.length ) );
+        for( int i = 0 ; i < genome.length ; i++ )
+            s.append( Code.encode( genome[i] ) );
+        return s.toString();
+        }
+                
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line.  The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode( d );
+        int lll = (int)(d.l);
+
+        genome = new byte[ lll ];
+
+        // read in the genes
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            Code.decode( d );
+            genome[i] = (byte)(d.l);
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false; // SimpleRuleIndividuals are special.
+        ByteVectorIndividual i = (ByteVectorIndividual)ind;
+        if( genome.length != i.genome.length )
+            return false;
+        for( int j = 0 ; j < genome.length ; j++ )
+            if( genome[j] != i.genome[j] )
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        { return genome; }
+    public void setGenome(Object gen)
+        { genome = (byte[]) gen; }
+    public int genomeLength()
+        { return genome.length; }
+
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for(int x=0;x<genome.length;x++)
+            dataOutput.writeByte(genome[x]);
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome==null || genome.length != len)
+            genome = new byte[len];
+        for(int x=0;x<genome.length;x++)
+            genome[x] = dataInput.readByte();
+        }
+
+    /** Clips each gene value to be within its specified [min,max] range. */
+    public void clamp() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            {
+            byte minGene = (byte)_species.minGene(i);
+            if (genome[i] < minGene)
+                genome[i] = minGene;
+            else 
+                {
+                byte maxGene = (byte)_species.maxGene(i);
+                if (genome[i] > maxGene)
+                    genome[i] = maxGene;
+                }
+            }
+        }
+                
+    public void setGenomeLength(int len)
+        {
+        byte[] newGenome = new byte[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    /** Returns true if each gene value is within is specified [min,max] range. */
+    public boolean isInRange() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            if (genome[i] < _species.minGene(i) ||
+                genome[i] > _species.maxGene(i)) return false;
+        return true;
+        }
+
+    public double distanceTo(Individual otherInd)
+        {               
+        if (!(otherInd instanceof ByteVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        ByteVectorIndividual other = (ByteVectorIndividual) otherInd;
+        byte[] otherGenome = other.genome;
+        double sumSquaredDistance =0.0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            long dist = this.genome[i] - (long)otherGenome[i];
+            sumSquaredDistance += dist*dist;
+            }
+        return StrictMath.sqrt(sumSquaredDistance);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/DoubleVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/DoubleVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/DoubleVectorIndividual.java	(revision 6152)
@@ -0,0 +1,615 @@
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+
+import java.io.*;
+
+/*
+ * DoubleVectorIndividual.java
+ * Created: Thu Mar 22 13:13:20 EST 2001
+ */
+
+/**
+ * DoubleVectorIndividual is a VectorIndividual whose genome is an array of
+ * doubles. Gene values may range from species.mingene(x) to species.maxgene(x),
+ * inclusive. The default mutation method randomizes genes to new values in this
+ * range, with <tt>species.mutationProbability</tt>. It can also add gaussian
+ * noise to the genes, if so directed in the FloatVectorSpecies. If the gaussian
+ * noise pushes the gene out of range, a new noise value is generated.
+ * 
+ * <p>
+ * <P><b>From ec.Individual:</b> 
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+ * <b>Default Base</b><br>
+ * vector.double-vect-ind
+ * 
+ * @author Liviu Panait
+ * @author Sean Luke and Liviu Panait
+ * @version 2.0
+ */
+
+public class DoubleVectorIndividual extends VectorIndividual
+    {
+    public static final String P_DOUBLEVECTORINDIVIDUAL = "double-vect-ind";
+
+    public double[] genome;
+
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_DOUBLEVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        DoubleVectorIndividual myobj = (DoubleVectorIndividual) (super
+            .clone());
+
+        // must clone the genome
+        myobj.genome = (double[]) (genome.clone());
+
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base); // actually unnecessary (Individual.setup()
+        // is empty)
+
+        // since VectorSpecies set its constraint values BEFORE it called
+        // super.setup(...) [which in turn called our setup(...)], we know that
+        // stuff like genomeSize has already been set...
+
+        Parameter def = defaultBase();
+
+        if (!(species instanceof FloatVectorSpecies))
+            state.output.fatal(
+                "DoubleVectorIndividual requires a FloatVectorSpecies",
+                base, def);
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+
+        genome = new double[s.genomeSize];
+        }
+
+    public void defaultCrossover(EvolutionState state, int thread,
+        VectorIndividual ind)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        DoubleVectorIndividual i = (DoubleVectorIndividual) ind;
+        double tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output
+                .fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch (s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread]
+                    .nextInt((genome.length / s.chunksize) + 1);
+                for (int x = 0; x < point * s.chunksize; x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT:
+                int point0 = state.random[thread]
+                    .nextInt((genome.length / s.chunksize) + 1);
+                point = state.random[thread]
+                    .nextInt((genome.length / s.chunksize) + 1);
+                if (point0 > point)
+                    {
+                    int p = point0;
+                    point0 = point;
+                    point = p;
+                    }
+                for (int x = point0 * s.chunksize; x < point * s.chunksize; x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for (int x = 0; x < genome.length / s.chunksize; x++)
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for (int y = x * s.chunksize; y < (x + 1) * s.chunksize; y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            case VectorSpecies.C_LINE_RECOMB:
+            {
+            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double t,u,min,max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                min = s.minGene(x);
+                max = s.maxGene(x);
+                t = alpha * genome[x] + (1 - alpha) * i.genome[x];
+                u = beta * i.genome[x] + (1 - beta) * genome[x];
+                if (!(t < min || t > max || u < min || u > max))
+                    {
+                    genome[x] = t;
+                    i.genome[x] = u; 
+                    }
+                }
+            }
+            break;
+            case VectorSpecies.C_INTERMED_RECOMB:
+            {
+            double t,u,min,max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                do
+                    {
+                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    min = s.minGene(x);
+                    max = s.maxGene(x);
+                    t = alpha * genome[x] + (1 - alpha) * i.genome[x];
+                    u = beta * i.genome[x] + (1 - beta) * genome[x];
+                    } while (t < min || t > max || u < min || u > max);
+                genome[x] = t;
+                i.genome[x] = u; 
+                }
+            }
+            case VectorSpecies.C_SIMULATED_BINARY:
+            {
+            simulatedBinaryCrossover(state.random[thread], i, s.crossoverDistributionIndex);
+            }
+            break;
+            }
+        }
+
+    /**
+     * Splits the genome into n pieces, according to points, which *must* be
+     * sorted. pieces.length must be 1 + points.length
+     */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0;
+        point1 = points[0];
+        for (int x = 0; x < pieces.length; x++)
+            {
+            pieces[x] = new double[point1 - point0];
+            System.arraycopy(genome, point0, pieces[x], 0, point1 - point0);
+            point0 = point1;
+            if (x >= pieces.length - 2)
+                point1 = genome.length;
+            else
+                point1 = points[x + 1];
+            }
+        }
+
+    /** Joins the n pieces and sets the genome to their concatenation. */
+    public void join(Object[] pieces)
+        {
+        int sum = 0;
+        for (int x = 0; x < pieces.length; x++)
+            sum += ((double[]) (pieces[x])).length;
+
+        int runningsum = 0;
+        double[] newgenome = new double[sum];
+        for (int x = 0; x < pieces.length; x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum,
+                ((double[]) (pieces[x])).length);
+            runningsum += ((double[]) (pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /**
+     * Destructively mutates the individual in some default manner. The default
+     * form simply randomizes genes to a uniform distribution from the min and
+     * max of the gene values. It can also add gaussian noise to the genes, if
+     * so directed in the FloatVectorSpecies. If the gaussian noise pushes the
+     * gene out of range, a new noise value is generated.
+     * 
+     * @author Sean Luke, Liviu Panait and Gabriel Balan
+     */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        if (!(s.mutationProbability > 0.0))
+            return;
+        boolean mutationIsBounded = s.mutationIsBounded;
+        MersenneTwisterFast rng = state.random[thread];
+        if (s.mutationType == FloatVectorSpecies.C_GAUSS_MUTATION)
+            {
+            for (int x = 0; x < genome.length; x++)
+                if (rng.nextBoolean(s.mutationProbability))
+                    {
+                    double val;
+                    double min = s.minGene(x);
+                    double max = s.maxGene(x);
+                    double stdev = s.gaussMutationStdev;
+                    int outOfBoundsLeftOverTries = s.outOfBoundsRetries;
+                    boolean givingUpAllowed = s.outOfBoundsRetries != 0;
+                    do
+                        {
+                        val = rng.nextGaussian() * stdev + genome[x];
+                        outOfBoundsLeftOverTries--;
+                        if (mutationIsBounded && (val > max || val < min))
+                            {
+                            if (givingUpAllowed && (outOfBoundsLeftOverTries == 0))
+                                {
+                                val = min + rng.nextFloat() * (max - min);
+                                s.outOfRangeRetryLimitReached(state);// it better get inlined
+                                break;
+                                }
+                            } else
+                            break;
+                        } while (true);
+                    genome[x] = val;
+                    }
+            } 
+        else if (s.mutationType == FloatVectorSpecies.C_POLYNOMIAL_MUTATION)
+            {
+            polynomialMutate(state.random[thread], s.crossoverDistributionIndex, s.polynomialIsAlternative, s.mutationIsBounded);
+            }
+        else
+            {// C_RESET_MUTATION
+            for (int x = 0; x < genome.length; x++)
+                if (rng.nextBoolean(s.mutationProbability))
+                    genome[x] = s.minGene(x) + rng.nextDouble() * (s.maxGene(x) - s.minGene(x));
+            }
+        }
+                
+                
+    /** This function is broken out to keep it identical to NSGA-II's mutation.c code. eta_m is the distribution
+        index.  */
+    public void polynomialMutate(MersenneTwisterFast random, double eta_m, boolean alternativePolynomialVersion, boolean mutationIsBounded)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        double[] ind = genome;
+        double[] min_realvar = s.minGenes;
+        double[] max_realvar = s.maxGenes;
+                
+        double rnd, delta1, delta2, mut_pow, deltaq;
+        double y, yl, yu, val, xy;
+        double y1;
+        for (int j=0; j < ind.length; j++)
+            {
+            if (random.nextBoolean(s.mutationProbability))
+                {
+                y1 = y = ind[j];
+                yl = min_realvar[j];
+                yu = max_realvar[j];
+                delta1 = (y-yl)/(yu-yl);
+                delta2 = (yu-y)/(yu-yl);
+
+                int totalTries = s.outOfBoundsRetries;
+                int tries = 0;
+                for(tries = 0; tries < totalTries || totalTries == 0; tries++)  // keep trying until totalTries is reached if it's not zero.  If it's zero, go on forever.
+                    {
+                    rnd = (random.nextDouble());
+                    mut_pow = 1.0/(eta_m+1.0);
+                    if (rnd <= 0.5)
+                        {
+                        xy = 1.0-delta1;
+                        val = 2.0*rnd + (alternativePolynomialVersion ? (1.0-2.0*rnd)*(Math.pow(xy,(eta_m+1.0))) : 0.0);
+                        deltaq =  Math.pow(val,mut_pow) - 1.0;
+                        }
+                    else
+                        {
+                        xy = 1.0-delta2;
+                        val = 2.0*(1.0-rnd) + (alternativePolynomialVersion ? 2.0*(rnd-0.5)*(Math.pow(xy,(eta_m+1.0))) : 0.0);
+                        deltaq = 1.0 - (Math.pow(val,mut_pow));
+                        }
+                    y1 = y + deltaq*(yu-yl);
+                    if (mutationIsBounded && (y1 >= yl && y1 <= yu)) break;  // yay, found one
+                    }
+                                        
+                // at this point, if tries is totalTries, we failed
+                if (totalTries != 0 && tries == totalTries)
+                    {
+                    // just randomize
+                    y1 = (double)(min_realvar[j] + random.nextDouble() * (max_realvar[j] - min_realvar[j]));
+                    }
+                ind[j] = y1;
+                }
+            }
+        }
+
+
+
+    public void simulatedBinaryCrossover(MersenneTwisterFast random, DoubleVectorIndividual other, double eta_c)
+        {
+        final double EPS = FloatVectorSpecies.SIMULATED_BINARY_CROSSOVER_EPS;
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        double[] parent1 = genome;
+        double[] parent2 = other.genome;
+        double[] min_realvar = s.minGenes;
+        double[] max_realvar = s.maxGenes;
+                
+                
+        double y1, y2, yl, yu;
+        double c1, c2;
+        double alpha, beta, betaq;
+        double rand;
+                
+        for(int i = 0; i < parent1.length; i++)
+            {
+            if (random.nextBoolean())  // 0.5f
+                {
+                if (Math.abs(parent1[i] - parent2[i]) > EPS)
+                    {
+                    if (parent1[i] < parent2[i])
+                        {
+                        y1 = parent1[i];
+                        y2 = parent2[i];
+                        }
+                    else
+                        {
+                        y1 = parent2[i];
+                        y2 = parent1[i];
+                        }
+                    yl = min_realvar[i];
+                    yu = max_realvar[i];    
+                    rand = random.nextDouble();
+                    beta = 1.0 + (2.0*(y1-yl)/(y2-y1));
+                    alpha = 2.0 - Math.pow(beta,-(eta_c+1.0));
+                    if (rand <= (1.0/alpha))
+                        {
+                        betaq = Math.pow((rand*alpha),(1.0/(eta_c+1.0)));
+                        }
+                    else
+                        {
+                        betaq = Math.pow((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0)));
+                        }
+                    c1 = 0.5*((y1+y2)-betaq*(y2-y1));
+                    beta = 1.0 + (2.0*(yu-y2)/(y2-y1));
+                    alpha = 2.0 - Math.pow(beta,-(eta_c+1.0));
+                    if (rand <= (1.0/alpha))
+                        {
+                        betaq = Math.pow((rand*alpha),(1.0/(eta_c+1.0)));
+                        }
+                    else
+                        {
+                        betaq = Math.pow((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0)));
+                        }
+                    c2 = 0.5*((y1+y2)+betaq*(y2-y1));
+                    if (c1<yl)
+                        c1=yl;
+                    if (c2<yl)
+                        c2=yl;
+                    if (c1>yu)
+                        c1=yu;
+                    if (c2>yu)
+                        c2=yu;
+                    if (random.nextBoolean())
+                        {
+                        parent1[i] = c2;
+                        parent2[i] = c1;
+                        }
+                    else
+                        {
+                        parent1[i] = c1;
+                        parent2[i] = c2;
+                        }
+                    }
+                else
+                    {
+                    // do nothing
+                    }
+                }
+            else
+                {
+                // do nothing
+                }
+            }
+        }
+
+
+    /**
+     * Initializes the individual by randomly choosing doubles uniformly from
+     * mingene to maxgene.
+     */
+    public void reset(EvolutionState state, int thread)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        for (int x = 0; x < genome.length; x++)
+            genome[x] = (s.minGene(x) + state.random[thread].nextDouble()
+                * (s.maxGene(x) - s.minGene(x)));
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual. It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = (hash << 1 | hash >>> 31);
+        for (int x = 0; x < genome.length; x++)
+            {
+            long l = Double.doubleToLongBits(genome[x]);
+            hash = (hash << 1 | hash >>> 31) ^ (int) ((l >>> 16) & 0xFFFFFFF)
+                ^ (int) (l & 0xFFFF);
+            }
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for (int i = 0; i < genome.length; i++)
+            s = s + " " + genome[i];
+        return s;
+        }
+
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append(Code.encode(genome.length));
+        for (int i = 0; i < genome.length; i++)
+            s.append(Code.encode(genome[i]));
+        return s.toString();
+        }
+
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line. The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode(d);
+        int lll = (int) (d.l);
+
+        genome = new double[lll];
+
+        // read in the genes
+        for (int i = 0; i < genome.length; i++)
+            {
+            Code.decode(d);
+            genome[i] = d.d;
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass())))
+            return false; // SimpleRuleIndividuals are special.
+        DoubleVectorIndividual i = (DoubleVectorIndividual) ind;
+        if (genome.length != i.genome.length)
+            return false;
+        for (int j = 0; j < genome.length; j++)
+            if (genome[j] != i.genome[j])
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        {
+        return genome;
+        }
+
+    public void setGenome(Object gen)
+        {
+        genome = (double[]) gen;
+        }
+
+    public int genomeLength()
+        {
+        return genome.length;
+        }
+
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for (int x = 0; x < genome.length; x++)
+            dataOutput.writeDouble(genome[x]);
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome == null || genome.length != len)
+            genome = new double[len];
+
+        for (int x = 0; x < genome.length; x++) 
+            genome[x] = dataInput.readDouble();
+        }
+
+    /** Clips each gene value to be within its specified [min,max] range.  
+        NaN is presently considered in range but the behavior of this method
+        should be assumed to be unspecified on encountering NaN. */
+    public void clamp() 
+        {
+        FloatVectorSpecies _species = (FloatVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            {
+            double minGene = _species.minGene(i);
+            if (genome[i] < minGene)
+                genome[i] = minGene;
+            else 
+                {
+                double maxGene = _species.maxGene(i);
+                if (genome[i] > maxGene)
+                    genome[i] = maxGene;
+                }
+            }
+        }
+                
+    public void setGenomeLength(int len)
+        {
+        double[] newGenome = new double[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    /** Returns true if each gene value is within is specified [min,max] range.
+        NaN is presently considered in range but the behavior of this method
+        should be assumed to be unspecified on encountering NaN. */
+    public boolean isInRange() 
+        {
+        FloatVectorSpecies _species = (FloatVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            if (genome[i] < _species.minGene(i) ||
+                genome[i] > _species.maxGene(i)) return false;
+        return true;
+        }
+
+    public double distanceTo(Individual otherInd)
+        { 
+        if (!(otherInd instanceof DoubleVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        DoubleVectorIndividual other = (DoubleVectorIndividual) otherInd;
+        double[] otherGenome = other.genome;
+        double sumSquaredDistance =0.0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            double dist = this.genome[i] - otherGenome[i];
+            sumSquaredDistance += dist*dist;
+            }
+        return StrictMath.sqrt(sumSquaredDistance);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorIndividual.java	(revision 6152)
@@ -0,0 +1,618 @@
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+
+import java.io.*;
+
+/*
+ * FloatVectorIndividual.java
+ * Created: Thu Mar 22 13:13:20 EST 2001
+ */
+
+/**
+ * FloatVectorIndividual is a VectorIndividual whose genome is an array of
+ * floats. Gene values may range from species.mingene(x) to species.maxgene(x),
+ * inclusive. The default mutation method randomizes genes to new values in this
+ * range, with <tt>species.mutationProbability</tt>. It can also add gaussian noise 
+ * to the genes, if so directed in the FloatVectorSpecies. If the gaussian noise 
+ * pushes the gene out of range, a new noise value is generated.
+ * 
+ * 
+ * <p>
+ * <P><b>From ec.Individual:</b>  
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+ * <b>Default Base</b><br>
+ * vector.float-vect-ind
+ * 
+ * @author Liviu Panait
+ * @version 2.0
+ */
+
+public class FloatVectorIndividual extends VectorIndividual
+    {
+    public static final String P_FLOATVECTORINDIVIDUAL = "float-vect-ind";
+
+    public float[] genome;
+
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_FLOATVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        FloatVectorIndividual myobj = (FloatVectorIndividual) (super.clone());
+
+        // must clone the genome
+        myobj.genome = (float[]) (genome.clone());
+
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base); // actually unnecessary (Individual.setup()
+        // is empty)
+
+        // since VectorSpecies set its constraint values BEFORE it called
+        // super.setup(...) [which in turn called our setup(...)], we know that
+        // stuff like genomeSize has already been set...
+
+        Parameter def = defaultBase();
+
+        if (!(species instanceof FloatVectorSpecies))
+            state.output.fatal(
+                "FloatVectorIndividual requires an FloatVectorSpecies",
+                base, def);
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+
+        genome = new float[s.genomeSize];
+        }
+
+    public void defaultCrossover(EvolutionState state, int thread,
+        VectorIndividual ind)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        FloatVectorIndividual i = (FloatVectorIndividual) ind;
+        float tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output
+                .fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch (s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread]
+                    .nextInt((genome.length / s.chunksize) + 1);
+                for (int x = 0; x < point * s.chunksize; x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT:
+                int point0 = state.random[thread]
+                    .nextInt((genome.length / s.chunksize) + 1);
+                point = state.random[thread]
+                    .nextInt((genome.length / s.chunksize) + 1);
+                if (point0 > point)
+                    {
+                    int p = point0;
+                    point0 = point;
+                    point = p;
+                    }
+                for (int x = point0 * s.chunksize; x < point * s.chunksize; x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for (int x = 0; x < genome.length / s.chunksize; x++)
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for (int y = x * s.chunksize; y < (x + 1) * s.chunksize; y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            case VectorSpecies.C_LINE_RECOMB:
+            {
+            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double t,u,min,max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                min = s.minGene(x);
+                max = s.maxGene(x);
+                t = alpha * genome[x] + (1 - alpha) * i.genome[x];
+                u = beta * i.genome[x] + (1 - beta) * genome[x];
+                if (!(t < min || t > max || u < min || u > max))
+                    {
+                    genome[x] = (float)t;
+                    i.genome[x] = (float)u; 
+                    }
+                }
+            }
+            break;
+            case VectorSpecies.C_INTERMED_RECOMB:
+            {
+            double t,u,min,max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                do
+                    {
+                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    min = s.minGene(x);
+                    max = s.maxGene(x);
+                    t = alpha * genome[x] + (1 - alpha) * i.genome[x];
+                    u = beta * i.genome[x] + (1 - beta) * genome[x];
+                    } while (t < min || t > max || u < min || u > max);
+                genome[x] = (float)t;
+                i.genome[x] = (float)u; 
+                }
+            }
+            break;
+            case VectorSpecies.C_SIMULATED_BINARY:
+            {
+            simulatedBinaryCrossover(state.random[thread], i, s.crossoverDistributionIndex);
+            }
+            break;
+            }
+        }
+
+
+    public void simulatedBinaryCrossover(MersenneTwisterFast random, FloatVectorIndividual other, double eta_c)
+        {
+        final double EPS = FloatVectorSpecies.SIMULATED_BINARY_CROSSOVER_EPS;
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        float[] parent1 = genome;
+        float[] parent2 = other.genome;
+        double[] min_realvar = s.minGenes;
+        double[] max_realvar = s.maxGenes;
+                
+        double y1, y2, yl, yu;
+        double c1, c2;
+        double alpha, beta, betaq;
+        double rand;
+                
+        for(int i = 0; i < parent1.length; i++)
+            {
+            if (random.nextBoolean())  // 0.5f
+                {
+                if (Math.abs(parent1[i] - parent2[i]) > EPS)
+                    {
+                    if (parent1[i] < parent2[i])
+                        {
+                        y1 = parent1[i];
+                        y2 = parent2[i];
+                        }
+                    else
+                        {
+                        y1 = parent2[i];
+                        y2 = parent1[i];
+                        }
+                    yl = min_realvar[i];
+                    yu = max_realvar[i];    
+                    rand = random.nextDouble();
+                    beta = 1.0 + (2.0*(y1-yl)/(y2-y1));
+                    alpha = 2.0 - Math.pow(beta,-(eta_c+1.0));
+                    if (rand <= (1.0/alpha))
+                        {
+                        betaq = Math.pow((rand*alpha),(1.0/(eta_c+1.0)));
+                        }
+                    else
+                        {
+                        betaq = Math.pow((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0)));
+                        }
+                    c1 = 0.5*((y1+y2)-betaq*(y2-y1));
+                    beta = 1.0 + (2.0*(yu-y2)/(y2-y1));
+                    alpha = 2.0 - Math.pow(beta,-(eta_c+1.0));
+                    if (rand <= (1.0/alpha))
+                        {
+                        betaq = Math.pow((rand*alpha),(1.0/(eta_c+1.0)));
+                        }
+                    else
+                        {
+                        betaq = Math.pow((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0)));
+                        }
+                    c2 = 0.5*((y1+y2)+betaq*(y2-y1));
+                    if (c1<yl)
+                        c1=yl;
+                    if (c2<yl)
+                        c2=yl;
+                    if (c1>yu)
+                        c1=yu;
+                    if (c2>yu)
+                        c2=yu;
+                    if (random.nextBoolean())
+                        {
+                        parent1[i] = (float)c2;
+                        parent2[i] = (float)c1;
+                        }
+                    else
+                        {
+                        parent1[i] = (float)c1;
+                        parent2[i] = (float)c2;
+                        }
+                    }
+                else
+                    {
+                    // do nothing
+                    }
+                }
+            else
+                {
+                // do nothing
+                }
+            }
+        }
+
+
+
+
+
+
+
+
+    /**
+     * Splits the genome into n pieces, according to points, which *must* be
+     * sorted. pieces.length must be 1 + points.length
+     */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0;
+        point1 = points[0];
+        for (int x = 0; x < pieces.length; x++)
+            {
+            pieces[x] = new float[point1 - point0];
+            System.arraycopy(genome, point0, pieces[x], 0, point1 - point0);
+            point0 = point1;
+            if (x >= pieces.length - 2)
+                point1 = genome.length;
+            else
+                point1 = points[x + 1];
+            }
+        }
+
+    /** Joins the n pieces and sets the genome to their concatenation. */
+    public void join(Object[] pieces)
+        {
+        int sum = 0;
+        for (int x = 0; x < pieces.length; x++)
+            sum += ((float[]) (pieces[x])).length;
+
+        int runningsum = 0;
+        float[] newgenome = new float[sum];
+        for (int x = 0; x < pieces.length; x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum,
+                ((float[]) (pieces[x])).length);
+            runningsum += ((float[]) (pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /**
+     * Destructively mutates the individual in some default manner. The default
+     * form simply randomizes genes to a uniform distribution from the min and
+     * max of the gene values. It can also add gaussian noise to the genes, 
+     * if so directed in the FloatVectorSpecies. If the gaussian noise
+     * pushes the gene out of range, a new noise value is generated.
+     * 
+     *  * @author Liviu Panait and Gabriel Balan
+     */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        if (!(s.mutationProbability > 0.0))
+            return;
+        boolean mutationIsBounded = s.mutationIsBounded;
+        MersenneTwisterFast rng = state.random[thread];
+
+        if (s.mutationType == FloatVectorSpecies.C_GAUSS_MUTATION)
+            {
+            for (int x = 0; x < genome.length; x++)
+                if (rng.nextBoolean(s.mutationProbability))
+                    {
+                    float val;
+                    float min = (float) s.minGene(x);
+                    float max = (float) s.maxGene(x);
+                    float stdev = (float)s.gaussMutationStdev;
+                    int outOfBoundsLeftOverTries = s.outOfBoundsRetries;
+                    boolean givingUpAllowed =  s.outOfBoundsRetries!=0;
+                    do
+                        {
+                        val = (float) (rng.nextGaussian() * stdev + genome[x]);
+                        outOfBoundsLeftOverTries--;
+                        if (mutationIsBounded && (val > max || val < min))
+                            {
+                            if(givingUpAllowed && (outOfBoundsLeftOverTries==0))
+                                {
+                                val = (float) (min + rng.nextFloat() * (max - min));
+                                s.outOfRangeRetryLimitReached(state);//it better get inlined
+                                break;
+                                }
+                            }
+                        else break;
+                        } while (true);
+                    genome[x] = val;
+                    }
+            }
+        else if (s.mutationType == FloatVectorSpecies.C_POLYNOMIAL_MUTATION)
+            {
+            polynomialMutate(state.random[thread], this, s.mutationDistributionIndex, s.polynomialIsAlternative, s.mutationIsBounded);
+            }
+        else
+            {// C_RESET_MUTATION
+            for (int x = 0; x < genome.length; x++)
+                if (rng.nextBoolean(s.mutationProbability))
+                    genome[x] = (float) ((float) s.minGene(x) + rng.nextFloat() * ((float) s.maxGene(x) - (float) s.minGene(x)));
+            }
+                        
+        }
+
+    /** This function is broken out to keep it identical to NSGA-II's mutation.c code. eta_m is the distribution
+        index.  */
+    public void polynomialMutate(MersenneTwisterFast random, FloatVectorIndividual individual, double eta_m, boolean alternativePolynomialVersion, boolean mutationIsBounded)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) individual.species;
+        float[] ind = individual.genome;
+        double[] min_realvar = s.minGenes;
+        double[] max_realvar = s.maxGenes;
+                
+        double rnd, delta1, delta2, mut_pow, deltaq;
+        double y, yl, yu, val, xy;
+        double y1;
+        for (int j=0; j < ind.length; j++)
+            {
+            if (random.nextBoolean(s.mutationProbability))
+                {
+                y1 = y = ind[j];
+                yl = min_realvar[j];
+                yu = max_realvar[j];
+                delta1 = (y-yl)/(yu-yl);
+                delta2 = (yu-y)/(yu-yl);
+
+                int totalTries = s.outOfBoundsRetries;
+                int tries = 0;
+                for(tries = 0; tries < totalTries || totalTries == 0; tries++)  // keep trying until totalTries is reached if it's not zero.  If it's zero, go on forever.
+                    {
+                    rnd = (random.nextDouble());
+                    mut_pow = 1.0/(eta_m+1.0);
+                    if (rnd <= 0.5)
+                        {
+                        xy = 1.0-delta1;
+                        val = 2.0*rnd + (alternativePolynomialVersion ? (1.0-2.0*rnd)*(Math.pow(xy,(eta_m+1.0))) : 0.0);
+                        deltaq =  Math.pow(val,mut_pow) - 1.0;
+                        }
+                    else
+                        {
+                        xy = 1.0-delta2;
+                        val = 2.0*(1.0-rnd) + (alternativePolynomialVersion ? 2.0*(rnd-0.5)*(Math.pow(xy,(eta_m+1.0))) : 0.0);
+                        deltaq = 1.0 - (Math.pow(val,mut_pow));
+                        }
+                    y1 = y + deltaq*(yu-yl);
+                    if (mutationIsBounded && (y1 >= yl && y1 <= yu)) break;  // yay, found one
+                    }
+                                        
+                // at this point, if tries is totalTries, we failed
+                if (totalTries != 0 && tries == totalTries)
+                    {
+                    // just randomize
+                    y1 = (float)(min_realvar[j] + random.nextFloat() * (max_realvar[j] - min_realvar[j]));
+                    }
+                ind[j] = (float) y1;
+                }
+            }
+                        
+        }
+
+
+    /**
+     * Initializes the individual by randomly choosing floats uniformly from
+     * mingene to maxgene.
+     */
+    public void reset(EvolutionState state, int thread)
+        {
+        FloatVectorSpecies s = (FloatVectorSpecies) species;
+        for (int x = 0; x < genome.length; x++)
+            genome[x] = (float) ((float) s.minGene(x) + state.random[thread]
+                .nextFloat()
+                * ((float) s.maxGene(x) - (float) s.minGene(x)));
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual. It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = (hash << 1 | hash >>> 31);
+        for (int x = 0; x < genome.length; x++)
+            hash = (hash << 1 | hash >>> 31) ^ Float.floatToIntBits(genome[x]);
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for (int i = 0; i < genome.length; i++)
+            s = s + " " + genome[i];
+        return s;
+        }
+
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append(Code.encode(genome.length));
+        for (int i = 0; i < genome.length; i++)
+            s.append(Code.encode(genome[i]));
+        return s.toString();
+        }
+
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line. The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode(d);
+        int lll = (int) (d.l);
+
+        genome = new float[lll];
+
+        // read in the genes
+        for (int i = 0; i < genome.length; i++)
+            {
+            Code.decode(d);
+            genome[i] = (float) (d.d);
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass())))
+            return false; // SimpleRuleIndividuals are special.
+        FloatVectorIndividual i = (FloatVectorIndividual) ind;
+        if (genome.length != i.genome.length)
+            return false;
+        for (int j = 0; j < genome.length; j++)
+            if (genome[j] != i.genome[j])
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        {
+        return genome;
+        }
+
+    public void setGenome(Object gen)
+        {
+        genome = (float[]) gen;
+        }
+
+    public int genomeLength()
+        {
+        return genome.length;
+        }
+
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for (int x = 0; x < genome.length; x++)
+            dataOutput.writeFloat(genome[x]);
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome == null || genome.length != len)
+            genome = new float[len];
+        for (int x = 0; x < genome.length; x++)
+            genome[x] = dataInput.readFloat();
+        }
+
+    /** Clips each gene value to be within its specified [min,max] range.  
+        NaN is presently considered in range but the behavior of this method
+        should be assumed to be unspecified on encountering NaN. */
+    public void clamp() 
+        {
+        FloatVectorSpecies _species = (FloatVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            {
+            float minGene = (float)_species.minGene(i);
+            if (genome[i] < minGene)
+                genome[i] = minGene;
+            else 
+                {
+                float maxGene = (float)_species.maxGene(i);
+                if (genome[i] > maxGene)
+                    genome[i] = maxGene;
+                }
+            }
+        }
+                
+    public void setGenomeLength(int len)
+        {
+        float[] newGenome = new float[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    /** Returns true if each gene value is within is specified [min,max] range.
+        NaN is presently considered in range but the behavior of this method
+        should be assumed to be unspecified on encountering NaN. */
+    public boolean isInRange() 
+        {
+        FloatVectorSpecies _species = (FloatVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            if (genome[i] < _species.minGene(i) ||
+                genome[i] > _species.maxGene(i)) return false;
+        return true;
+        }
+
+    public double distanceTo(Individual otherInd)
+        { 
+        if (!(otherInd instanceof FloatVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        FloatVectorIndividual other = (FloatVectorIndividual) otherInd;
+        float[] otherGenome = other.genome;
+        double sumSquaredDistance =0.0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            double dist = this.genome[i] - otherGenome[i];
+            sumSquaredDistance += dist*dist;
+            }
+        return StrictMath.sqrt(sumSquaredDistance);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorSpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorSpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorSpecies.java	(revision 6152)
@@ -0,0 +1,804 @@
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+
+/* 
+ * FloatVectorSpecies.java
+ * 
+ * Created: Tue Feb 20 13:26:00 2001
+ * By: Sean Luke
+ */
+
+/**
+ * FloatVectorSpecies is a subclass of VectorSpecies with special
+ * constraints for floating-point vectors, namely FloatVectorIndividual and
+ * DoubleVectorIndividual.
+ *
+ * <p>FloatVectorSpecies can specify min/max numeric constraints on gene values
+ * in three different ways.
+ *
+ * <ol>
+ * <li> You may provide a default min and max value.
+ *      This is done by specifying:
+ *      <p><i>base</i>.<tt>min-gene</tt>
+ *      <br><i>base</i>.<tt>max-gene</tt>
+ *      <p><i>Note:</i> you <b>must</b> provide these values even if you don't use them,
+ *      as they're used as defaults by #2 and #3 below.
+ *<p>
+ * <li> You may provide min and max values for genes in segments (regions) along
+ *      the genome.  This is done by specifying:
+ *      <p><i>base</i>.<tt>num-segments</tt>
+ *      The segments may be defined by either start or end indices of genes. 
+ *      This is controlled by specifying the value of:
+ *      <p><i>base</i>.<tt>segment-type</tt>
+ *      which can assume the value of start or end, with start being the default.
+ *      The indices are defined using Java array style, i.e. the first gene has the index of 0, 
+ *      and the last gene has the index of genome-size - 1.
+ *      <p>Using this method, each segment is specified by<i>j</i>...
+ *      <p><i>base</i>.<tt>segment.</tt><i>j</i><tt>.start</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.min-gene</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.max-gene</tt>
+ *      if segment-type value was chosen as start or by:
+ *      <p><i>base</i>.<tt>segment.</tt><i>j</i><tt>.end</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.min-gene</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.max-gene</tt>
+ *      if segment-type value is equal to end.
+ *<p>
+ * <li> You may provide min and max values for each separate gene.  
+ *      This is done by specifying (for each gene location <i>i</i> you wish to specify)
+ *      <p><i>base</i>.<tt>min-gene</tt>.<i>i</i>
+ *      <br><i>basn</i>.<tt>max-gene</tt>.<i>i</i>
+ * </ol>
+ * 
+ * <p>Any settings for #3 override #2, and both override #1. 
+ *
+ * <p>
+ * FloatVectorSpecies provides support for three ways of mutating a gene:
+ * <ul>
+ * <li>replacing the gene's value with a value uniformly-drawn from the gene's
+ * range (the default behavior, legacy from the previous versions).</li>
+ * <li>perturbing the gene's value with gaussian noise; if the gene-by-gene range 
+ * is used, than the standard deviation is scaled to reflect each gene's range. 
+ * If the gaussian mutation's standard deviation is too large for the range,
+ * than there's a large probability the mutated value will land outside range.
+ * We will try again a number of times (100) before giving up and using the 
+ * previous mutation method.</li>
+ * <li>perturbing the gene's value with noise chosen from a <i>polynomial distribution</i>,
+ * similar to the gaussian distribution.  The polynomial distribution was popularized
+ * by Kalyanmoy Deb and is found in many of his publications (see http://www.iitk.ac.in/kangal/deb.shtml).
+ * The polynomial distribution has two options.  First, there is the <i>index</i>.  This
+ * variable defines the shape of the distribution and is in some sense the equivalent of the
+ * standard deviation in the gaussian distribution.  The index is an integer.  If it is zero,
+ * the polynomial distribution is simply the uniform distribution from [1,-1].  If it is 1, the
+ * polynomial distribution is basically a triangular distribution from [1,-1] peaking at 0.  If
+ * it is 2, the polynomial distribution follows a squared function, again peaking at 0.  Larger
+ * values result in even more peaking and narrowness.  The default values used in nearly all of
+ * the NSGA-II and Deb work is 20.  Second, there is whether or not the value is intended for
+ * <i>bounded</i> genes.  The default polynomial distribution is used when we assume the gene can
+ * take on literally any value, even beyond the min and max values.  For genes which are restricted
+ * to be between min and max, there is an alternative version of the polynomial distribution, used by
+ * Deb's team but not discussed much in the literature, desiged for that situation.  We assume boundedness
+ * by default, and have found it to be somewhat better for NSGA-II and SPEA2 problems.  For a description
+ * of this alternative version, see "A Niched-Penalty Approach for Constraint Handling in Genetic Algorithms"
+ * by Kalyanmoy Deb and Samir Agrawal.  Deb's default implementation bounds the result to min or max;
+ * instead ECJ's implementation of the polynomial distribution retries until it finds a legal value.  This
+ * will be just fine for ranges like [0,1], but for smaller ranges you may be waiting a long time.
+ * </ul>
+ * 
+ * 
+ * <p>
+ * <b>Parameters</b><br>
+ * <table>
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>min-gene</tt><br>
+ * <font size=-1>double (default=0.0)</font></td>
+ * <td valign=top>(the minimum gene value)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>max-gene</tt><br>
+ * <font size=-1>double &gt;= <i>base</i>.min-gene</font></td>
+ * <td valign=top>(the maximum gene value)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>min-gene</tt>.<i>i</i><br>
+ * <font size=-1>double (default=<i>base</i>.<tt>min-gene</tt>)</font></td>
+ * <td valign=top>(the minimum gene value for gene <i>i</i>)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>max-gene</tt>.<i>i</i><br>
+ * <font size=-1>double &gt;= <i>base</i>.min-gene.<i>i</i> (default=<i>base</i>.<tt>max-gene</tt>)</font></td>
+ * <td valign=top>(the maximum gene value for gene <i>i</i>)</td>
+ * </tr>
+ * 
+ * <tr><td valign=top><i>base.</i>.<tt>num-segments</tt><br>
+ * <font size=-1>int &gt;= 1 (default=no segments used)</font></td>
+ * <td valign=top>(the number of gene segments defined)</td>
+ * </tr>
+ * 
+ * <tr><td valign=top><i>base.</i>.<tt>segment-type</tt><br>
+ * <font size=-1>start (default) or end</font></td>
+ * <td valign=top>(defines the way in which segments are defined: either by providing start indices (segment-type=start) or by providing end indices (segment-type=end)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>start</tt><br>
+ * <font size=-1>0 &lt;= int &lt; genome length</font></td>
+ * <td valign=top>(the start index of gene segment <i>j</i> -- the end of a segment is before the start of the next segment)</td>
+ * <td valign=top>(used when the value of segment-type parameter is equal to start)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>end</tt><br>
+ * <font size=-1>0 &lt;= int &lt; genome length</font></td>
+ * <td valign=top>(the end of gene segment <i>j</i> -- the start of a segment is after the end of the previous segment)</td>
+ * <td valign=top>(used when the value of segment-type parameter is equal to end)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>min-gene</tt><br>
+ * <font size=-1>double (default=0.0)</font></td>
+ * <td valign=top>(the minimum gene value for segment <i>j</i>)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>max-gene</tt><br>
+ * <font size=-1>double &gt;= <i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>min-gene</tt></td>
+ * <td valign=top>(the maximum gene value for segment <i>j</i>)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>mutation-type</tt><br>
+ * <font size=-1><tt>reset</tt>, <tt>gauss</tt>, or <tt>polynomial</tt> (default=<tt>reset</tt>)</font></td>
+ * <td valign=top>(the mutation type)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>mutation-stdev</tt><br>
+ * <font size=-1>double &ge; 0</font></td>
+ * <td valign=top>(the standard deviation or the gauss perturbation)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>out-of-bounds-retries</tt><br>
+ *  <font size=-1>int &ge; 0 (default=100)</font></td>
+ *  <td valign=top>(number of times the gaussian mutation got the gene out of range 
+ *  before we give up and reset the gene's value; 0 means "never give up")</td>
+ * </tr>
+ *
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>distribution-index</tt><br>
+ * <font size=-1>int &ge; 0</font></td>
+ * <td valign=top>(the mutation distribution index for the polynomial mutation distribution)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>alternative-polynomial-version</tt><br>
+ *  <font size=-1>boolean (default=true)</font></td>
+ *  <td valign=top>(whether to use the "bounded" variation of the polynomial mutation or the standard ("unbounded") version)</td>
+ * </tr>
+ * 
+ * <tr>
+ * <td valign=top><i>base</i>.<tt>mutation-bounded</tt><br>
+ *  <font size=-1>boolean (default=true)</font></td>
+ *  <td valign=top>(whether mutation is restricted to only being within the min/max gene values.  Does not apply to SimulatedBinaryCrossover (which is always bounded))</td>
+ * </tr>
+ * 
+ * </table>
+ * @author Sean Luke, Gabriel Balan, Rafal Kicinger
+ * @version 2.0
+ */
+public class FloatVectorSpecies extends VectorSpecies
+    {
+    public final static String P_MINGENE = "min-gene";
+
+    public final static String P_MAXGENE = "max-gene";
+
+    public final static String P_MUTATIONTYPE = "mutation-type";
+
+    public final static String P_STDEV = "mutation-stdev";
+
+    public final static String P_MUTATION_DISTRIBUTION_INDEX = "mutation-distribution-index";
+
+    public final static String P_POLYNOMIAL_ALTERNATIVE = "alternative-polynomial-version";
+
+    public final static String V_RESET_MUTATION = "reset";
+
+    public final static String V_GAUSS_MUTATION = "gauss";
+
+    public final static String V_POLYNOMIAL_MUTATION = "polynomial";
+
+    public final static String P_OUTOFBOUNDS_RETRIES = "out-of-bounds-retries";
+
+    public final static String P_NUM_SEGMENTS = "num-segments";
+        
+    public final static String P_SEGMENT_TYPE = "segment-type";
+
+    public final static String P_SEGMENT_START = "start";
+        
+    public final static String P_SEGMENT_END = "end";
+
+    public final static String P_SEGMENT = "segment";
+
+    public final static String P_MUTATION_BOUNDED = "mutation-bounded";
+
+    public final static int C_RESET_MUTATION = 0;
+
+    public final static int C_GAUSS_MUTATION = 1;
+
+    public final static int C_POLYNOMIAL_MUTATION = 2;
+
+    public double[] minGenes;
+    public double[] maxGenes;
+
+    /** What kind of mutation do we have? */
+    public int mutationType;
+        
+    public double gaussMutationStdev;
+    public boolean mutationIsBounded;
+
+    public int outOfBoundsRetries=100;
+        
+    public int mutationDistributionIndex;
+    public boolean polynomialIsAlternative;
+
+    static final double SIMULATED_BINARY_CROSSOVER_EPS = 1.0e-14;   
+
+    private boolean outOfBoundsRetriesWarningPrinted = false;
+    public void outOfRangeRetryLimitReached(EvolutionState state)
+        {
+        if(!outOfBoundsRetriesWarningPrinted)
+            {
+            outOfBoundsRetriesWarningPrinted=true;
+            state.output.warning(
+                "The limit of 'out-of-range' retries for gaussian mutation was reached.");
+            }
+        }
+    
+    public double maxGene(int gene)
+        {
+        double[] m = maxGenes;
+        if (m.length <= gene)
+            { 
+            if (!dynamicInitialSize && !warned) warnAboutGene(gene);
+            gene = m.length - 1;
+            }
+        return m[gene];
+        }
+
+    public double minGene(int gene)
+        {
+        double[] m = minGenes;
+        if (m.length <= gene)
+            { 
+            if (!dynamicInitialSize && !warned) warnAboutGene(gene);
+            gene = m.length - 1;
+            }
+        return m[gene];
+        }
+
+    public boolean inNumericalTypeRange(double geneVal)
+        {
+        if (i_prototype instanceof FloatVectorIndividual)
+            return (geneVal <= Float.MAX_VALUE && geneVal >= -Float.MAX_VALUE);
+        else if (i_prototype instanceof DoubleVectorIndividual)
+            return true; // geneVal is valid for all double
+        else
+            return false; // dunno what the individual is...
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base);
+
+        Parameter def = defaultBase();
+
+        // create the arrays
+        minGenes = new double[genomeSize];
+        maxGenes = new double[genomeSize];
+
+
+
+        // LOADING GLOBAL MIN/MAX GENES
+        double minGene = state.parameters.getDoubleWithDefault(base.push(P_MINGENE), def.push(P_MINGENE), 0);
+        double maxGene = state.parameters.getDouble(base.push(P_MAXGENE), def.push(P_MAXGENE), minGene);
+        if (maxGene < minGene)
+            state.output.fatal("FloatVectorSpecies must have a default min-gene which is <= the default max-gene",
+                base.push(P_MAXGENE), def.push(P_MAXGENE));
+        
+        for (int x = 0; x < genomeSize; x++)
+            {
+            minGenes[x] = minGene;
+            maxGenes[x] = maxGene;
+            }
+
+        
+        // LOADING SEGMENTS
+        
+        
+        //Set number of segments to 0 by default
+        int numSegments = 0;
+        // Now check to see if segments of genes (genes having the same min and
+        // max values) exist
+        if (state.parameters.exists(base.push(P_NUM_SEGMENTS), def.push(P_NUM_SEGMENTS)))
+            {
+            if (dynamicInitialSize)
+                state.output.warnOnce("Using dynamic initial sizing, but per-segment min/max gene declarations.  This is probably wrong.  You probably want to use global min/max declarations.",
+                    base.push(P_NUM_SEGMENTS), def.push(P_NUM_SEGMENTS));
+                        
+            numSegments = state.parameters.getIntWithDefault(base.push(P_NUM_SEGMENTS), 
+                def.push(P_NUM_SEGMENTS), 0);
+                        
+            if(numSegments == 0)
+                state.output.warning(
+                    "The number of genome segments has been defined to be equal to 0.\n"
+                    + "Hence, no genome segments will be defined.", 
+                    base.push(P_NUM_SEGMENTS), 
+                    def.push(P_NUM_SEGMENTS));
+            else if(numSegments < 0)
+                state.output.fatal(
+                    "Invalid number of genome segments: " + numSegments
+                    + "\nIt must be a nonnegative value.", 
+                    base.push(P_NUM_SEGMENTS), 
+                    def.push(P_NUM_SEGMENTS));
+                                                        
+            //read the type of segment definition using the default start value
+            String segmentType = state.parameters.getStringWithDefault(base.push(P_SEGMENT_TYPE), 
+                def.push(P_SEGMENT_TYPE), P_SEGMENT_START);
+                        
+            if(segmentType.equalsIgnoreCase(P_SEGMENT_START))
+                initializeGenomeSegmentsByStartIndices(state, base, def, numSegments, minGene, maxGene);
+            else if(segmentType.equalsIgnoreCase(P_SEGMENT_END))
+                initializeGenomeSegmentsByEndIndices(state, base, def, numSegments, minGene, maxGene);
+            else
+                state.output.fatal(
+                    "Invalid specification of genome segment type: " + segmentType
+                    + "\nThe " + P_SEGMENT_TYPE + " parameter must have the value of " + P_SEGMENT_START + " or " + P_SEGMENT_END, 
+                    base.push(P_SEGMENT_TYPE), 
+                    def.push(P_SEGMENT_TYPE));
+
+
+            }
+            
+            
+            
+        // LOADING PER-GENE VALUES
+
+        boolean foundStuff = false;
+        boolean warnedMin = false;
+        boolean warnedMax = false;
+        for (int x = 0; x < genomeSize; x++)
+            {
+            if (!state.parameters.exists(base.push(P_MINGENE).push("" + x), def.push(P_MINGENE).push("" + x)))
+                {
+                if (foundStuff && !warnedMin)
+                    {
+                    state.output.warning(
+                        "FloatVectorSpecies has missing min-gene values for some genes.\n"
+                        + "The first one is gene #" + x + ".",
+                        base.push(P_MINGENE).push("" + x), def.push(P_MINGENE).push("" + x));
+                    warnedMin = true;
+                    }
+                } 
+            else
+                {
+                if (dynamicInitialSize)
+                    state.output.warnOnce("Using dynamic initial sizing, but per-gene min/max gene declarations.  This is probably wrong.  You probably want to use global min/max declarations.",
+                        base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x));
+
+                minGenes[x] = state.parameters.getDoubleWithDefault(base.push(P_MINGENE).push("" + x), 
+                    def.push(P_MINGENE).push("" + x), minGene);
+                foundStuff = true;
+                }
+
+            if (!state.parameters.exists(base.push(P_MAXGENE).push("" + x), def.push(P_MAXGENE).push("" + x)))
+                {
+                if (foundStuff && !warnedMax)
+                    {
+                    state.output.warning(
+                        "FloatVectorSpecies has missing max-gene values for some genes.\n"
+                        + "The first one is gene #" + x + ".",
+                        base.push(P_MAXGENE).push("" + x), def.push(P_MAXGENE).push("" + x));
+                    warnedMax = true;
+                    }
+                } 
+            else
+                {
+                if (dynamicInitialSize)
+                    state.output.warnOnce("Using dynamic initial sizing, but per-gene min/max gene declarations.  This is probably wrong.  You probably want to use global min/max declarations.",
+                        base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x));
+
+                maxGenes[x] = state.parameters.getDoubleWithDefault(base.push(P_MAXGENE).push("" + x), 
+                    def.push(P_MAXGENE).push("" + x), maxGene);
+                foundStuff = true;
+                }
+            }
+                    
+            
+            
+
+
+            
+        // VERIFY
+        for(int x=0 ; x < genomeSize; x++)
+            {
+            if (maxGenes[x] != maxGenes[x])  // uh oh, NaN
+                state.output.fatal("FloatVectorSpecies found that max-gene[" + x + "] is NaN");
+
+            if (minGenes[x] != minGenes[x])  // uh oh, NaN
+                state.output.fatal("FloatVectorSpecies found that min-gene[" + x + "] is NaN");
+
+            if (maxGenes[x] < minGenes[x])
+                state.output.fatal("FloatVectorSpecies must have a min-gene[" + x + "] which is <= the max-gene[" + x + "]");
+
+            // check to see if these longs are within the data type of the particular individual
+            if (!inNumericalTypeRange(minGenes[x]))
+                state.output.fatal("This FloatvectorSpecies has a prototype of the kind: "
+                    + i_prototype.getClass().getName()
+                    + ", but doesn't have a min-gene["
+                    + x
+                    + "] value within the range of this prototype's genome's data types");
+            if (!inNumericalTypeRange(maxGenes[x]))
+                state.output.fatal("This FloatvectorSpecies has a prototype of the kind: "
+                    + i_prototype.getClass().getName()
+                    + ", but doesn't have a max-gene["
+                    + x
+                    + "] value within the range of this prototype's genome's data types");
+            }
+
+        
+        
+        
+        
+        /// MUTATION
+        
+
+        mutationIsBounded = state.parameters.getBoolean(base.push(P_MUTATION_BOUNDED), def.push(P_MUTATION_BOUNDED), true);
+        String mtype = state.parameters.getStringWithDefault(base.push(P_MUTATIONTYPE), def.push(P_MUTATIONTYPE), null);
+        mutationType = C_RESET_MUTATION;
+        if (mtype == null)
+            state.output.warning("No mutation type given for FloatVectorSpecies, assuming 'reset' mutation",
+                base.push(P_MUTATIONTYPE), def.push(P_MUTATIONTYPE));
+        else if (mtype.equalsIgnoreCase(V_RESET_MUTATION))
+            mutationType = C_RESET_MUTATION; // redundant
+        else if (mtype.equalsIgnoreCase(V_POLYNOMIAL_MUTATION))
+            mutationType = C_POLYNOMIAL_MUTATION; // redundant
+        else if (mtype.equalsIgnoreCase(V_GAUSS_MUTATION))
+            mutationType = C_GAUSS_MUTATION;
+        else
+            state.output.fatal("FloatVectorSpecies given a bad mutation type: "
+                + mtype, base.push(P_MUTATIONTYPE), def.push(P_MUTATIONTYPE));
+
+        if (mutationType == C_POLYNOMIAL_MUTATION)
+            {
+            mutationDistributionIndex = state.parameters.getInt(base.push(P_MUTATION_DISTRIBUTION_INDEX), def.push(P_MUTATION_DISTRIBUTION_INDEX), 0);
+            if (mutationDistributionIndex < 0)
+                state.output.fatal("If FloatVectorSpecies is going to use polynomial mutation, the distribution index must be defined and >= 0.",
+                    base.push(P_MUTATION_DISTRIBUTION_INDEX), def.push(P_MUTATION_DISTRIBUTION_INDEX));
+            polynomialIsAlternative = state.parameters.getBoolean(base.push(P_POLYNOMIAL_ALTERNATIVE), def.push(P_POLYNOMIAL_ALTERNATIVE), true);
+
+            outOfBoundsRetries = state.parameters.getIntWithDefault(base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES), outOfBoundsRetries);
+            if(outOfBoundsRetries<0)
+                {
+                state.output.fatal(
+                    "If it's going to use polynomial mutation, FloatvectorSpecies must have a positive number of out-of-bounds retries or 0 (for don't give up).  " +
+                    "This is even the case if doing so-called \"bounded\" polynomial mutation, which auto-bounds anyway, or if the mutation is unbounded.  " + 
+                    "In either case, just provide an arbitrary value, which will be ignored.",
+                    base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES));
+                }
+            }
+                
+        if (mutationType == C_GAUSS_MUTATION)
+            {
+            gaussMutationStdev = state.parameters.getDouble(base.push(P_STDEV),def.push(P_STDEV), 0);
+            if (gaussMutationStdev <= 0)
+                state.output.fatal("If it's going to use gaussian mutation, FloatvectorSpecies must have a strictly positive standard deviation",
+                    base.push(P_STDEV), def.push(P_STDEV));
+                        
+            outOfBoundsRetries = state.parameters.getIntWithDefault(base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES), outOfBoundsRetries);
+            if(outOfBoundsRetries<0)
+                {
+                state.output.fatal(
+                    "If it's going to use gaussian mutation, FloatvectorSpecies must have a positive number of out-of-bounds retries or 0 (for don't give up).  " +
+                    "This is even the case if the mutation is unbounded.  In that case, just provide an arbitrary value, which will be ignored.",
+                    base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES));
+                }
+            }           
+        /*
+        //Debugging
+        for(int i = 0; i < minGenes.length; i++)
+        System.out.println("Min: " + minGenes[i] + ", Max: " + maxGenes[i]);
+        */
+        }
+        
+        
+    private void initializeGenomeSegmentsByStartIndices(final EvolutionState state, 
+        final Parameter base, 
+        final Parameter def,
+        int numSegments,
+        double minGene, double maxGene)
+        {
+        boolean warnedMin = false;
+        boolean warnedMax = false;
+        double currentSegmentMinGeneValue = Double.MAX_VALUE;
+        double currentSegmentMaxGeneValue = Double.MIN_VALUE;
+                
+        //loop in reverse order 
+        int previousSegmentEnd = genomeSize;
+        int currentSegmentEnd = 0;
+                
+        for (int i = numSegments - 1; i >= 0; i--)
+            {
+            //check if the segment data exist
+            if (state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), 
+                    def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START)))
+                {
+                //Read the index of the end gene specifying current segment
+                currentSegmentEnd = state.parameters.getInt(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), 
+                    def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START));
+                                
+                }
+            else
+                {
+                state.output.fatal("Genome segment " + i + " has not been defined!" +
+                    "\nYou must specify start indices for " + numSegments + " segment(s)", 
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START),
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START));
+                }
+                        
+            //check if the start index is valid
+            if(currentSegmentEnd >= previousSegmentEnd || currentSegmentEnd < 0)
+                state.output.fatal(
+                    "Invalid start index value for segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be smaller than " + previousSegmentEnd +
+                    " and greater than or equal to  " + 0);
+                        
+            //check if the index of the first segment is equal to 0
+            if(i == 0 && currentSegmentEnd != 0)
+                state.output.fatal(
+                    "Invalid start index value for the first segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be equal to " + 0);
+                        
+                        
+            //get min and max values of genes in this segment
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE)))
+                {
+                if (!warnedMin)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing min-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMin = true;
+                    }
+                                
+                //the min-gene value has not been defined for this segment so assume the global min value
+                currentSegmentMinGeneValue = minGene;
+                }
+            else  //get the min value for this segment
+                {
+                currentSegmentMinGeneValue = state.parameters.getDoubleWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    minGene);
+                                
+                //check if the value is in range
+                if (!inNumericalTypeRange(currentSegmentMinGeneValue))
+                    state.output
+                        .error(
+                            "This IntegerVectorSpecies has a prototype of the kind: "
+                            + i_prototype.getClass()
+                            .getName()
+                            + ", but doesn't have a min-gene "
+                            + " value for segment " + i
+                            + " within the range of this prototype's genome's data types",
+                            base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                            base.push(P_SEGMENT).push(""+i).push(P_MINGENE));
+                                
+                }
+                        
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)))
+                {
+                if (!warnedMax)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing max-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMax = true;
+                    }
+                                
+                //the max-gen value has not been defined for this segment so assume the global max value
+                currentSegmentMaxGeneValue = maxGene;
+                                
+                }
+            else   //get the max value for this segment
+                {
+                currentSegmentMaxGeneValue = state.parameters.getDoubleWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    maxGene);
+                                
+                //check if the value is in range
+                if (!inNumericalTypeRange(currentSegmentMaxGeneValue))
+                    state.output
+                        .fatal(
+                            "This IntegerVectorSpecies has a prototype of the kind: "
+                            + i_prototype.getClass()
+                            .getName()
+                            + ", but doesn't have a max-gene "
+                            + " value for segment " + i
+                            + " within the range of this prototype's genome's data types",
+                            base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                            base.push(P_SEGMENT).push(""+i).push(P_MAXGENE));
+                }
+
+            //check is min is smaller than or equal to max
+            if (currentSegmentMaxGeneValue < currentSegmentMinGeneValue)
+                state.output.fatal(
+                    "IntegerVectorSpecies must have a min-gene value for segment "
+                    + i + " which is <= the max-gene value", 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE));
+
+                        
+            //and assign min and max values for all genes in this segment
+            for(int j = previousSegmentEnd-1; j >= currentSegmentEnd; j--)
+                {
+                minGenes[j] = currentSegmentMinGeneValue;
+                maxGenes[j] = currentSegmentMaxGeneValue;
+                }
+                        
+            previousSegmentEnd = currentSegmentEnd;
+                        
+            }
+                
+        }
+        
+    private void initializeGenomeSegmentsByEndIndices(final EvolutionState state, 
+        final Parameter base, 
+        final Parameter def,
+        int numSegments,
+        double minGene, double maxGene)
+        {
+        boolean warnedMin = false;
+        boolean warnedMax = false;
+        double currentSegmentMinGeneValue = Double.MAX_VALUE;
+        double currentSegmentMaxGeneValue = Double.MIN_VALUE;
+                
+        int previousSegmentEnd = -1;  
+        int currentSegmentEnd = 0;
+        // iterate over segments and set genes values for each segment
+        for (int i = 0; i < numSegments; i++)
+            {
+            //check if the segment data exist
+            if (state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END)))
+                {
+                //Read the index of the end gene specifying current segment
+                currentSegmentEnd = state.parameters.getInt(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), 
+                    def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END));
+                                
+                }
+            else
+                {
+                state.output.fatal("Genome segment " + i + " has not been defined!" +
+                    "\nYou must specify end indices for " + numSegments + " segment(s)", 
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END),
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END));
+                }
+                        
+            //check if the end index is valid
+            if(currentSegmentEnd <= previousSegmentEnd || currentSegmentEnd >= genomeSize)
+                state.output.fatal(
+                    "Invalid end index value for segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be greater than " + previousSegmentEnd +
+                    " and smaller than " + genomeSize);
+                        
+            //check if the index of the final segment is equal to the genomeSize
+            if(i == numSegments - 1 && currentSegmentEnd != (genomeSize-1))
+                state.output.fatal(
+                    "Invalid end index value for the last segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be equal to the index of the last gene in the genome:  " + (genomeSize-1));
+                        
+                        
+            //get min and max values of genes in this segment
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE)))
+                {
+                if (!warnedMin)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing min-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMin = true;
+                    }
+                                
+                //the min-gene value has not been defined for this segment so assume the global min value
+                currentSegmentMinGeneValue = minGene;
+                }
+            else  //get the min value for this segment
+                {
+                currentSegmentMinGeneValue = state.parameters.getDoubleWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    minGene);
+                                
+                //check if the value is in range
+                if (!inNumericalTypeRange(currentSegmentMinGeneValue))
+                    state.output
+                        .error(
+                            "This IntegerVectorSpecies has a prototype of the kind: "
+                            + i_prototype.getClass()
+                            .getName()
+                            + ", but doesn't have a min-gene "
+                            + " value for segment " + i
+                            + " within the range of this prototype's genome's data types",
+                            base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                            base.push(P_SEGMENT).push(""+i).push(P_MINGENE));
+                                
+                }
+                        
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)))
+                {
+                if (!warnedMax)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing max-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMax = true;
+                    }
+                                
+                //the max-gen value has not been defined for this segment so assume the global max value
+                currentSegmentMaxGeneValue = maxGene;
+                                
+                }
+            else   //get the max value for this segment
+                {
+                currentSegmentMaxGeneValue = state.parameters.getDoubleWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    maxGene);
+                                
+                //check if the value is in range
+                if (!inNumericalTypeRange(currentSegmentMaxGeneValue))
+                    state.output
+                        .fatal(
+                            "This IntegerVectorSpecies has a prototype of the kind: "
+                            + i_prototype.getClass()
+                            .getName()
+                            + ", but doesn't have a max-gene "
+                            + " value for segment " + i
+                            + " within the range of this prototype's genome's data types",
+                            base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                            base.push(P_SEGMENT).push(""+i).push(P_MAXGENE));
+                }
+
+            //check is min is smaller than or equal to max
+            if (currentSegmentMaxGeneValue < currentSegmentMinGeneValue)
+                state.output.fatal(
+                    "IntegerVectorSpecies must have a min-gene value for segment "
+                    + i + " which is <= the max-gene value", 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE));
+
+                        
+            //and assign min and max values for all genes in this segment
+            for(int j = previousSegmentEnd+1; j <= currentSegmentEnd; j++)
+                {
+                minGenes[j] = currentSegmentMinGeneValue;
+                maxGenes[j] = currentSegmentMaxGeneValue;
+                }
+                        
+            previousSegmentEnd = currentSegmentEnd;
+                        
+            }
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/GeneVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/GeneVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/GeneVectorIndividual.java	(revision 6152)
@@ -0,0 +1,329 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * GeneVectorIndividual.java
+ * Created: Thu Mar 22 13:13:20 EST 2001
+ */
+
+/**
+ * GeneVectorIndividual is a VectorIndividual whose genome is an array of VectorGenes.
+ * The default mutation method calls the mutate() method on each gene independently
+ * with <tt>species.mutationProbability</tt>.  Initialization calls reset(), which
+ * should call reset() on each gene.  Do not expect that the genes will actually
+ * exist during initialization -- see the default implementation of reset() as an example
+ * for how to handle this.
+ *
+
+ * <P><b>From ec.Individual:</b>  
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+ <p><b>Default Base</b><br>
+ vector.gene-vect-ind
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class GeneVectorIndividual extends VectorIndividual
+    {
+    public static final String P_GENEVECTORINDIVIDUAL = "gene-vect-ind";
+    public VectorGene[] genome;
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_GENEVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        GeneVectorIndividual myobj = (GeneVectorIndividual) (super.clone());
+
+        // must clone the genome
+        myobj.genome = (VectorGene[])(genome.clone());
+        for(int x=0;x<genome.length;x++)
+            myobj.genome[x] = (VectorGene)(genome[x].clone());
+        
+        return myobj;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+
+        // since VectorSpecies set its constraint values BEFORE it called
+        // super.setup(...) [which in turn called our setup(...)], we know that
+        // stuff like genomeSize has already been set...
+        
+        Parameter def = defaultBase();
+        
+        if (!(species instanceof GeneVectorSpecies)) 
+            state.output.fatal("GeneVectorIndividual requires a GeneVectorSpecies", base, def);
+        GeneVectorSpecies s = (GeneVectorSpecies) species;
+        
+        // note that genome isn't initialized with any genes yet -- they're all null.
+        // reset() needs
+        genome = new VectorGene[s.genomeSize];
+        reset(state,0);
+        }
+        
+    public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
+        {
+        GeneVectorSpecies s = (GeneVectorSpecies) species;
+        GeneVectorIndividual i = (GeneVectorIndividual) ind;
+        VectorGene tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output.fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch(s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                for(int x=0;x<point*s.chunksize;x++)
+                    { 
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x]; 
+                    genome[x] = tmp; 
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT: 
+                int point0 = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                if (point0 > point) { int p = point0; point0 = point; point = p; }
+                for(int x=point0*s.chunksize;x<point*s.chunksize;x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for(int x=0;x<genome.length/s.chunksize;x++) 
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for(int y=x*s.chunksize;y<(x+1)*s.chunksize;y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            }
+        }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0; point1 = points[0];
+        for(int x=0;x<pieces.length;x++)
+            {
+            pieces[x] = new VectorGene[point1-point0];
+            System.arraycopy(genome,point0,pieces[x],0,point1-point0);
+            point0 = point1;
+            if (x >=pieces.length-2)
+                point1 = genome.length;
+            else point1 = points[x+1];
+            }
+        }
+    
+    /** Joins the n pieces and sets the genome to their concatenation.*/
+    public void join(Object[] pieces)
+        {
+        int sum=0;
+        for(int x=0;x<pieces.length;x++)
+            sum += ((VectorGene[])(pieces[x])).length;
+        
+        int runningsum = 0;
+        VectorGene[] newgenome = new VectorGene[sum];
+        for(int x=0;x<pieces.length;x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum, ((VectorGene[])(pieces[x])).length);
+            runningsum += ((VectorGene[])(pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /** Destructively mutates the individual in some default manner.  The default form
+        simply randomizes genes to a uniform distribution from the min and max of the gene values. */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        GeneVectorSpecies s = (GeneVectorSpecies) species;
+        if (s.mutationProbability>0.0)
+            for(int x=0;x<genome.length;x++)
+                if (state.random[thread].nextBoolean(s.mutationProbability))
+                    genome[x].mutate(state,thread);
+        }
+
+    /** Initializes the individual by calling reset(...) on each gene. */
+    public void reset(EvolutionState state, int thread)
+        {
+        GeneVectorSpecies s = (GeneVectorSpecies) species;
+
+        for(int x=0;x<genome.length;x++)
+            {
+            // first create the gene if it doesn't exist
+            if (genome[x]==null) genome[x] = (VectorGene)(s.genePrototype.clone());
+            // now reset it
+            genome[x].reset(state,thread);
+            }
+
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        for(int x=0;x<genome.length;x++)
+            hash = ( hash << 1 | hash >>> 31 ) ^ genome[x].hashCode();
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        StringBuffer s = new StringBuffer();
+        for( int i = 0 ; i < genome.length ; i++ )
+            { s.append(" "); s.append(genome[i].printGeneToStringForHumans()); }
+        return s.toString();
+        }
+        
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        for( int i = 0 ; i < genome.length ; i++ )
+            { s.append(" "); s.append(genome[i].printGeneToString()); }
+        return s.toString();
+        }
+
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line.  The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode( d );
+        int lll = (int)(d.l);
+
+        genome = new VectorGene[ lll ];
+
+        GeneVectorSpecies _species = (GeneVectorSpecies) species;
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            genome[i] = (VectorGene)(_species.genePrototype.clone());
+            genome[i].readGene(state,reader);
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false;
+        GeneVectorIndividual i = (GeneVectorIndividual)ind;
+        if( genome.length != i.genome.length )
+            return false;
+        for( int j = 0 ; j < genome.length ; j++ )
+            if( !(genome[j].equals(i.genome[j])))
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        { return genome; }
+    public void setGenome(Object gen)
+        { genome = (VectorGene[]) gen; }
+    public int genomeLength()
+        { return genome.length; }
+
+    // clone all the genes
+    public void cloneGenes(Object piece)
+        {
+        VectorGene[] genes = (VectorGene[]) piece;
+        for(int i = 0 ; i < genes.length; i++)
+            {
+            if (genes[i] != null) genes[i] = (VectorGene)(genes[i].clone());
+            }
+        }
+    
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for(int x=0;x<genome.length;x++)
+            genome[x].writeGene(state,dataOutput);
+        }
+
+    public void setGenomeLength(int len)
+        {
+        GeneVectorSpecies s = (GeneVectorSpecies) species;
+        VectorGene[] newGenome = new VectorGene[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        for(int x=genome.length; x< newGenome.length; x++)
+            if (genome[x]==null) genome[x] = (VectorGene)(s.genePrototype.clone());  // not reset
+        genome = newGenome;
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome==null || genome.length != len)
+            genome = new VectorGene[len];
+        GeneVectorSpecies _species = (GeneVectorSpecies) species;
+
+        for(int x=0;x<genome.length;x++)
+            {
+            genome[x] = (VectorGene)(_species.genePrototype.clone());
+            genome[x].readGene(state,dataInput);
+            }
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/GeneVectorSpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/GeneVectorSpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/GeneVectorSpecies.java	(revision 6152)
@@ -0,0 +1,63 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * GeneVectorSpecies.java
+ * 
+ * Created: Tue Feb 20 13:26:00 2001
+ * By: Sean Luke
+ */
+
+/**
+ * GeneVectorSpecies is a subclass of VectorSpecies with special
+ * constraints for GeneVectorIndividuals.
+ *
+ * <p>At present there is exactly one item stored in GeneVectorSpecies:
+ * the prototypical VectorGene that populates the genome array stored in a
+ * GeneVectorIndividual.
+ *
+ * @author Sean Luke
+ * @version 1.0 
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><tt>gene</tt><br>
+ <font size=-1>classname, inherits and != ec.VectorGene</font></td>
+ <td valign=top>(the prototypical gene for this kind of individual)</td></tr>
+ </table>
+
+ <p><b>Parameter bases</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>gene</tt></td>
+ <td>The prototypical gene for this kind of individual</td></tr>
+ </table>
+
+*/
+ 
+public class GeneVectorSpecies extends VectorSpecies
+    {
+    public static final String P_GENE = "gene";
+    public VectorGene genePrototype;
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        Parameter def = defaultBase();
+
+        genePrototype = (VectorGene)(state.parameters.getInstanceForParameterEq(
+                base.push(P_GENE),def.push(P_GENE),VectorGene.class));
+        genePrototype.setup(state,base.push(P_GENE));
+
+        // make sure that super.setup is done AFTER we've loaded our gene prototype.
+        super.setup(state,base);
+        }
+        
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/IntegerVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/IntegerVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/IntegerVectorIndividual.java	(revision 6152)
@@ -0,0 +1,398 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * IntegerVectorIndividual.java
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ */
+
+/**
+ * IntegerVectorIndividual is a VectorIndividual whose genome is an array of ints.
+ * Gene values may range from species.mingene(x) to species.maxgene(x), inclusive.
+ * The default mutation method randomizes genes to new values in this range,
+ * with <tt>species.mutationProbability</tt>.
+ *
+
+ * <P><b>From ec.Individual:</b>  
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+ <p><b>Default Base</b><br>
+ vector.int-vect-ind
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class IntegerVectorIndividual extends VectorIndividual
+    {
+    public static final String P_INTEGERVECTORINDIVIDUAL = "int-vect-ind";
+    public int[] genome;
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_INTEGERVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        IntegerVectorIndividual myobj = (IntegerVectorIndividual) (super.clone());
+
+        // must clone the genome
+        myobj.genome = (int[])(genome.clone());
+        
+        return myobj;
+        } 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+
+        Parameter def = defaultBase();
+        
+        if (!(species instanceof IntegerVectorSpecies)) 
+            state.output.fatal("IntegerVectorIndividual requires an IntegerVectorSpecies", base, def);
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        
+        genome = new int[s.genomeSize];
+        }
+        
+    public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        IntegerVectorIndividual i = (IntegerVectorIndividual) ind;
+        int tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output.fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch(s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                for(int x=0;x<point*s.chunksize;x++)
+                    { 
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x]; 
+                    genome[x] = tmp; 
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT: 
+                int point0 = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                if (point0 > point) { int p = point0; point0 = point; point = p; }
+                for(int x=point0*s.chunksize;x<point*s.chunksize;x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for(int x=0;x<genome.length/s.chunksize;x++) 
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for(int y=x*s.chunksize;y<(x+1)*s.chunksize;y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            case VectorSpecies.C_LINE_RECOMB:
+            {
+            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                min = s.minGene(x);
+                max = s.maxGene(x);
+                t = (long) Math.floor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                u = (long) Math.floor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                if (!(t < min || t > max || u < min || u > max))
+                    {
+                    genome[x] = (int) t;
+                    i.genome[x] = (int) u; 
+                    }
+                }
+            }
+            break;
+            case VectorSpecies.C_INTERMED_RECOMB:
+            {
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                do
+                    {
+                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    min = s.minGene(x);
+                    max = s.maxGene(x);
+                    t = (long) Math.floor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                    u = (long) Math.floor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                    } while (t < min || t > max || u < min || u > max);
+                genome[x] = (int) t;
+                i.genome[x] = (int) u; 
+                }
+            }
+            break;
+            }
+        }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0; point1 = points[0];
+        for(int x=0;x<pieces.length;x++)
+            {
+            pieces[x] = new int[point1-point0];
+            System.arraycopy(genome,point0,pieces[x],0,point1-point0);
+            point0 = point1;
+            if (x >=pieces.length-2)
+                point1 = genome.length;
+            else point1 = points[x+1];
+            }
+        }
+    
+    /** Joins the n pieces and sets the genome to their concatenation.*/
+    public void join(Object[] pieces)
+        {
+        int sum=0;
+        for(int x=0;x<pieces.length;x++)
+            sum += ((int[])(pieces[x])).length;
+        
+        int runningsum = 0;
+        int[] newgenome = new int[sum];
+        for(int x=0;x<pieces.length;x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum, ((int[])(pieces[x])).length);
+            runningsum += ((int[])(pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+
+    /** Returns a random value from between min and max inclusive.  This method handles
+        overflows that complicate this computation.  Does NOT check that
+        min is less than or equal to max.  You must check this yourself. */
+    public int randomValueFromClosedInterval(int min, int max, MersenneTwisterFast random)
+        {
+        if (max - min < 0) // we had an overflow
+            {
+            int l = 0;
+            do l = random.nextInt();
+            while(l < min || l > max);
+            return l;
+            }
+        else return min + random.nextInt(max - min + 1);
+        }
+
+
+    /** Destructively mutates the individual in some default manner.  The default form
+        simply randomizes genes to a uniform distribution from the min and max of the gene values. */
+    // notice that we bump to longs to avoid overflow errors
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        if (s.mutationProbability>0.0)
+            for(int x=0;x<genome.length;x++)
+                if (state.random[thread].nextBoolean(s.mutationProbability))
+                    genome[x] = randomValueFromClosedInterval((int)s.minGene(x), (int)s.maxGene(x), state.random[thread]);
+        }
+        
+    
+
+    /** Initializes the individual by randomly choosing Integers uniformly from mingene to maxgene. */
+    // notice that we bump to longs to avoid overflow errors
+    public void reset(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        for(int x=0;x<genome.length;x++)
+            genome[x] = randomValueFromClosedInterval((int)s.minGene(x), (int)s.maxGene(x), state.random[thread]);
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = ( hash << 1 | hash >>> 31 );
+        for(int x=0;x<genome.length;x++)
+            hash = ( hash << 1 | hash >>> 31 ) ^ genome[x];
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for( int i = 0 ; i < genome.length ; i++ )
+            s = s + " " + genome[i];
+        return s;
+        }
+        
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append( Code.encode( genome.length ) );
+        for( int i = 0 ; i < genome.length ; i++ )
+            s.append( Code.encode( genome[i] ) );
+        return s.toString();
+        }
+                
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line.  The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode( d );
+        int lll = (int)(d.l);
+
+        genome = new int[ lll ];
+
+        // read in the genes
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            Code.decode( d );
+            genome[i] = (int)(d.l);
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false; // SimpleRuleIndividuals are special.
+        IntegerVectorIndividual i = (IntegerVectorIndividual)ind;
+        if( genome.length != i.genome.length )
+            return false;
+        for( int j = 0 ; j < genome.length ; j++ )
+            if( genome[j] != i.genome[j] )
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        { return genome; }
+    public void setGenome(Object gen)
+        { genome = (int[]) gen; }
+    public int genomeLength()
+        { return genome.length; }
+        
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for(int x=0;x<genome.length;x++)
+            dataOutput.writeInt(genome[x]);
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome==null || genome.length != len)
+            genome = new int[len];
+        for(int x=0;x<genome.length;x++)
+            genome[x] = dataInput.readInt();
+        }
+
+    /** Clips each gene value to be within its specified [min,max] range. */
+    public void clamp() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            {
+            int minGene = (int)_species.minGene(i);
+            if (genome[i] < minGene)
+                genome[i] = minGene;
+            else 
+                {
+                int maxGene = (int)_species.maxGene(i);
+                if (genome[i] > maxGene)
+                    genome[i] = maxGene;
+                }
+            }
+        }
+                
+    public void setGenomeLength(int len)
+        {
+        int[] newGenome = new int[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    /** Returns true if each gene value is within is specified [min,max] range. */
+    public boolean isInRange() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            if (genome[i] < _species.minGene(i) ||
+                genome[i] > _species.maxGene(i)) return false;
+        return true;
+        }
+
+    public double distanceTo(Individual otherInd)
+        {               
+        if (!(otherInd instanceof IntegerVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        IntegerVectorIndividual other = (IntegerVectorIndividual) otherInd;
+        int[] otherGenome = other.genome;
+        double sumSquaredDistance =0.0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            long dist = this.genome[i] - (long)otherGenome[i];
+            sumSquaredDistance += dist*dist;
+            }
+        return StrictMath.sqrt(sumSquaredDistance);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/IntegerVectorSpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/IntegerVectorSpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/IntegerVectorSpecies.java	(revision 6152)
@@ -0,0 +1,560 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * IntegerVectorSpecies.java
+ * 
+ * Created: Tue Feb 20 13:26:00 2001
+ * By: Sean Luke
+ */
+
+/**
+ * IntegerVectorSpecies is a subclass of VectorSpecies with special constraints
+ * for integral vectors, namely ByteVectorIndividual, ShortVectorIndividual,
+ * IntegerVectorIndividual, and LongVectorIndividual.
+ 
+ * <p>IntegerVectorSpecies can specify min/max numeric constraints on gene values
+ * in three different ways.
+ *
+ * <ol>
+ * <li> You may provide a default min and max value.
+ *      This is done by specifying:
+ *      <p><i>base</i>.<tt>min-gene</tt>
+ *      <br><i>base</i>.<tt>max-gene</tt>
+ *      <p><i>Note:</i> you <b>must</b> provide these values even if you don't use them,
+ *      as they're used as defaults by #2 and #3 below.
+ *<p>
+ * <li> You may provide min and max values for genes in segments (regions) along
+ *      the genome.  This is done by specifying:
+ *      <p><i>base</i>.<tt>num-segments</tt>
+ *      The segments may be defined by either start or end indices of genes. 
+ *      This is controlled by specifying the value of:
+ *      <p><i>base</i>.<tt>segment-type</tt>
+ *      which can assume the value of start or end, with start being the default.
+ *      The indices are defined using Java array style, i.e. the first gene has the index of 0, 
+ *      and the last gene has the index of genome-size - 1.
+ *      <p>Using this method, each segment is specified by<i>j</i>...
+ *      <p><i>base</i>.<tt>segment.</tt><i>j</i><tt>.start</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.min-gene</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.max-gene</tt>
+ *      if segment-type value was chosen as start or by:
+ *      <p><i>base</i>.<tt>segment.</tt><i>j</i><tt>.end</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.min-gene</tt>
+ *      <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.max-gene</tt>
+ *      if segment-type value is equal to end.
+ *<p>
+ * <li> You may provide min and max values for each separate gene.
+ *      This is done by specifying (for each gene location <i>i</i> you wish to specify).  
+ *      <p><i>base</i>.<tt>min-gene</tt>.<i>i</i>
+ *      <br><i>base</i>.<tt>max-gene</tt>.<i>i</i>
+ * </ol>
+ * 
+ * <p>Any settings for #3 override #2, and both override #1. 
+ *
+ *
+ * <p><b>Parameters</b><br>
+ * <table>
+ * <tr><td valign=top><i>base</i>.<tt>min-gene</tt><br>
+ * <font size=-1>long (default=0)</font></td>
+ * <td valign=top>(the minimum gene value)</td></tr>
+ *
+ * <tr><td valign=top><i>base</i>.<tt>max-gene</tt><br>
+ * <font size=-1>long &gt;= <i>base</i>.min-gene</font></td>
+ * <td valign=top>(the maximum gene value)</td></tr>
+ *
+ * <tr><td valign=top><i>base</i>.<tt>min-gene</tt>.<i>i</i><br>
+ * <font size=-1>long (default=<i>base</i>.<tt>min-gene</tt>)</font></td>
+ * <td valign=top>(the minimum gene value for gene <i>i</i>)</td></tr>
+ *
+ * <tr><td valign=top><i>base</i>.<tt>max-gene</tt>.<i>i</i><br>
+ * <font size=-1>long &gt;= <i>base</i>.min-gene.<i>i</i> (default=<i>base</i>.<tt>max-gene</tt>)</font></td>
+ * <td valign=top>(the maximum gene value for gene <i>i</i>)</td></tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>num-segments</tt><br>
+ * <font size=-1>int &gt;= 1 (default=no segments used)</font></td>
+ * <td valign=top>(the number of gene segments defined)</td>
+ * </tr>
+ * 
+ * <tr><td valign=top><i>base.</i>.<tt>segment-type</tt><br>
+ * <font size=-1>start (default) or end</font></td>
+ * <td valign=top>(defines the way in which segments are defined: either by providing start indices (segment-type=start) or by providing end indices (segment-type=end)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>start</tt><br>
+ * <font size=-1>0 &lt;= int &lt; genome length</font></td>
+ * <td valign=top>(the start index of gene segment <i>j</i> -- the end of a segment is before the start of the next segment)</td>
+ * <td valign=top>(used when the value of segment-type parameter is equal to start)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>end</tt><br>
+ * <font size=-1>0 &lt;= int &lt; genome length</font></td>
+ * <td valign=top>(the end of gene segment <i>j</i> -- the start of a segment is after the end of the previous segment)</td>
+ * <td valign=top>(used when the value of segment-type parameter is equal to end)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>min-gene</tt><br>
+ * <font size=-1>double (default=0.0)</font></td>
+ * <td valign=top>(the minimum gene value for segment <i>j</i>)</td>
+ * </tr>
+ *
+ * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>max-gene</tt><br>
+ * <font size=-1>double &gt;= <i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>min-gene</tt></td>
+ * <td valign=top>(the maximum gene value for segment <i>j</i>)</td>
+ * </tr>
+ * 
+ * </table>
+ * @author Sean Luke, Rafal Kicinger
+ * @version 1.0 
+ */
+public class IntegerVectorSpecies extends VectorSpecies
+    {
+    public final static String P_MINGENE = "min-gene";
+    public final static String P_MAXGENE = "max-gene";
+    
+    public final static String P_NUM_SEGMENTS = "num-segments";
+        
+    public final static String P_SEGMENT_TYPE = "segment-type";
+
+    public final static String P_SEGMENT_START = "start";
+        
+    public final static String P_SEGMENT_END = "end";
+
+    public final static String P_SEGMENT = "segment";
+        
+    public long[] minGenes;
+    public long[] maxGenes;
+    
+    public long maxGene(int gene)
+        {
+        long[] m = maxGenes;
+        if (m.length <= gene)
+            { 
+            if (!dynamicInitialSize && !warned) warnAboutGene(gene);
+            gene = m.length - 1;
+            }
+        return m[gene];
+        }
+    
+    public long minGene(int gene)
+        {
+        long[] m = minGenes;
+        if (m.length <= gene)
+            { 
+            if (!dynamicInitialSize && !warned) warnAboutGene(gene);
+            gene = m.length - 1;
+            }
+        return m[gene];
+        }
+    
+    public boolean inNumericalTypeRange(long geneVal)
+        {
+        if (i_prototype instanceof ByteVectorIndividual)
+            return (geneVal <= Byte.MAX_VALUE && geneVal >= Byte.MIN_VALUE);
+        else if (i_prototype instanceof ShortVectorIndividual)
+            return (geneVal <= Short.MAX_VALUE && geneVal >= Short.MIN_VALUE);
+        else if (i_prototype instanceof IntegerVectorIndividual)
+            return (geneVal <= Integer.MAX_VALUE && geneVal >= Integer.MIN_VALUE);
+        else if (i_prototype instanceof LongVectorIndividual)
+            return true;  // geneVal is valid for all longs
+        else return false;  // dunno what the individual is...
+        }
+    
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // keep in mind that the *species* variable has not been set yet.
+        super.setup(state,base);
+        
+        Parameter def = defaultBase();
+
+        // create the arrays
+        minGenes = new long[genomeSize];
+        maxGenes = new long[genomeSize];
+        
+        
+        
+
+        // LOADING GLOBAL MIN/MAX GENES
+        long minGene = state.parameters.getLongWithDefault(base.push(P_MINGENE),def.push(P_MINGENE),0);
+        long maxGene = state.parameters.getLong(base.push(P_MAXGENE),def.push(P_MAXGENE),minGene);
+        if (maxGene < minGene)
+            state.output.fatal("IntegerVectorSpecies must have a default min-gene which is <= the default max-gene",
+                base.push(P_MAXGENE),def.push(P_MAXGENE));
+        
+        for (int x = 0; x < genomeSize; x++)
+            {
+            minGenes[x] = minGene;
+            maxGenes[x] = maxGene;
+            }
+
+
+
+
+        // LOADING SEGMENTS
+
+        //Set number of segments to 0 by default
+        int numSegments = 0;
+        // Now check to see if segments of genes (genes having the same min and
+        // max values) exist
+        if (state.parameters.exists(base.push(P_NUM_SEGMENTS), def.push(P_NUM_SEGMENTS)))
+            {
+            if (dynamicInitialSize)
+                state.output.warnOnce("Using dynamic initial sizing, but per-segment min/max gene declarations.  This is probably wrong.  You probably want to use global min/max declarations.",
+                    base.push(P_NUM_SEGMENTS), def.push(P_NUM_SEGMENTS));
+                        
+            numSegments = state.parameters.getIntWithDefault(base.push(P_NUM_SEGMENTS), 
+                def.push(P_NUM_SEGMENTS), 0);
+                        
+            if(numSegments == 0)
+                state.output.warning(
+                    "The number of genome segments has been defined to be equal to 0.\n"
+                    + "Hence, no genome segments will be defined.", 
+                    base.push(P_NUM_SEGMENTS), 
+                    def.push(P_NUM_SEGMENTS));
+            else if(numSegments < 0)
+                state.output.fatal(
+                    "Invalid number of genome segments: " + numSegments
+                    + "\nIt must be a nonnegative value.", 
+                    base.push(P_NUM_SEGMENTS), 
+                    def.push(P_NUM_SEGMENTS));
+                                
+            //read the type of segment definition using the default start value
+            String segmentType = state.parameters.getStringWithDefault(base.push(P_SEGMENT_TYPE), 
+                def.push(P_SEGMENT_TYPE), P_SEGMENT_START);
+                        
+            if(segmentType.equalsIgnoreCase(P_SEGMENT_START))
+                initializeGenomeSegmentsByStartIndices(state, base, def, numSegments, minGene, maxGene);
+            else if(segmentType.equalsIgnoreCase(P_SEGMENT_END))
+                initializeGenomeSegmentsByEndIndices(state, base, def, numSegments, minGene, maxGene);
+            else
+                state.output.fatal(
+                    "Invalid specification of genome segment type: " + segmentType
+                    + "\nThe " + P_SEGMENT_TYPE + " parameter must have the value of " + P_SEGMENT_START + " or " + P_SEGMENT_END, 
+                    base.push(P_SEGMENT_TYPE), 
+                    def.push(P_SEGMENT_TYPE));
+
+
+            }
+
+
+
+        // LOADING PER-GENE VALUES
+
+        boolean foundStuff = false;
+        boolean warnedMin=false;
+        boolean warnedMax=false;
+        for(int x=0;x<genomeSize;x++)
+            {
+            if (!state.parameters.exists(base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x)))
+                {
+                if (foundStuff && !warnedMin)
+                    {
+                    state.output.warning("IntegerVectorSpecies has missing min-gene values for some genes.\n" +
+                        "The first one is gene #"+x+".", base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x));
+                    warnedMin = true;
+                    }
+                }
+            else 
+                {
+                if (dynamicInitialSize)
+                    state.output.warnOnce("Using dynamic initial sizing, but per-gene min/max gene declarations.  This is probably wrong.  You probably want to use global min/max declarations.",
+                        base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x));
+
+                minGenes[x] = state.parameters.getLongWithDefault(base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x),minGene);
+                foundStuff = true;
+                }
+
+            if (!state.parameters.exists(base.push(P_MAXGENE).push(""+x),base.push(P_MAXGENE).push(""+x)))
+                {
+                if (foundStuff && !warnedMax)
+                    {
+                    state.output.warning("IntegerVectorSpecies has missing max-gene values for some genes.\n" +
+                        "The first one is gene #"+x+".", base.push(P_MAXGENE).push(""+x),base.push(P_MAXGENE).push(""+x));
+                    warnedMax = true;
+                    }
+                }
+            else 
+                {
+                if (dynamicInitialSize)
+                    state.output.warnOnce("Using dynamic initial sizing, but per-gene min/max gene declarations.  This is probably wrong.  You probably want to use global min/max declarations.",
+                        base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x));
+
+                maxGenes[x] = state.parameters.getLongWithDefault(base.push(P_MAXGENE).push(""+x),base.push(P_MAXGENE).push(""+x),maxGene);
+                foundStuff = true;
+                }
+            }
+        
+        
+        
+        
+        // VERIFY
+        for(int x=0; x< genomeSize; x++)
+            {
+            if (maxGenes[x] < minGenes[x])
+                state.output.fatal("IntegerVectorSpecies must have a min-gene["+x+"] which is <= the max-gene["+x+"]");
+            
+            // check to see if these longs are within the data type of the particular individual
+            if (!inNumericalTypeRange(minGenes[x]))
+                state.output.fatal("This IntegerVectorSpecies has a prototype of the kind: " 
+                    + i_prototype.getClass().getName() +
+                    ", but doesn't have a min-gene["+x+"] value within the range of this prototype's genome's data types");
+            if (!inNumericalTypeRange(maxGenes[x]))
+                state.output.fatal("This IntegerVectorSpecies has a prototype of the kind: " 
+                    + i_prototype.getClass().getName() +
+                    ", but doesn't have a max-gene["+x+"] value within the range of this prototype's genome's data types");
+            }
+
+                
+        /*
+        //Debugging
+        for(int i = 0; i < minGenes.length; i++)
+        System.out.println("Min: " + minGenes[i] + ", Max: " + maxGenes[i]);
+        */
+        }
+    
+        
+    private void initializeGenomeSegmentsByStartIndices(final EvolutionState state, 
+        final Parameter base, 
+        final Parameter def,
+        int numSegments,
+        long minGene, long maxGene)
+        {
+        boolean warnedMin = false;
+        boolean warnedMax = false;
+        long currentSegmentMinGeneValue = Long.MAX_VALUE;
+        long currentSegmentMaxGeneValue = Long.MIN_VALUE;
+                
+        //loop in reverse order 
+        int previousSegmentEnd = genomeSize;
+        int currentSegmentEnd = 0;
+                
+        for (int i = numSegments - 1; i >= 0; i--)
+            {
+            //check if the segment data exist
+            if (state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), 
+                    def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START)))
+                {
+                //Read the index of the end gene specifying current segment
+                currentSegmentEnd = state.parameters.getInt(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), 
+                    def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START));
+                                
+                }
+            else
+                {
+                state.output.fatal("Genome segment " + i + " has not been defined!" +
+                    "\nYou must specify start indices for " + numSegments + " segment(s)", 
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START),
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START));
+                }
+                        
+            //check if the start index is valid
+            if(currentSegmentEnd >= previousSegmentEnd || currentSegmentEnd < 0)
+                state.output.fatal(
+                    "Invalid start index value for segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be smaller than " + previousSegmentEnd +
+                    " and greater than or equal to  " + 0);
+                        
+            //check if the index of the first segment is equal to 0
+            if(i == 0 && currentSegmentEnd != 0)
+                state.output.fatal(
+                    "Invalid start index value for the first segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be equal to " + 0);
+                        
+                        
+            //get min and max values of genes in this segment
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE)))
+                {
+                if (!warnedMin)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing min-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMin = true;
+                    }
+                                
+                //the min-gene value has not been defined for this segment so assume the global min value
+                currentSegmentMinGeneValue = minGene;
+                }
+            else  //get the min value for this segment
+                {
+                currentSegmentMinGeneValue = state.parameters.getLongWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    minGene);
+                                
+                }
+                        
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)))
+                {
+                if (!warnedMax)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing max-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMax = true;
+                    }
+                                
+                //the max-gen value has not been defined for this segment so assume the global max value
+                currentSegmentMaxGeneValue = maxGene;
+                                
+                }
+            else   //get the max value for this segment
+                {
+                currentSegmentMaxGeneValue = state.parameters.getLongWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    maxGene);
+                }
+
+            //check is min is smaller than or equal to max
+            if (currentSegmentMaxGeneValue < currentSegmentMinGeneValue)
+                state.output.fatal(
+                    "IntegerVectorSpecies must have a min-gene value for segment "
+                    + i + " which is <= the max-gene value", 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE));
+
+                        
+            //and assign min and max values for all genes in this segment
+            for(int j = previousSegmentEnd-1; j >= currentSegmentEnd; j--)
+                {
+                minGenes[j] = currentSegmentMinGeneValue;
+                maxGenes[j] = currentSegmentMaxGeneValue;
+                }
+                        
+            previousSegmentEnd = currentSegmentEnd;
+                        
+            }
+                
+        }
+        
+    private void initializeGenomeSegmentsByEndIndices(final EvolutionState state, 
+        final Parameter base, 
+        final Parameter def,
+        int numSegments,
+        long minGene, long maxGene)
+        {
+        boolean warnedMin = false;
+        boolean warnedMax = false;
+        long currentSegmentMinGeneValue = Long.MAX_VALUE;
+        long currentSegmentMaxGeneValue = Long.MIN_VALUE;
+                
+        int previousSegmentEnd = -1;  
+        int currentSegmentEnd = 0;
+        // iterate over segments and set genes values for each segment
+        for (int i = 0; i < numSegments; i++)
+            {
+            //check if the segment data exist
+            if (state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END)))
+                {
+                //Read the index of the end gene specifying current segment
+                currentSegmentEnd = state.parameters.getInt(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), 
+                    def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END));
+                                
+                }
+            else
+                {
+                state.output.fatal("Genome segment " + i + " has not been defined!" +
+                    "\nYou must specify end indices for " + numSegments + " segment(s)", 
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END),
+                    base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END));
+                }
+                        
+            //check if the end index is valid
+            if(currentSegmentEnd <= previousSegmentEnd || currentSegmentEnd >= genomeSize)
+                state.output.fatal(
+                    "Invalid end index value for segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be greater than " + previousSegmentEnd +
+                    " and smaller than " + genomeSize);
+                        
+            //check if the index of the final segment is equal to the genomeSize
+            if(i == numSegments - 1 && currentSegmentEnd != (genomeSize-1))
+                state.output.fatal(
+                    "Invalid end index value for the last segment " + i + ": " + currentSegmentEnd 
+                    +  "\nThe value must be equal to the index of the last gene in the genome:  " + (genomeSize-1));
+                        
+                        
+            //get min and max values of genes in this segment
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE)))
+                {
+                if (!warnedMin)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing min-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMin = true;
+                    }
+                                
+                //the min-gene value has not been defined for this segment so assume the global min value
+                currentSegmentMinGeneValue = minGene;
+                }
+            else  //get the min value for this segment
+                {
+                currentSegmentMinGeneValue = state.parameters.getLongWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MINGENE), 
+                    minGene);
+                                
+                }
+                        
+            if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)))
+                {
+                if (!warnedMax)
+                    {
+                    state.output.warning(
+                        "IntegerVectorSpecies has missing max-gene values for some segments.\n"
+                        + "The first segment is #" + i + ".", 
+                        base.push(P_SEGMENT).push(""+i), 
+                        base.push(P_SEGMENT).push(""+i));
+                    warnedMax = true;
+                    }
+                                
+                //the max-gen value has not been defined for this segment so assume the global max value
+                currentSegmentMaxGeneValue = maxGene;
+                }
+            else   //get the max value for this segment
+                {
+                currentSegmentMaxGeneValue = state.parameters.getLongWithDefault(
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    maxGene);
+                }
+
+            //check is min is smaller than or equal to max
+            if (currentSegmentMaxGeneValue < currentSegmentMinGeneValue)
+                state.output.fatal(
+                    "IntegerVectorSpecies must have a min-gene value for segment "
+                    + i + " which is <= the max-gene value", 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), 
+                    base.push(P_SEGMENT).push(""+i).push(P_MAXGENE));
+                        
+            //and assign min and max values for all genes in this segment
+            for(int j = previousSegmentEnd+1; j <= currentSegmentEnd; j++)
+                {
+                minGenes[j] = currentSegmentMinGeneValue;
+                maxGenes[j] = currentSegmentMaxGeneValue;
+                }
+                        
+            previousSegmentEnd = currentSegmentEnd;
+            }
+        }
+    
+    }
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/LongVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/LongVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/LongVectorIndividual.java	(revision 6152)
@@ -0,0 +1,419 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * LongVectorIndividual.java
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ */
+
+/**
+ * LongVectorIndividual is a VectorIndividual whose genome is an array of longs.
+ * Gene values may range from species.mingene(x) to species.maxgene(x), inclusive.
+ * The default mutation method randomizes genes to new values in this range,
+ * with <tt>species.mutationProbability</tt>.
+ *
+
+ * <P><b>From ec.Individual:</b> 
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+
+ <p><b>Default Base</b><br>
+ vector.long-vect-ind
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class LongVectorIndividual extends VectorIndividual
+    {
+    public static final String P_LONGVECTORINDIVIDUAL = "long-vect-ind";
+    public long[] genome;
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_LONGVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        LongVectorIndividual myobj = (LongVectorIndividual) (super.clone());
+
+        // must clone the genome
+        myobj.genome = (long[])(genome.clone());
+        
+        return myobj;
+        } 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);  // actually unnecessary (Individual.setup() is empty)
+        
+        Parameter def = defaultBase();
+        
+        if (!(species instanceof IntegerVectorSpecies)) 
+            state.output.fatal("LongVectorIndividual requires an IntegerVectorSpecies", base, def);
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        
+        genome = new long[s.genomeSize];
+        }
+        
+        
+    // Because Math.floor only goes within the double integer space
+    long longFloor(double x)
+        {
+        long l = (long) x;  // pulls towards zero
+                
+        if (x >= 0)
+            {
+            return l;  // NaN will get shunted to 0 apparently
+            }
+        else if (x < Long.MIN_VALUE + 1)  // it'll go to Long.MIN_VALUE
+            {
+            return Long.MIN_VALUE;
+            }
+        else if (l == x)  // it's exact
+            {
+            return l;
+            }
+        else
+            {
+            return l - 1;
+            }
+        }
+        
+    public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        LongVectorIndividual i = (LongVectorIndividual) ind;
+        long tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output.fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch(s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                for(int x=0;x<point*s.chunksize;x++)
+                    { 
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x]; 
+                    genome[x] = tmp; 
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT: 
+                int point0 = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                if (point0 > point) { int p = point0; point0 = point; point = p; }
+                for(int x=point0*s.chunksize;x<point*s.chunksize;x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for(int x=0;x<genome.length/s.chunksize;x++) 
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for(int y=x*s.chunksize;y<(x+1)*s.chunksize;y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            case VectorSpecies.C_LINE_RECOMB:
+            {
+            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                min = s.minGene(x);
+                max = s.maxGene(x);
+                t = longFloor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                u = longFloor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                if (!(t < min || t > max || u < min || u > max))
+                    {
+                    genome[x] = t;
+                    i.genome[x] = u; 
+                    }
+                }
+            }
+            break;
+            case VectorSpecies.C_INTERMED_RECOMB:
+            {
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                do
+                    {
+                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    min = s.minGene(x);
+                    max = s.maxGene(x);
+                    t = longFloor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                    u = longFloor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                    } while (t < min || t > max || u < min || u > max);
+                genome[x] = t;
+                i.genome[x] = u; 
+                }
+            }
+            break;
+            }
+        }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0; point1 = points[0];
+        for(int x=0;x<pieces.length;x++)
+            {
+            pieces[x] = new long[point1-point0];
+            System.arraycopy(genome,point0,pieces[x],0,point1-point0);
+            point0 = point1;
+            if (x >=pieces.length-2)
+                point1 = genome.length;
+            else point1 = points[x+1];
+            }
+        }
+    
+    /** Joins the n pieces and sets the genome to their concatenation.*/
+    public void join(Object[] pieces)
+        {
+        int sum=0;
+        for(int x=0;x<pieces.length;x++)
+            sum += ((long[])(pieces[x])).length;
+        
+        int runningsum = 0;
+        long[] newgenome = new long[sum];
+        for(int x=0;x<pieces.length;x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum, ((long[])(pieces[x])).length);
+            runningsum += ((long[])(pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /** Returns a random value from between min and max inclusive.  This method handles
+        overflows that complicate this computation.  Does NOT check that
+        min is less than or equal to max.  You must check this yourself. */
+    public long randomValueFromClosedInterval(long min, long max, MersenneTwisterFast random)
+        {
+        if (max - min < 0) // we had an overflow
+            {
+            long l = 0;
+            do l = random.nextLong();
+            while(l < min || l > max);
+            return l;
+            }
+        else return min + random.nextLong(max - min + 1L);
+        }
+
+    /** Destructively mutates the individual in some default manner.  The default form
+        simply randomizes genes to a uniform distribution from the min and max of the gene values. */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        if (s.mutationProbability>0.0)
+            for(int x=0;x<genome.length;x++)
+                if (state.random[thread].nextBoolean(s.mutationProbability))
+                    genome[x] = randomValueFromClosedInterval(s.minGene(x), s.maxGene(x), state.random[thread]);
+        }
+        
+    /** Initializes the individual by randomly choosing Longs uniformly from mingene to maxgene. */
+    public void reset(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        for(int x=0;x<genome.length;x++)
+            genome[x] = randomValueFromClosedInterval(s.minGene(x), s.maxGene(x), state.random[thread]);
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = ( hash << 1 | hash >>> 31 );
+        for(int x=0;x<genome.length;x++)
+            hash = ( hash << 1 | hash >>> 31 ) ^ (int)((genome[x] >>> 16) & 0xFFFFFFFF) ^ (int)(genome[x] & 0xFFFF);
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for( int i = 0 ; i < genome.length ; i++ )
+            s = s + " " + genome[i];
+        return s;
+        }
+        
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append( Code.encode( genome.length ) );
+        for( int i = 0 ; i < genome.length ; i++ )
+            s.append( Code.encode( genome[i] ) );
+        return s.toString();
+        }
+
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line.  The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode( d );
+        int lll = (int)(d.l);
+
+        genome = new long[ lll ];
+
+        // read in the genes
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            Code.decode( d );
+            genome[i] = d.l;
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false; // SimpleRuleIndividuals are special.
+        LongVectorIndividual i = (LongVectorIndividual)ind;
+        if( genome.length != i.genome.length )
+            return false;
+        for( int j = 0 ; j < genome.length ; j++ )
+            if( genome[j] != i.genome[j] )
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        { return genome; }
+    public void setGenome(Object gen)
+        { genome = (long[]) gen; }
+    public int genomeLength()
+        { return genome.length; }
+
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for(int x=0;x<genome.length;x++)
+            dataOutput.writeLong(genome[x]);
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome==null || genome.length != len)
+            genome = new long[len];
+        for(int x=0;x<genome.length;x++)
+            genome[x] = dataInput.readLong();
+        }
+
+    /** Clips each gene value to be within its specified [min,max] range. */
+    public void clamp() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            {
+            long minGene = _species.minGene(i);
+            if (genome[i] < minGene)
+                genome[i] = minGene;
+            else 
+                {
+                long maxGene = _species.maxGene(i);
+                if (genome[i] > maxGene)
+                    genome[i] = maxGene;
+                }
+            }
+        }
+                
+    public void setGenomeLength(int len)
+        {
+        long[] newGenome = new long[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    /** Returns true if each gene value is within is specified [min,max] range. */
+    public boolean isInRange() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            if (genome[i] < _species.minGene(i) ||
+                genome[i] > _species.maxGene(i)) return false;
+        return true;
+        }
+
+    public double distanceTo(Individual otherInd)
+        {               
+        if (!(otherInd instanceof LongVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        LongVectorIndividual other = (LongVectorIndividual) otherInd;
+        long[] otherGenome = other.genome;
+        double sumSquaredDistance =0.0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            // can't subtract two longs and expect a long.  Must convert to doubles :-(
+            double dist = this.genome[i] - (double)otherGenome[i];
+            sumSquaredDistance += dist*dist;
+            }
+        return StrictMath.sqrt(sumSquaredDistance);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/README	(revision 6152)
@@ -0,0 +1,147 @@
+This package, and the 'breed' subpackage contained inside, implement basic 
+vector representations common in evolution
+strategies and genetic algorithms.  The package is straightforward.  There
+are various VectorIndividuals, each with an associated VectorSpecies that
+it uses to maintain certain constraints (such as the minimum and maximum
+gene values in the vector).
+
+VectorIndividuals can be used with any breeding pipeline you care to design,
+but since certain crossover and mutation methods are so common, the individuals
+themselves implement those methods, and the VectorMutationPipeline and
+VectorCrossoverPipeline are designed not to perform those methods but simply
+to trigger the individuals into performing it themselves.  Thus if you
+want to create a custom crossover procedure that's different from the
+standard ones, you can do so simply by overriding the appropriate
+defaultCrossover() method in the individual class, rather than making
+a new pipeline.
+
+VectorIndividuals also have significant numbers of hooks for variable-length
+vector representations.
+
+Note that there are different VectorIndividuals for different basic types.  For
+example, there's a BitVectorIndividual and a FloatVectorIndividual, etc.
+This doesn't use Java's generics facility.  Why?  Because Java's generics
+are *extremely* slow.  They simplify the implementation of code like this but
+at a very very high cost, and so ECJ just breaks out the individuals on a per-
+type basis for efficiency purposes.
+
+The various vector representations and their associated species and basic 
+types are:
+
+INDIVIDUAL			SPECIES			BASIC TYPE
+BitVectorIndividual		VectorSpecies		boolean
+ByteVectorIndividual		IntegerVectorSpecies	byte
+ShortVectorIndividual		IntegerVectorSpecies	short
+IntegerVectorIndividual		IntegerVectorSpecies	int
+LongVectorIndividual		IntegerVectorSpecies	long
+FloatVectorIndividual		FloatVectorSpecies	float
+DoubleVectorIndividual		FloatVectorSpecies	double
+GeneVectorIndividual		GeneVectorSpecies	VectorGene
+
+
+Some items to note about certain species:
+
+
+ec.vector.VectorSpecies
+
+This is the superclass of all vector species, and defines three kinds of 
+crossover: one-point, two-point, and uniform crossover (referred to as 'any'),
+with a per-gene crossover probability for uniform crossover.  Additionally, 
+a mutation probability specifies a per-gene likelihood of performing 
+mutation on that gene (the kind of mutation depends on the particular 
+vector individual being used).
+
+VectorSpecies also allows you to specify a *chunk size*.  Chunks are regions
+in which no crossover is allowed.  Crossover only occurs on chunk boundaries.
+This allows you, for example, to indicate that an individual consists of
+chunks 12 boolean values long (say), and that they are to be treated as atomic
+units by the crossover operator -- it can't cross over within the chunk.
+
+VectorSpecies is the species for BitVectorIndividual, as BitVectorIndividual
+doesn't need any special features.
+
+
+ec.vector.IntegerVectorSpecies
+
+IntegerVectorSpecies is a VectorSpecies and so has all the same features as it.
+Also, it allows you to specify min and max gene values for each 
+gene in three different ways.  First, you can specify a global min and max
+value for all genes.  Second, you can specify _segments_ (regions in the
+genome) which all share the same min and max values.  Third, you can specify
+individual min and max values for each independent gene.  These three methods
+can be mixed as well: independent gene values override segments, which override
+global values.  Note that segments are not the same thing as chunks.
+
+The default mutation procedure for IntegerVectorSpecies genes is gene
+randomization.  Override this as you see fit.
+
+
+ec.vector.FloatVectorSpecies
+
+This class, like IntegerVectorSpecies, has all the features of VectorSpecies,
+and furthermore has min and max gene values specified on a global, segment,
+and per-gene basis.  
+
+The default mutation procedure for FloatVectorSpecies can be either
+randomization or adding gaussian random noise with a specified mutation
+standard deviation.  If the random noise exceeds the min and max bounds
+for that gene, FloatVectorSpecies will retry (you can specify how many
+times) before giving up and not mutating the gene.
+
+
+ec.vector.GeneVectorSpecies
+
+This class is a VectorSpecies and so has all of its features.  However the
+atomic type of the vector array isn't a number or boolean, but rather a 
+specific object called a VectorGene; or more specifically, a subclass of
+VectorGene which you specify (with the 'gene' parameter).  The objective
+of this Species and GeneVectorIndividual is to enable you to have arbitrary
+genes of any kind you like -- just stick your data in your VectorGene
+subclass.
+
+
+
+
+Other classes of importance:
+
+
+ec.vector.VectorGene
+
+This class is used with GeneVectorIndividual and GeneVectorSpecies to give you
+flexibility with regard to the makeup of genes in the individual.  To implement
+a VectorGene subclass, you'll need to provide a few basic methods (equality
+testing, hash codes, the reset method, the mutation method) and optionally some
+print facilities, depending on your needs.
+
+
+ec.vector.breed.VectorMutationPipeline
+
+Defines a basic mutation breeding pipeline for vector individuals.  The class
+is very simple: when it is charged to produce a child, it requests a child
+from its source, then calls defaultMutate() on that child and returns it.
+
+
+ec.vector.breed.VectorCrossoverPipeline
+
+Defines a basic crossover breeding pipeline for vector individuals.  The class
+is very simple: when it is charged to produce children, it requests a child
+from each of its sources, then calls defaultCrossover() on one child, passing
+in the other child, to get them to cross over with one another. It then returns
+the children.
+
+
+ec.vector.breed.ListCrossoverPipeline	[UNTESTED]
+
+Defines one-point and two-point crossover for vector individuals whose length may
+vary.  This crossover pipeline may be useful for representations which are lists
+rather than fixed-length vectors.
+
+
+ec.vector.breed.MultiCrossoverPipeline	[UNTESTED]
+
+Performs a version of N-person multiple crossover.  The size of N is determined
+by the number of sources provided to the pipeline.  For each gene, the gene
+values among the N indivdiuals are shuffled.  The resulting children are then
+returned.
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/ShortVectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/ShortVectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/ShortVectorIndividual.java	(revision 6152)
@@ -0,0 +1,384 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+/*
+ * ShortVectorIndividual.java
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ */
+
+/**
+ * ShortVectorIndividual is a VectorIndividual whose genome is an array of shorts.
+ * Gene values may range from species.mingene(x) to species.maxgene(x), inclusive.
+ * The default mutation method randomizes genes to new values in this range,
+ * with <tt>species.mutationProbability</tt>.
+
+ * <P><b>From ec.Individual:</b>  
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+
+ <p><b>Default Base</b><br>
+ vector.short-vect-ind
+
+ * @author Liviu Panait
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class ShortVectorIndividual extends VectorIndividual
+    {
+    public static final String P_SHORTVECTORINDIVIDUAL = "short-vect-ind";
+    public short[] genome;
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_SHORTVECTORINDIVIDUAL);
+        }
+
+    public Object clone()
+        {
+        ShortVectorIndividual myobj = (ShortVectorIndividual) (super.clone());
+
+        // must clone the genome
+        myobj.genome = (short[])(genome.clone());
+        
+        return myobj;
+        } 
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state, base); // actually, unnecessary but...
+        
+        // since IntegerVectorSpecies set its constraint values BEFORE it called
+        // super.setup(...) [which in turn called our setup(...)], we know that
+        // stuff like genomeSize has already been set...
+        
+        Parameter def = defaultBase();
+        
+        if (!(species instanceof IntegerVectorSpecies)) 
+            state.output.fatal("ShortVectorIndividual requires an IntegerVectorSpecies", base, def);
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        
+        genome = new short[s.genomeSize];
+        }
+        
+    public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        ShortVectorIndividual i = (ShortVectorIndividual) ind;
+        short tmp;
+        int point;
+
+        if (genome.length != i.genome.length)
+            state.output.fatal("Genome lengths are not the same for fixed-length vector crossover");
+        switch(s.crossoverType)
+            {
+            case VectorSpecies.C_ONE_POINT:
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                for(int x=0;x<point*s.chunksize;x++)
+                    { 
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x]; 
+                    genome[x] = tmp; 
+                    }
+                break;
+            case VectorSpecies.C_TWO_POINT: 
+                int point0 = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                point = state.random[thread].nextInt((genome.length / s.chunksize)+1);
+                if (point0 > point) { int p = point0; point0 = point; point = p; }
+                for(int x=point0*s.chunksize;x<point*s.chunksize;x++)
+                    {
+                    tmp = i.genome[x];
+                    i.genome[x] = genome[x];
+                    genome[x] = tmp;
+                    }
+                break;
+            case VectorSpecies.C_ANY_POINT:
+                for(int x=0;x<genome.length/s.chunksize;x++) 
+                    if (state.random[thread].nextBoolean(s.crossoverProbability))
+                        for(int y=x*s.chunksize;y<(x+1)*s.chunksize;y++)
+                            {
+                            tmp = i.genome[y];
+                            i.genome[y] = genome[y];
+                            genome[y] = tmp;
+                            }
+                break;
+            case VectorSpecies.C_LINE_RECOMB:
+            {
+            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                min = s.minGene(x);
+                max = s.maxGene(x);
+                t = (long) Math.floor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                u = (long) Math.floor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                if (!(t < min || t > max || u < min || u > max))
+                    {
+                    genome[x] = (short) t;
+                    i.genome[x] = (short) u; 
+                    }
+                }
+            }
+            break;
+            case VectorSpecies.C_INTERMED_RECOMB:
+            {
+            long t,u;
+            long min, max;
+            for (int x = 0; x < genome.length; x++)
+                {
+                do
+                    {
+                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
+                    min = s.minGene(x);
+                    max = s.maxGene(x);
+                    t = (long) Math.floor(alpha * genome[x] + (1 - alpha) * i.genome[x] + 0.5);
+                    u = (long) Math.floor(beta * i.genome[x] + (1 - beta) * genome[x] + 0.5);
+                    } while (t < min || t > max || u < min || u > max);
+                genome[x] = (short) t;
+                i.genome[x] = (short) u; 
+                }
+            }
+            break;
+            }
+        }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length */
+    public void split(int[] points, Object[] pieces)
+        {
+        int point0, point1;
+        point0 = 0; point1 = points[0];
+        for(int x=0;x<pieces.length;x++)
+            {
+            pieces[x] = new short[point1-point0];
+            System.arraycopy(genome,point0,pieces[x],0,point1-point0);
+            point0 = point1;
+            if (x >=pieces.length-2)
+                point1 = genome.length;
+            else point1 = points[x+1];
+            }
+        }
+    
+    /** Joins the n pieces and sets the genome to their concatenation.*/
+    public void join(Object[] pieces)
+        {
+        int sum=0;
+        for(int x=0;x<pieces.length;x++)
+            sum += ((short[])(pieces[x])).length;
+        
+        int runningsum = 0;
+        short[] newgenome = new short[sum];
+        for(int x=0;x<pieces.length;x++)
+            {
+            System.arraycopy(pieces[x], 0, newgenome, runningsum, ((short[])(pieces[x])).length);
+            runningsum += ((short[])(pieces[x])).length;
+            }
+        // set genome
+        genome = newgenome;
+        }
+
+    /** Destructively mutates the individual in some default manner.  The default form
+        simply randomizes genes to a uniform distribution from the min and max of the gene values. */
+    public void defaultMutate(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        if (s.mutationProbability>0.0)
+            for(int x=0;x<genome.length;x++)
+                if (state.random[thread].nextBoolean(s.mutationProbability))
+                    genome[x] = (short)((int)s.minGene(x) + state.random[thread].nextInt((int)s.maxGene(x)-(int)s.minGene(x)+1));
+        }
+        
+    
+
+    /** Initializes the individual by randomly choosing Shorts uniformly from mingene to maxgene. */
+    public void reset(EvolutionState state, int thread)
+        {
+        IntegerVectorSpecies s = (IntegerVectorSpecies) species;
+        for(int x=0;x<genome.length;x++)
+            genome[x] = (short)((int)s.minGene(x) + state.random[thread].nextInt((int)s.maxGene(x)-(int)s.minGene(x)+1));
+        }
+
+    public int hashCode()
+        {
+        // stolen from GPIndividual.  It's a decent algorithm.
+        int hash = this.getClass().hashCode();
+
+        hash = ( hash << 1 | hash >>> 31 );
+        for(int x=0;x<genome.length;x++)
+            hash = ( hash << 1 | hash >>> 31 ) ^ genome[x];
+
+        return hash;
+        }
+
+    public String genotypeToStringForHumans()
+        {
+        String s = "";
+        for( int i = 0 ; i < genome.length ; i++ )
+            s = s + " " + genome[i];
+        return s;
+        }
+        
+    public String genotypeToString()
+        {
+        StringBuffer s = new StringBuffer();
+        s.append( Code.encode( genome.length ) );
+        for( int i = 0 ; i < genome.length ; i++ )
+            s.append( Code.encode( genome[i] ) );
+        return s.toString();
+        }
+
+    protected void parseGenotype(final EvolutionState state,
+        final LineNumberReader reader) throws IOException
+        {
+        // read in the next line.  The first item is the number of genes
+        String s = reader.readLine();
+        DecodeReturn d = new DecodeReturn(s);
+        Code.decode( d );
+        int lll = (int)(d.l);
+
+        genome = new short[ lll ];
+
+        // read in the genes
+        for( int i = 0 ; i < genome.length ; i++ )
+            {
+            Code.decode( d );
+            genome[i] = (short)(d.l);
+            }
+        }
+
+    public boolean equals(Object ind)
+        {
+        if (!(this.getClass().equals(ind.getClass()))) return false; // SimpleRuleIndividuals are special.
+        ShortVectorIndividual i = (ShortVectorIndividual)ind;
+        if( genome.length != i.genome.length )
+            return false;
+        for( int j = 0 ; j < genome.length ; j++ )
+            if( genome[j] != i.genome[j] )
+                return false;
+        return true;
+        }
+
+    public Object getGenome()
+        { return genome; }
+    public void setGenome(Object gen)
+        { genome = (short[]) gen; }
+    public int genomeLength()
+        { return genome.length; }
+        
+    public void writeGenotype(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        dataOutput.writeInt(genome.length);
+        for(int x=0;x<genome.length;x++)
+            dataOutput.writeShort(genome[x]);
+        }
+
+    public void readGenotype(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        int len = dataInput.readInt();
+        if (genome==null || genome.length != len)
+            genome = new short[len];
+        for(int x=0;x<genome.length;x++)
+            genome[x] = dataInput.readShort();
+        }
+
+    /** Clips each gene value to be within its specified [min,max] range. */
+    public void clamp() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            {
+            short minGene = (short)_species.minGene(i);
+            if (genome[i] < minGene)
+                genome[i] = minGene;
+            else 
+                {
+                short maxGene = (short)_species.maxGene(i);
+                if (genome[i] > maxGene)
+                    genome[i] = maxGene;
+                }
+            }
+        }
+                
+    public void setGenomeLength(int len)
+        {
+        short[] newGenome = new short[len];
+        System.arraycopy(genome, 0, newGenome, 0, 
+            genome.length < newGenome.length ? genome.length : newGenome.length);
+        genome = newGenome;
+        }
+
+    /** Returns true if each gene value is within is specified [min,max] range. */
+    public boolean isInRange() 
+        {
+        IntegerVectorSpecies _species = (IntegerVectorSpecies)species;
+        for (int i = 0; i < genomeLength(); i++)
+            if (genome[i] < _species.minGene(i) ||
+                genome[i] > _species.maxGene(i)) return false;
+        return true;
+        }
+
+    public double distanceTo(Individual otherInd)
+        {               
+        if (!(otherInd instanceof ShortVectorIndividual)) 
+            return super.distanceTo(otherInd);  // will return infinity!
+                
+        ShortVectorIndividual other = (ShortVectorIndividual) otherInd;
+        short[] otherGenome = other.genome;
+        double sumSquaredDistance =0.0;
+        for(int i=0; i < other.genomeLength(); i++)
+            {
+            long dist = this.genome[i] - (long)otherGenome[i];
+            sumSquaredDistance += dist*dist;
+            }
+        return StrictMath.sqrt(sumSquaredDistance);
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorDefaults.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorDefaults.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorDefaults.java	(revision 6152)
@@ -0,0 +1,36 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+
+/* 
+ * VectorDefaults.java
+ * 
+ * Created: Thu Mar 22 13:22:30 2001
+ * By: Liviu Panait
+ */
+
+/**
+ * Vector defaults is the basic defaults class for the Vector package.
+ *
+ * @author Liviu Panait
+ * @version 1.0 
+ */
+
+public final class VectorDefaults implements DefaultsForm
+    {
+    public static final String P_VECTOR = "vector";
+
+    /** Returns the default base. */
+    public static final Parameter base()
+        {
+        return new Parameter(P_VECTOR);
+        }    
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorGene.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorGene.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorGene.java	(revision 6152)
@@ -0,0 +1,169 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+import ec.util.*;
+import java.io.*;
+
+
+/*
+ * VectorGene.java
+ * Created: Thu Mar 22 13:13:20 EST 2001
+ */
+
+/**
+ * VectorGene is an abstract superclass of objects which may be used in
+ * the genome array of GeneVectorIndividuals.
+ *
+
+ * <p>In addition to serialization for checkpointing, VectorGenes may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeGene(...,DataOutput)/readGene(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives a VectorGene in binary.  It is the most efficient approach to sending
+ * VectorGenes over networks, etc.  The default versions of writeGene/readGene throw errors.
+ * You don't need to implement them if you don't plan on using read/writeGene.
+ *
+ * <li><b>printGene(...,PrintWriter)/readGene(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives a VectorGene in text encoded such that the VectorGene is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readGene</b>
+ * reads in a line, then calls <b>readGeneFromString</b> on that line.
+ * You are responsible for implementing readGeneFromString: the Code class is there to help you.
+ * The default version throws an error if called.
+ * <b>printGene</b> calls <b>printGeneToString<b>
+ * and printlns the resultant string. You are responsible for implementing the printGeneToString method in such
+ * a way that readGeneFromString can read back in the VectorGene println'd with printGeneToString.  The default form
+ * of printGeneToString() simply calls <b>toString()</b> 
+ * by default.  You might override <b>printGeneToString()</b> to provide better information.   You are not required to implement these methods, but without
+ * them you will not be able to write VectorGenes to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printGeneForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints a VectorGene in a fashion intended for human consumption only.
+ * <b>printGeneForHumans</b> calls <b>printGeneToStringForHumans()<b> 
+ * and printlns the resultant string.  The default form of this method just returns the value of
+ * <b>toString()</b>. You may wish to override this to provide more information instead. 
+ * You should handle one of these methods properly
+ * to ensure VectorGenes can be printed by ECJ.
+ * </ul>
+
+ <p><b>Default Base</b><br>
+ vector.vect-gene
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+public abstract class VectorGene implements Prototype
+    {
+    public static final String P_VECTORGENE = "vect-gene";
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // nothing by default
+        }
+        
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_VECTORGENE);
+        }
+    
+    public Object clone()
+        {
+        try { return super.clone(); }
+        catch (CloneNotSupportedException e) 
+            { throw new InternalError(); } // never happens
+        }
+        
+
+
+    /** Generates a hash code for this gene -- the rule for this is that the hash code
+        must be the same for two genes that are equal to each other genetically. */
+    public abstract int hashCode();
+    
+    /** Unlike the standard form for Java, this function should return true if this
+        gene is "genetically identical" to the other gene. */
+    public abstract boolean equals( final Object other );
+
+    /**
+       The reset method randomly reinitializes the gene.
+    */
+    public abstract void reset(final EvolutionState state, final int thread);
+
+    /**
+       Mutate the gene.  The default form just resets the gene.
+    */
+    public void mutate(final EvolutionState state, final int thread)
+        {
+        reset(state,thread);
+        }
+
+    /**
+       Nice printing.  The default form simply calls printGeneToStringForHumans and prints the result, 
+       but you might want to override this.
+    */
+    public void printGeneForHumans( final EvolutionState state, final int verbosity, final int log )
+        {  state.output.println(printGeneToStringForHumans(),log); }
+
+    /** Prints the gene to a string in a human-readable fashion.  The default simply calls toString(). */
+    public String printGeneToStringForHumans()
+        { return toString(); }
+
+    /** Prints the gene to a string in a fashion readable by readGeneFromString and parseable by readGene(state, reader).
+        Override this.  The default form returns toString(). */
+    public String printGeneToString()
+        { return toString(); }
+
+    /** Reads a gene from a string, which may contain a final '\n'.
+        Override this method.  The default form generates an error.
+    */
+    public void readGeneFromString(final String string, final EvolutionState state)
+        { state.output.error("readGeneFromString(string,state) unimplemented in " + this.getClass()); }
+
+    /**
+       Prints the gene in a way that can be read by readGene().  The default form simply
+       calls printGeneToString().   Override this gene to do custom writing to the log,
+       or just override printGeneToString(...), which is probably easier to do.
+    */
+    public void printGene( final EvolutionState state, final int verbosity, final int log )
+        { state.output.println(printGeneToString(),log); }
+
+    /**
+       Prints the gene in a way that can be read by readGene().  The default form simply
+       calls printGeneToString(state).   Override this gene to do custom writing,
+       or just override printGeneToString(...), which is probably easier to do.
+    */
+    public void printGene( final EvolutionState state, final PrintWriter writer )
+        { writer.println(printGeneToString()); }
+
+    /**
+       Reads a gene printed by printGene(...).  The default form simply reads a line into
+       a string, and then calls readGeneFromString() on that line.  Override this gene to do
+       custom reading, or just override readGeneFromString(...), which is probably easier to do.
+    */
+    public void readGene(final EvolutionState state,
+        final LineNumberReader reader)
+        throws IOException
+        { readGeneFromString(reader.readLine(),state); }
+
+    /** Override this if you need to write rules out to a binary stream */
+    public void writeGene(final EvolutionState state,
+        final DataOutput dataOutput) throws IOException
+        {
+        state.output.fatal("writeGene(EvolutionState, DataOutput) not implemented in " + this.getClass());
+        }
+
+    /** Override this if you need to read rules in from a binary stream */
+    public void readGene(final EvolutionState state,
+        final DataInput dataInput) throws IOException
+        {
+        state.output.fatal("readGene(EvolutionState, DataInput) not implemented in " + this.getClass());
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorIndividual.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorIndividual.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorIndividual.java	(revision 6152)
@@ -0,0 +1,148 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.*;
+
+/*
+ * VectorIndividual.java
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ */
+
+/**
+ * VectorIndividual is the abstract superclass of simple individual representations
+ * which consist of vectors of values (booleans, integers, floating-point, etc.)
+ *
+ * <p>This class contains two methods, defaultCrossover and defaultMutate, which can
+ * be overridden if all you need is a simple crossover and a simple mutate mechanism.
+ * the VectorCrossoverPipeline and VectorMutationPipeline classes use these methods to do their
+ * handiwork.  For more sophisticated crossover and mutation, you'll need to write
+ * a custom breeding pipeline.
+ *
+ * <p>The <i>kind</i> of default crossover and mutation, and associated information,
+ * is stored in the VectorIndividual's VectorSpecies object, which is obtained through
+ * the <tt>species</tt> variable.  For example, 
+ * VectorIndividual assumes three common types of crossover as defined in VectorSpecies
+ * which you should implement in your defaultCrossover method: one-point, 
+ * two-point, and any-point (otherwise known as "uniform") crossover.
+ *
+ * <p>VectorIndividual is typically used for fixed-length vector representations;
+ * however, it can also be used with variable-length representations.  Two methods have
+ * been provided in all subclasses of VectorIndividual to help you there: split and
+ * join, which you can use to break up and reconnect VectorIndividuals in a variety
+ * of ways.  Note that you may want to override the reset() method to create individuals
+ * with different initial lengths.
+ *
+ * <p>VectorIndividuals must belong to the species VectorSpecies (or some subclass of it).
+ *
+ 
+ * <P><b>From ec.Individual:</b>
+ *
+ * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
+ *
+ * <ul>
+ * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
+ * transmits or receives an individual in binary.  It is the most efficient approach to sending
+ * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
+ * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your 
+ * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
+ * You don't need to implement them if you don't plan on using read/writeIndividual.
+ *
+ * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
+ * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
+ * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
+ * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
+ * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
+ * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
+ * You are responsible for implementing parseGenotype: the Code class is there to help you.
+ * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
+ * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
+ * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
+ * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
+ * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
+ *
+ * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
+ * approach prints an individual in a fashion intended for human consumption only.
+ * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b> 
+ * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
+ * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
+ * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
+ * to ensure individuals can be printed by ECJ.
+ * </ul>
+
+ * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
+ * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
+ * a VectorIndividual or subclass, you'll need to read/write those variables as well.
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public abstract class VectorIndividual extends Individual
+    {
+    /** Destructively crosses over the individual with another in some default manner.  In most
+        implementations provided in ECJ, one-, two-, and any-point crossover is done with a 
+        for loop, rather than a possibly more efficient approach like arrayCopy().  The disadvantage
+        is that arrayCopy() takes advantage of a CPU's bulk copying.  The advantage is that arrayCopy()
+        would require a scratch array, so you'd be allocing and GCing an array for every crossover.
+        Dunno which is more efficient.  */
+    public void defaultCrossover(EvolutionState state, int thread, 
+        VectorIndividual ind) { }
+
+    /** Destructively mutates the individual in some default manner.  The default version calls reset()*/
+    public void defaultMutate(EvolutionState state, int thread) { reset(state,thread); }
+
+    /** Initializes the individual. */
+    public abstract void reset(EvolutionState state, int thread);
+
+    /** Returns the gene array.  If you know the type of the array, you can cast it and work on
+        it directly.  Otherwise, you can still manipulate it in general, because arrays (like
+        all objects) respond to clone() and can be manipulated with arrayCopy without bothering
+        with their type.  This might be useful in creating special generalized crossover operators
+        -- we apologize in advance for the fact that Java doesn't have a template system.  :-( 
+        The default version returns null. */
+    public Object getGenome() { return null; }
+    
+    /** Sets the gene array.  See getGenome().  The default version does nothing.
+     */
+    public void setGenome(Object gen) { }
+
+    /** Returns the length of the gene array.  By default, this method returns 0. */
+    public int genomeLength() { return 0; }
+
+    /** Initializes the individual to a new size.  Only use this if you need to initialize variable-length individuals. */
+    public void reset(EvolutionState state, int thread, int newSize)
+        {
+        setGenomeLength(newSize);
+        reset(state, thread);
+        }
+
+    /** Sets the genome length.  If the length is longer, then it is filled with a default value (likely 0 or false).
+        This may or may not be a valid value -- you will need to set appropriate values here. 
+        The default implementation does nothing; but all subclasses in ECJ implement a subset of this. */
+    public void setGenomeLength(int len) { }
+
+    /** Splits the genome into n pieces, according to points, which *must* be sorted. 
+        pieces.length must be 1 + points.length.  The default form does nothing -- be careful
+        not to use this method if it's not implemented!  It should be trivial to implement it
+        for your genome -- just like at the other implementations.  */
+    public void split(int[] points, Object[] pieces) { }
+
+    /** Joins the n pieces and sets the genome to their concatenation.  The default form does nothing. 
+        It should be trivial to implement it
+        for your genome -- just like at the other implementations.  */
+    public void join(Object[] pieces) { }
+
+    /** Clones the genes in pieces, and replaces the genes with their copies.  Does NOT copy the array, but modifies it in place.
+        If the VectorIndividual holds numbers or booleans etc. instead of genes, nothing is cloned
+        (why bother?). */
+    public void cloneGenes(Object piece) { }  // default does nothing.
+    
+    public long size() { return genomeLength(); }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorSpecies.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorSpecies.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/VectorSpecies.java	(revision 6152)
@@ -0,0 +1,350 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector;
+
+import ec.util.*;
+import java.io.*;
+import ec.*;
+
+/* 
+ * VectorSpecies.java
+ * 
+ * Created: Thu Mar 22 17:44:00 2001
+ * By: Liviu Panait
+ */
+
+/**
+ * VectorSpecies is a species which can create VectorIndividuals.  Different
+ * VectorSpecies are used for different kinds of VectorIndividuals: a plain
+ * VectorSpecies is probably only applicable for BitVectorIndividuals.
+ * 
+ * <p>VectorSpecies supports the following recombination methods:</p>
+ * <ul>
+ * <li><b>One-point crossover</b>.</li>
+ * <li><b>Two-point crossover</b>.</li>
+ * <li><b>Uniform crossover</b> - inaccurately called "any-point".</li>
+ * <li><b>Line recombination</b> - children are random points on a line between
+ *      the two parents.</li>
+ * <li><b>Intermediate recombination</b> - the value of each component of the
+ *      vector is between the values of that component of the parent vectors.
+ *      </li>
+ * </ul>
+ * <p>Note that for LongVectorIndividuals, there are certain values that will
+ * never be created by line and intermediate recombination, because the
+ * recombination is calculated using doubles and then rounded to the nearest
+ * long. For large enough values (but still smaller than the maximum long), the
+ * difference between one double and the next is greater than one.</p>
+ *
+ * <p>VectorSpecies has three wasy to determine the initial size of the individual:</p>
+ * <ul>
+ * <li><b>A fixed size</b>.</li>
+ * <li><b>Geometric distribution</b>.</li>
+ * <li><b>Uniform distribution</b></li>
+ * </ul>
+ *
+ * <p>If the algorithm used is the geometric distribution, the VectorSpecies starts at a
+ * minimum size and continues flipping a coin with a certain "resize probability",
+ * increasing the size each time, until the coin comes up tails (fails).  The chunk size
+ * must be 1 in this case.
+ *
+ * <p> If the algorithm used is the uniform distribution, the VectorSpecies picks a random
+ * size between a provided minimum and maximum size, inclusive.  The chunk size
+ * must be 1 in this case.
+ *
+ * <p>If the size is fixed, then you can also provide a "chunk size" which constrains the
+ * locations in which crossover can be performed (only along chunk boundaries).  The genome
+ * size must be a multiple of the chunk size in this case.
+ *
+ * <p>VectorSpecies also contains a number of parameters guiding how the individual
+ * crosses over and mutates.
+ 
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>genome-size</tt><br>
+ <font size=-1>int &gt;= 1 or one of: geometric, uniform</font></td>
+ <td valign=top>(size of the genome, or if 'geometric' or 'uniform', the algorithm used to size the initial genome)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>chunk-size</tt><br>
+ <font size=-1>1 &lt;= int &lt;= genome-size (default=1)</font></td>
+ <td valign=top>(the chunk size for crossover (crossover will only occur on chunk boundaries))</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>geometric-prob</tt><br>
+ <font size=-1>0.0 &lt;= float &lt; 1.0</font></td>
+ <td valign=top>(the coin-flip probability for increasing the initial size using the geometric distribution)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>min-initial-size</tt><br>
+ <font size=-1>int &gt;= 0</font></td>
+ <td valign=top>(the minimum initial size of the genome)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>max-initial-size</tt><br>
+ <font size=-1>int &gt;= min-initial-size</font></td>
+ <td valign=top>(the maximum initial size of the genome)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>crossover-type</tt><br>
+ <font size=-1>string, one of: one, two, any</font></td>
+ <td valign=top>(default crossover type (one-point, two-point, any-point (uniform), line, or intermediate)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>crossover-prob</tt><br>
+ <font size=-1>0.0 &gt;= float &gt;= 1.0 </font></td>
+ <td valign=top>(probability that a gene will get crossed over during any-point crossover)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>mutation-prob</tt><br>
+ <font size=-1>0.0 &lt;= float &lt;= 1.0 </font></td>
+ <td valign=top>(probability that a gene will get mutated over default mutation)</td></tr>
+
+ <tr><td valign=top><i>base</i>.<tt>line-extension</tt><br>
+ <font size=-1>float &gt;= 0.0 </font></td>
+ <td valign=top>(for line and intermediate recombination, how far along the line or outside of the hypercube children can be. If this value is zero, all children must be within the hypercube.)
+
+ </table>
+
+ <p><b>Default Base</b><br>
+ vector.species
+
+ * @author Sean Luke and Liviu Panait
+ * @version 1.0 
+ */
+
+public class VectorSpecies extends Species
+    {
+    public static final String P_VECTORSPECIES = "species";
+
+    public final static String P_CROSSOVERTYPE = "crossover-type";
+    public final static String P_CHUNKSIZE = "chunk-size";
+    public final static String V_ONE_POINT = "one";
+    public final static String V_TWO_POINT = "two";
+    public final static String V_ANY_POINT = "any";
+    public final static String V_LINE_RECOMB = "line";
+    public final static String V_INTERMED_RECOMB = "intermediate";
+    public final static String V_SIMULATED_BINARY = "sbx";
+    public final static String P_CROSSOVER_DISTRIBUTION_INDEX = "crossover-distribution-index";
+    public final static String P_MUTATIONPROB = "mutation-prob";
+    public final static String P_CROSSOVERPROB = "crossover-prob";
+    public final static String P_GENOMESIZE = "genome-size";
+    public final static String P_LINEDISTANCE = "line-extension";
+    public final static String V_GEOMETRIC = "geometric";
+    public final static String P_GEOMETRIC_PROBABILITY = "geometric-prob";
+    public final static String V_UNIFORM = "uniform";
+    public final static String P_UNIFORM_MIN = "min-initial-size";
+    public final static String P_UNIFORM_MAX = "max-initial-size";
+
+    public final static int C_ONE_POINT = 0;
+    public final static int C_TWO_POINT = 1;
+    public final static int C_ANY_POINT = 128;
+    public final static int C_LINE_RECOMB = 256;
+    public final static int C_INTERMED_RECOMB = 512;
+    public final static int C_SIMULATED_BINARY = 1024;
+    public final static int C_NONE = 0;
+    public final static int C_GEOMETRIC = 1;
+    public final static int C_UNIFORM = 2;
+
+    /** Probability that a gene will mutate */
+    public float mutationProbability;
+    /** Probability that a gene will cross over -- ONLY used in V_ANY_POINT crossover */
+    public float crossoverProbability;
+    /** What kind of crossover do we have? */
+    public int crossoverType;
+    /** How big of a genome should we create on initialization? */
+    public int genomeSize;
+    /** What should the SBX distribution index be? */
+    public int crossoverDistributionIndex;
+    /** How should we reset the genome? */
+    public int genomeResizeAlgorithm;
+    /** What's the smallest legal genome? */
+    public int minInitialSize;
+    /** What's the largest legal genome? */
+    public int maxInitialSize;
+    /** With what probability would our genome be at least 1 larger than it is now during initialization? */
+    public float genomeIncreaseProbability;
+    /** How big of chunks should we define for crossover? */
+    public int chunksize;
+    /** How far along the long a child can be located for line or intermediate recombination */
+    public double lineDistance;
+    /** Was the initial size determined dynamically? */
+    public boolean dynamicInitialSize = false;
+
+    // we use warned here because it's quite a bit faster than calling warnOnce
+    protected boolean warned = false;
+    EvolutionState state;
+    protected void warnAboutGene(int gene)
+        {
+        state.output.warnOnce("Attempt to access maxGene or minGene from IntegerVectorSpecies beyond initial genomeSize.\n" +
+            "From now on, maxGene(a) = maxGene(maxGeneIndex) for a >= maxGeneIndex.  Likewise for minGene(...)");
+        warned = true;
+        }
+    
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_VECTORSPECIES);
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        // setup constraints  FIRST so the individuals can see them when they're
+        // set up.
+        
+        Parameter def = defaultBase();
+        
+        this.state = state;
+        
+        String genomeSizeForm = state.parameters.getString(base.push(P_GENOMESIZE),def.push(P_GENOMESIZE));
+        if (genomeSizeForm == null) // clearly an error
+            {
+            state.output.fatal("No genome size specified.", base.push(P_GENOMESIZE),def.push(P_GENOMESIZE));
+            }
+        else if (genomeSizeForm.equals(V_GEOMETRIC))
+            {
+            dynamicInitialSize = true;
+            genomeSize = 1;
+            genomeResizeAlgorithm = C_GEOMETRIC;
+            chunksize = state.parameters.getIntWithDefault(base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE),1);
+            if (chunksize != 1)
+                state.output.fatal("To use Geometric size initialization, VectorSpecies must have a chunksize of 1",
+                    base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE));
+            minInitialSize = state.parameters.getInt(base.push(P_UNIFORM_MIN),def.push(P_UNIFORM_MIN), 0);
+            if (minInitialSize < 0)
+                {
+                state.output.warning("Gemoetric size initialization used, but no minimum initial size provided.  Assuming minimum is 0.");
+                minInitialSize = 0;
+                }
+            genomeIncreaseProbability = state.parameters.getFloatWithMax(base.push(P_GEOMETRIC_PROBABILITY),def.push(P_GEOMETRIC_PROBABILITY),0.0, 1.0);
+            if (genomeIncreaseProbability < 0.0 || genomeIncreaseProbability >= 1.0)  // note >=
+                state.output.fatal("To use Gemoetric size initialization, the genome increase probability must be >= 0.0 and < 1.0",
+                    base.push(P_GEOMETRIC_PROBABILITY),def.push(P_GEOMETRIC_PROBABILITY));
+            }
+        else if (genomeSizeForm.equals(V_UNIFORM))
+            {
+            dynamicInitialSize = true;
+            genomeSize = 1;
+            genomeResizeAlgorithm = C_UNIFORM;
+            chunksize = state.parameters.getIntWithDefault(base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE),1);
+            if (chunksize != 1)
+                state.output.fatal("To use Uniform size initialization, VectorSpecies must have a chunksize of 1",
+                    base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE));
+            minInitialSize = state.parameters.getInt(base.push(P_UNIFORM_MIN),def.push(P_UNIFORM_MIN),0);
+            if (minInitialSize < 0)
+                state.output.fatal("To use Uniform size initialization, you must set a minimum initial size >= 0",
+                    base.push(P_UNIFORM_MIN),def.push(P_UNIFORM_MIN));
+            maxInitialSize = state.parameters.getInt(base.push(P_UNIFORM_MAX),def.push(P_UNIFORM_MAX),0);
+            if (maxInitialSize < 0)
+                state.output.fatal("To use Uniform size initialization, you must set a maximum initial size >= 0",
+                    base.push(P_UNIFORM_MAX),def.push(P_UNIFORM_MAX));
+            if (maxInitialSize < minInitialSize)
+                state.output.fatal("To use Uniform size initialization, you must set a maximum initial size >= the minimum initial size",
+                    base.push(P_UNIFORM_MAX),def.push(P_UNIFORM_MAX));
+            }
+        else  // it's a number
+            {
+            genomeSize = state.parameters.getInt(base.push(P_GENOMESIZE),def.push(P_GENOMESIZE),1);
+            if (genomeSize==0)
+                state.output.error("VectorSpecies must have a genome size > 0",
+                    base.push(P_GENOMESIZE),def.push(P_GENOMESIZE));
+                        
+            genomeResizeAlgorithm = C_NONE;
+
+            chunksize = state.parameters.getIntWithDefault(base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE),1);
+            if (chunksize <= 0 || chunksize > genomeSize)
+                state.output.fatal("VectorSpecies must have a chunksize which is > 0 and < genomeSize",
+                    base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE));
+            if (genomeSize % chunksize != 0)
+                state.output.fatal("VectorSpecies must have a genomeSize which is a multiple of chunksize",
+                    base.push(P_CHUNKSIZE),def.push(P_CHUNKSIZE));
+            }
+                                
+        mutationProbability = state.parameters.getFloatWithMax(
+            base.push(P_MUTATIONPROB),def.push(P_MUTATIONPROB),0.0,1.0);
+        if (mutationProbability==-1.0)
+            state.output.error("VectorSpecies must have a mutation probability between 0.0 and 1.0 inclusive",
+                base.push(P_MUTATIONPROB),def.push(P_MUTATIONPROB));
+    
+        String ctype = state.parameters.getStringWithDefault(base.push(P_CROSSOVERTYPE), def.push(P_CROSSOVERTYPE), null);
+        crossoverType = C_ONE_POINT;
+        if (ctype==null)
+            state.output.warning("No crossover type given for VectorSpecies, assuming one-point crossover",
+                base.push(P_CROSSOVERTYPE),def.push(P_CROSSOVERTYPE));
+        else if (ctype.equalsIgnoreCase(V_ONE_POINT))
+            crossoverType=C_ONE_POINT;  // redundant
+        else if (ctype.equalsIgnoreCase(V_TWO_POINT))
+            crossoverType=C_TWO_POINT;
+        else if (ctype.equalsIgnoreCase(V_ANY_POINT))
+            crossoverType=C_ANY_POINT;
+        else if (ctype.equalsIgnoreCase(V_LINE_RECOMB))
+            crossoverType=C_LINE_RECOMB;
+        else if (ctype.equalsIgnoreCase(V_INTERMED_RECOMB))
+            crossoverType=C_INTERMED_RECOMB;
+        else if (ctype.equalsIgnoreCase(V_SIMULATED_BINARY))
+            crossoverType=C_SIMULATED_BINARY;
+        else state.output.error("VectorSpecies given a bad crossover type: " + ctype,
+            base.push(P_CROSSOVERTYPE),def.push(P_CROSSOVERTYPE));
+    
+        if (crossoverType==C_LINE_RECOMB || crossoverType==C_INTERMED_RECOMB)
+            {
+            if (!(this instanceof IntegerVectorSpecies) && !(this instanceof FloatVectorSpecies))
+                state.output.error("Line and intermediate recombinations are only supported by IntegerVectorSpecies and FloatVectorSpecies", base.push(P_CROSSOVERTYPE), def.push(P_CROSSOVERTYPE));
+            lineDistance = state.parameters.getDouble(
+                base.push(P_LINEDISTANCE), def.push(P_LINEDISTANCE), 0.0);
+            if (lineDistance==-1.0)
+                state.output.error("If it's going to use line or intermediate recombination, VectorSpecies needs a line extension >= 0.0  (0.25 is common)", base.push(P_LINEDISTANCE), def.push(P_LINEDISTANCE));
+            }
+        else lineDistance = 0.0;
+
+        if (crossoverType==C_ANY_POINT)
+            {
+            crossoverProbability = state.parameters.getFloatWithMax(
+                base.push(P_CROSSOVERPROB),def.push(P_CROSSOVERPROB),0.0,0.5);
+            if (crossoverProbability==-1.0)
+                state.output.error("If it's going to use any-point crossover, VectorSpecies must have a crossover probability between 0.0 and 0.5 inclusive",
+                    base.push(P_CROSSOVERPROB),def.push(P_CROSSOVERPROB));
+            }
+        else crossoverProbability = 0.0f;
+
+        if (crossoverType==C_SIMULATED_BINARY)
+            {
+            if (!(this instanceof FloatVectorSpecies))
+                state.output.error("Simulated binary crossover (SBX) is only supported by FloatVectorSpecies", base.push(P_CROSSOVERTYPE), def.push(P_CROSSOVERTYPE));
+            crossoverDistributionIndex = state.parameters.getInt(base.push(P_CROSSOVER_DISTRIBUTION_INDEX), def.push(P_CROSSOVER_DISTRIBUTION_INDEX), 0);
+            if (crossoverDistributionIndex < 0)
+                state.output.fatal("If FloatVectorSpecies is going to use simulated binary crossover (SBX), the distribution index must be defined and >= 0.",
+                    base.push(P_CROSSOVER_DISTRIBUTION_INDEX), def.push(P_CROSSOVER_DISTRIBUTION_INDEX));
+            }
+        else crossoverProbability = 0.0f;
+
+        state.output.exitIfErrors();
+                
+        if (crossoverType != C_ANY_POINT && state.parameters.exists(base.push(P_CROSSOVERPROB),def.push(P_CROSSOVERPROB)))
+            state.output.warning("The 'crossover-prob' parameter may only be used with any-point crossover.  It states the probability that a particular gene will be crossed over.  If you were looking for the probability of crossover happening at *all*, look at the 'likelihood' parameter.",
+                base.push(P_CROSSOVERPROB),def.push(P_CROSSOVERPROB));
+        
+        // NOW call super.setup(...), which will in turn set up the prototypical individual
+        super.setup(state,base);
+        }
+
+    public Individual newIndividual(final EvolutionState state, int thread) 
+        
+        {
+        VectorIndividual newind = (VectorIndividual)(super.newIndividual(state, thread));
+
+        if (genomeResizeAlgorithm == C_NONE)
+            newind.reset( state, thread );
+        else if (genomeResizeAlgorithm == C_UNIFORM)
+            {
+            int size = state.random[thread].nextInt(maxInitialSize - minInitialSize + 1) + minInitialSize;
+            newind.reset(state, thread, size);
+            }
+        else if (genomeResizeAlgorithm == C_GEOMETRIC)
+            {
+            int size = minInitialSize;
+            while(state.random[thread].nextBoolean(genomeIncreaseProbability)) size++;
+            newind.reset(state, thread, size);
+            }
+                        
+        return newind;
+        }
+    }
+
+
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/GeneDuplicationPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/GeneDuplicationPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/GeneDuplicationPipeline.java	(revision 6152)
@@ -0,0 +1,115 @@
+/*
+  Copyright 2010 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.vector.breed;
+
+import ec.BreedingPipeline;
+import ec.EvolutionState;
+import ec.Individual;
+import ec.SelectionMethod;
+import ec.util.Parameter;
+import ec.vector.*;
+
+/**
+ * <p>GeneDuplicationPipeline is designed to duplicate a sequence of genes from the chromosome and append
+ * them to the end of the chromosome.  The sequence of genes copied are randomly determined.  That is to
+ * say a random begining index is selected and a random ending index is selected from the chromosome.  Then
+ * this area is then copied (begining inclusive, ending exclusive) and appended to the end of the chromosome.
+ * Since randomness is a factor several checks are performed to make sure the begining and ending indicies are
+ * valid.  For example, since the ending index is exclusive, the ending index cannot equal the begining index (a
+ * new ending index would be randomly seleceted in this case).  Likewise the begining index cannot be larger than the
+ * ending index (they would be swapped in this case).</p>
+ *
+ * <p><b>Default Base</b><br>
+ * ec.vector.breed.GeneDuplicationPipeline
+ *
+ * @author Sean Luke, Joseph Zelibor III, and Eric Kangas
+ * @version 1.0
+ */
+public class GeneDuplicationPipeline extends BreedingPipeline
+    {
+    public static final String P_DUPLICATION = "duplicate";
+    public static final int NUM_SOURCES = 1;
+
+    public Parameter defaultBase()
+        {
+        return VectorDefaults.base().push(P_DUPLICATION);
+        }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public int produce(int min, 
+        int max, 
+        int start, 
+        int subpopulation,
+        Individual[] inds, 
+        EvolutionState state, 
+        int thread) 
+        {
+
+        // grab individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+
+        // now let's mutate 'em
+        for(int q=start; q < n+start; q++)
+            {
+            if (sources[0] instanceof SelectionMethod)
+                inds[q] = (Individual)(inds[q].clone());
+
+            //duplicate from the genome between a random begin and end point,
+            //and put that at the end of the new genome.
+            VectorIndividual ind = (VectorIndividual)(inds[q]);
+            
+            int len = ind.genomeLength();
+
+            //zero length individual, just return
+            if (len == 0)
+                {
+                return n;
+                }
+
+            int end = 0;
+            int begin = state.random[thread].nextInt(len+1);
+            do 
+                {
+                end = state.random[thread].nextInt(len+1);
+                } 
+            while (begin == end);  //because the end is exclusive, start cannot be
+            //equal to end.
+            
+
+            if (end < begin) 
+                {
+                int temp = end;  //swap if necessary
+                end = begin;
+                begin = temp;
+                }
+
+            // copy the original into a new array.
+            Object[] original = new Object[2];
+            ind.split(new int[] {0, len}, original);
+                        
+            // copy the splice into a new array
+            Object[] splice = new Object[3];
+            ind.split(new int[] {begin, end}, splice);
+                        
+            // clone the genes in splice[1] (which we'll concatenate back in) in case we're using GeneVectorIndividual
+            ind.cloneGenes(splice[1]);
+            
+            // appends the pieces together with the splice at the end.
+            ind.join(new Object[] {original[1], splice[1]});
+            }
+        return n;  // number of individuals produced, 1 here.
+        }
+
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/ListCrossoverPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/ListCrossoverPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/ListCrossoverPipeline.java	(revision 6152)
@@ -0,0 +1,361 @@
+/*
+  Copyright 2006 by Sean Luke and George Mason University
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.vector.breed;
+
+/* 
+ * ListCrossoverPipeline.java
+ * 
+ * Created: Sat 23 May 2009 11:57:17 AM EDT
+ * By: Stephen Donnelly
+ */
+ 
+import ec.vector.*;
+import ec.*;
+import ec.util.*;
+
+
+/**
+   ListCrossoverPipeline is a crossover pipeline for vector individuals whose length
+   may be lengthened or shortened.  There are two crossover options available: one-point
+   and two-point.  One-point crossover picks a crossover point for each of the vectors
+   (the crossover point can be different), and then does one-point crossover using those
+   points.  Two-point crossover picks TWO crossover points for each of the vectors (again,
+   the points can be different among the vectors), and swaps the middle regions between
+   the respective crossover points.
+
+   <p>ListCrossoverPipeline will try tries times to meet certain constraints: first,
+   the resulting children must be no smaller than min-child-size.  Second, the amount
+   of material removed from a parent must be no less than mix-crossover-percent and no 
+   more than max-crossover-percent.
+        
+   <p>If toss is true, then only one child is generated, else at most two are generated.
+
+   <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+   2 * minimum typical number of individuals produced by each source, unless toss
+   is set, in which case it's simply the minimum typical number.
+
+   <p><b>Number of Sources</b><br>
+   2
+
+   <p><b>Parameters</b><br>
+   <table>
+   <tr><td valign=top><i>base</i>.<tt>toss</tt><br>
+   <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font>/td>
+   <td valign=top>(after crossing over with the first new individual, should its second sibling individual be thrown away instead of adding it to 
+   the population?)</td></tr>
+
+   <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
+   <font size=-1>int &gt;= 1</font></td>
+   <td valign=top>(number of times to try finding valid crossover points)</td></tr>
+
+   <tr><td valign=top><i>base</i>.<tt>min-child-size</tt><br>
+   <font size=-1>int &gt;= 0 (default)</font></td>
+   <td valign=top>(the minimum allowed size of a child)</td></tr>
+
+   <tr><td valign=top><i>base</i>.<tt>min-crossover-percent</tt><br>
+   <font size=-1>0 (default) &lt;= float &lt;= 1</font></td>
+   <td valign=top>(the minimum percentage of an individual that may be removed during crossover)</td></tr>
+
+   <tr><td valign=top><i>base</i>.<tt>max-crossover-percent</tt><br>
+   <font size=-1>0 &lt;= float &lt;= 1 (default)</font></td>
+   <td valign=top>(the maximum percentage of an individual that may be removed during crossover)</td></tr>
+
+   </table>
+
+   <p><b>Default Base</b><br>
+   vector.list-xover
+
+
+**/
+
+public class ListCrossoverPipeline extends BreedingPipeline
+    {
+    public static final String P_TOSS = "toss";
+    public static final String P_LIST_CROSSOVER = "list-xover";
+    public static final String P_MIN_CHILD_SIZE = "min-child-size";
+    public static final String P_NUM_TRIES = "tries";
+    public static final String P_MIN_CROSSOVER_PERCENT = "min-crossover-percent";
+    public static final String P_MAX_CROSSOVER_PERCENT = "max-crossover-percent";
+    public static final int NUM_SOURCES = 2;
+    
+    public boolean tossSecondParent;
+    public int crossoverType;
+    public int minChildSize;
+    public int numTries;
+    public float minCrossoverPercentage;
+    public float maxCrossoverPercentage;
+    
+    VectorIndividual parents[];
+    
+    public ListCrossoverPipeline() { parents = new VectorIndividual[2]; }
+    public Parameter defaultBase() { return VectorDefaults.base().push(P_LIST_CROSSOVER); }
+
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        ListCrossoverPipeline c = (ListCrossoverPipeline)(super.clone());
+        c.parents = (VectorIndividual[]) parents.clone();
+        return c;
+        }
+   
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        Parameter def = defaultBase();
+        
+        tossSecondParent = state.parameters.getBoolean(base.push(P_TOSS),
+            def.push(P_TOSS),false);
+                                           
+        minChildSize = state.parameters.getIntWithDefault(base.push(P_MIN_CHILD_SIZE),
+            def.push(P_MIN_CHILD_SIZE), 0);
+                                                            
+        numTries = state.parameters.getIntWithDefault(base.push(P_NUM_TRIES),
+            def.push(P_NUM_TRIES), 1);
+                                                         
+        minCrossoverPercentage = state.parameters.getFloatWithDefault(base.push(P_MIN_CROSSOVER_PERCENT),
+            def.push(P_MIN_CROSSOVER_PERCENT), 0.0);
+        maxCrossoverPercentage = state.parameters.getFloatWithDefault(base.push(P_MAX_CROSSOVER_PERCENT),
+            def.push(P_MAX_CROSSOVER_PERCENT), 1.0);
+                                                         
+
+        String crossoverTypeString = state.parameters.getStringWithDefault(base.push(VectorSpecies.P_CROSSOVERTYPE),
+            def.push(VectorSpecies.P_CROSSOVERTYPE),
+            VectorSpecies.V_TWO_POINT);
+                                                                             
+        // determine the crossover method to use (only 1-point & 2-point currently supported)
+        if(crossoverTypeString.equalsIgnoreCase(VectorSpecies.V_ONE_POINT))
+            {
+            crossoverType = VectorSpecies.C_ONE_POINT;
+            }
+        else if(crossoverTypeString.equalsIgnoreCase(VectorSpecies.V_TWO_POINT))
+            {
+            crossoverType = VectorSpecies.C_TWO_POINT;
+            }
+        else
+            {
+            state.output.error("ListCrossoverPipeline:\n:" +
+                "   Parameter crossover-type is currently set to: " + crossoverTypeString + "\n" +
+                "   Currently supported crossover types are \"one\" and \"two\" point.\n");
+            }
+        
+        // sanity check for crossover parameters
+        if(minChildSize < 0)
+            {
+            state.output.error("ListCrossoverPipeline:\n" +
+                "   Parameter min-child-size is currently equal to: " + Integer.toString(minChildSize) + "\n" +
+                "   min-child-size must be a positive integer\n");
+            }
+        
+        if(numTries < 1)
+            {
+            state.output.error("ListCrossoverPipeline:\n" +
+                "   Parameter tries is currently equal to: " + Integer.toString(numTries) + "\n" +
+                "   tries must be greater than or equal to 1\n");
+            }
+                               
+        
+        if(minCrossoverPercentage < 0.0 || minCrossoverPercentage > 1.0)
+            {
+            state.output.error("ListCrossoverPipeline:\n" +
+                "   Parameter min-crossover-percent is currently equal to: " + Float.toString(minCrossoverPercentage) + "\n" +
+                "   min-crossover-percent must be either a real-value float between [0.0, 1.0] or left unspecified\n");
+            }
+        if(maxCrossoverPercentage < 0.0 || maxCrossoverPercentage > 1.0)
+            {
+            state.output.error("ListCrossoverPipeline:\n" +
+                "   Parameter max-crossover-percent is currently equal to: " + Float.toString(maxCrossoverPercentage) + "\n" +
+                "   max-crossover-percent must be either a real-value float between [0.0, 1.0] or left unspecified\n");
+            }
+        if(minCrossoverPercentage > maxCrossoverPercentage)
+            {
+            state.output.error("ListCrossoverPipeline:\n" +
+                "   Parameter min-crossover-percent must be less than max-crossover-percent\n");
+            }
+        if(minCrossoverPercentage == maxCrossoverPercentage)
+            {
+            state.output.warning("ListCrossoverPipeline:\n" +
+                "   Parameter min-crossover-percent and max-crossover-percent are currently equal to: " + 
+                Float.toString(minCrossoverPercentage) + "\n" +
+                "   This effectively prevents any crossover from occurring\n");
+            }
+        }
+    
+    
+    public int typicalIndsProduced()
+        {
+        return (tossSecondParent? minChildProduction(): minChildProduction()*2);
+        }
+        
+    
+    
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+       
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+             
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, true);  // DO produce children from source -- we've not done so already
+
+        for(int q=start;q<n+start; /* no increment */)  // keep on going until we're filled up
+            {
+            // grab two individuals from our sources
+            if (sources[0]==sources[1])  // grab from the same source
+                {
+                sources[0].produce(2,2,0,subpopulation,parents,state,thread);
+                if (!(sources[0] instanceof BreedingPipeline))  // it's a selection method probably
+                    { 
+                    parents[0] = (VectorIndividual)(parents[0].clone());
+                    parents[1] = (VectorIndividual)(parents[1].clone());
+                    }
+                }
+            else // grab from different sources
+                {
+                sources[0].produce(1,1,0,subpopulation,parents,state,thread);
+                sources[1].produce(1,1,1,subpopulation,parents,state,thread);
+                if (!(sources[0] instanceof BreedingPipeline))  // it's a selection method probably
+                    parents[0] = (VectorIndividual)(parents[0].clone());
+                if (!(sources[1] instanceof BreedingPipeline)) // it's a selection method probably
+                    parents[1] = (VectorIndividual)(parents[1].clone());
+                }
+                
+                
+            // determines size of parents, in terms of chunks
+            int chunk_size = ((VectorSpecies)(parents[0].species)).chunksize;  
+            int[] size = new int[2];
+            size[0] = (int)parents[0].genomeLength();
+            size[1] = (int)parents[1].genomeLength();      
+            int[] size_in_chunks = new int[2];
+            size_in_chunks[0] = size[0]/chunk_size;
+            size_in_chunks[1] = size[1]/chunk_size;
+            
+            // variables used to split & join the children
+            int[] min_chunks = new int[2];
+            int[] max_chunks = new int[2];
+            int[][] split = new int[2][2];
+            Object[][] pieces = new Object[2][3];
+            
+            // determine min and max crossover segment lengths, in terms of chunks
+            for(int i = 0; i < 2; i++)
+                {
+                min_chunks[i] = (int)(size_in_chunks[i]*minCrossoverPercentage);
+                // round minCrossoverPercentage up to nearest chunk boundary
+                if(size[i] % chunk_size != 0 && min_chunks[i] < size_in_chunks[i])
+                    {
+                    min_chunks[i]++;
+                    }
+                max_chunks[i] = (int)(size_in_chunks[i]*maxCrossoverPercentage);
+                }
+            
+            // attempt 'num-tries' times to produce valid children (which are bigger than min-child-size)
+            boolean valid_children = false;
+            int attempts = 0;
+            while(valid_children == false && attempts < numTries)
+                {
+                // generate split indices for one-point (tail end used as end of segment)
+                if(crossoverType == VectorSpecies.C_ONE_POINT)
+                    {
+                    for(int i = 0; i < 2; i++)
+                        {
+                        // select first index at most 'max_chunks' away from tail end of vector
+                        split[i][0] = size_in_chunks[i] - max_chunks[i];
+                        // shift back towards tail end with random value based on min/max parameters
+                        split[i][0] += state.random[thread].nextInt(max_chunks[i] - min_chunks[i]);
+                        // convert split from chunk numbers to array indices
+                        split[i][0] *= chunk_size;
+                        // select tail end chunk boundary as second split index
+                        split[i][1] = size_in_chunks[i]*chunk_size;
+                        }
+                    }
+               
+                // generate split indices for two-point (both indicies have randomized positions)
+                else if(crossoverType == VectorSpecies.C_TWO_POINT)
+                    {
+                    for(int i = 0; i < 2; i++)
+                        {
+                        // select first split index randomly
+                        split[i][0] = state.random[thread].nextInt(size_in_chunks[i] - min_chunks[i]);
+                        // second index must be at least 'min_chunks' after the first index
+                        split[i][1] = split[i][0] + min_chunks[i];
+                        // add a random value up to max crossover size, without exceeding size of the parent
+                        split[i][1] += state.random[thread].nextInt(Math.min(max_chunks[i] - min_chunks[i], size_in_chunks[i] - split[i][0]));
+                        // convert split from chunk numbers to array indices
+                        split[i][0] *= chunk_size;
+                        split[i][1] *= chunk_size;
+                        }
+                    }
+               
+                // use the split indices generated above to split the parents into pieces
+                parents[0].split(split[0], pieces[0]);
+                parents[1].split(split[1], pieces[1]);         
+               
+                // create copies of the parents, swap the middle segment, and then rejoin the pieces
+                // - this is done to test whether or not the resulting children are of a valid size,
+                // - because we are using Object references to an undetermined array type, there is no way 
+                //   to cast it to the appropriate array type (i.e. short[] or double[]) to figure out the
+                //   length of the pieces
+                // - instead, we use the join method on copies, and let each vector type figure out its own
+                //   length with the genomeLength() method
+                VectorIndividual[] children = new VectorIndividual[2];
+                children[0] = (VectorIndividual)(parents[0].clone());
+                children[1] = (VectorIndividual)(parents[1].clone());
+               
+                Object swap = pieces[0][1];
+                pieces[0][1] = pieces[1][1];
+                pieces[1][1] = swap;
+                    
+                children[0].join(pieces[0]);
+                children[1].join(pieces[1]);
+                if(children[0].genomeLength() > minChildSize && children[1].genomeLength() > minChildSize)
+                    {
+                    valid_children = true;
+                    }
+                attempts++;
+                }
+           
+            // if the children produced were valid, updates the parents
+            if(valid_children == true)
+                {
+                parents[0].join(pieces[0]);
+                parents[1].join(pieces[1]);
+                parents[0].evaluated=false;
+                parents[1].evaluated=false;
+                }
+            // insert parents back into the population
+            inds[q] = parents[0];
+            q++;
+            if(q < n + start && tossSecondParent == false)
+                {
+                inds[q] = parents[1];
+                q++;
+                }
+            } 
+        
+        return n;
+        }
+    
+    }
+    
+    
+    
+    
+    
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/MultipleVectorCrossoverPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/MultipleVectorCrossoverPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/MultipleVectorCrossoverPipeline.java	(revision 6152)
@@ -0,0 +1,808 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+package ec.vector.breed;
+
+import ec.vector.*;
+import ec.*;
+import ec.util.Parameter;
+
+
+/* 
+ * MultipleVectorCrossoverPipeline.java
+ * 
+ * Created: Thu May 14 2009
+ * By: Beenish Jamil
+ */
+
+
+/**
+ *
+ MultipleVectorCrossoverPipeline is a BreedingPipeline which implements a uniform
+ (any point) crossover between multiple vectors. It is intended to be used with
+ three or more vectors. It takes n parent individuals and returns n crossed over
+ individuals. The number of parents and consequently children is specified by the
+ number of sources parameter. 
+ <p>The standard vector crossover probability is used for this crossover type. 
+ <br> <i> Note</i> : It is necessary to set the crossover-type parameter to 'any' 
+ in order to use this pipeline.
+ 
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ number of parents
+
+ <p><b>Number of Sources</b><br>
+ variable (generally 3 or more)
+
+ 
+ <p><b>Default Base</b><br>
+ vector.multixover
+*/
+
+// This class is MUCH MUCH longer than it need be.  We could just do it by using 
+// ECJ's generic split and join operations, but only rely on that in the default
+// case, and instead use faster per-array operations.
+
+
+public class MultipleVectorCrossoverPipeline extends BreedingPipeline {
+
+    /** default base */
+    public static final String P_CROSSOVER = "multixover";
+    
+    /** Temporary holding place for parents */
+    VectorIndividual[] parents;
+   
+    public Parameter defaultBase() { return VectorDefaults.base().push(P_CROSSOVER); }    
+    
+    /** Returns the number of parents */
+    public int numSources() { return DYNAMIC_SOURCES;}
+    
+    public Object clone()
+        {
+        MultipleVectorCrossoverPipeline c = (MultipleVectorCrossoverPipeline)(super.clone());
+
+        // deep-cloned stuff
+        c.parents = (VectorIndividual[]) parents.clone();
+
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);        
+        parents = new VectorIndividual[sources.length];
+        }
+        
+    /**
+     * Returns the minimum number of children that are produced per crossover 
+     */
+    public int typicalIndsProduced()
+        {
+        return minChildProduction()*sources.length; // minChild is always 1     
+        }
+    
+        
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+
+        
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, true);  // DO produce children from source -- we've not done so already
+
+
+        if(inds[0] instanceof BitVectorIndividual)
+            n = multipleBitVectorCrossover(min, max, start, subpopulation, // redundant reassignment
+                inds, state, thread);
+        
+        else if(inds[0] instanceof ByteVectorIndividual)
+            n = multipleByteVectorCrossover(min, max, start, subpopulation, 
+                inds, state, thread);
+        
+        else if(inds[0] instanceof DoubleVectorIndividual)
+            n = multipleDoubleVectorCrossover(min, max, start, subpopulation, 
+                inds, state, thread);
+        
+        else if(inds[0] instanceof FloatVectorIndividual)
+            n = multipleFloatVectorCrossover(min, max, start, subpopulation, 
+                inds, state, thread);
+
+        else if(inds[0] instanceof IntegerVectorIndividual)
+            n = multipleIntegerVectorCrossover(min, max, start, subpopulation,
+                inds, state, thread);
+        
+        else if(inds[0] instanceof GeneVectorIndividual)
+            n = multipleGeneVectorCrossover(min, max, start, subpopulation, 
+                inds, state, thread);
+
+        else if(inds[0] instanceof LongVectorIndividual)
+            n = multipleLongVectorCrossover(min, max, start, subpopulation, 
+                inds, state, thread);
+
+        else if(inds[0] instanceof ShortVectorIndividual)
+            n = multipleShortVectorCrossover(min, max, start, subpopulation, 
+                inds, state, thread);
+
+        else // default crossover -- shouldn't need this unless a new vector type is added
+            {
+            // check how many sources are provided
+            if(sources.length <= 2)
+                // this method shouldn't be called for just two parents 
+                state.output.error("Only two parents specified!"); 
+
+
+            // fill up parents: 
+            for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+                {               
+                // produce one parent from each source 
+                sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+                if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                    parents[i] = (VectorIndividual)(parents[i].clone());
+                }
+
+
+            //... some required intermediary steps ....
+
+            // assuming all of the species are the same species ... 
+            VectorSpecies species = (VectorSpecies)parents[0].species;
+
+            // an array of the split points (width = 1)
+            int[] points = new int[(int)parents[0].genomeLength() - 1];
+            for(int i = 0; i < points.length; i++){
+                points[i] = i+1;    // first split point/index = 1
+                }
+
+
+            // split all the parents into object arrays 
+            Object[][] pieces = new Object[parents.length][(int)parents[0].genomeLength()]; 
+
+            // splitting...
+            for(int i = 0; i < parents.length; i++){
+                if(parents[i].genomeLength() != parents[0].genomeLength())              
+                    state.output.fatal("All vectors must be of the same length for crossover!");
+                else
+                    parents[i].split(points, pieces[i]);
+                }
+
+
+            // crossing them over now
+            for(int i = 0; i < pieces[0].length; i++)
+                {   
+                if(state.random[thread].nextBoolean(species.crossoverProbability))
+                    {
+                    // shuffle
+                    for(int j = pieces.length-1; j > 0; j--) // no need to shuffle first index at the end
+                        {
+                        // find parent to swap piece with
+                        int parent2 = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self
+                        // swap
+                        Object temp = pieces[j][i];
+                        pieces[j][i] = pieces[parent2][i];
+                        pieces[parent2][i] = temp;
+                        }
+                    }
+                }
+
+            // join them and add them to the population starting at the start location
+            for(int i = 0, q = start; i < parents.length; i++, q++)
+                { 
+                parents[i].join(pieces[i]);                         
+                parents[i].evaluated = false;
+                if(q<inds.length) // just in case
+                    {               
+                    inds[q] = (VectorIndividual)parents[i];
+                    }
+                }
+            }
+        return n;
+        }
+    
+    
+    /** Crosses over the Bit Vector Individuals using a 
+        uniform crossover method.      
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default. 
+        */
+    public int multipleBitVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        if(!(inds[0] instanceof BitVectorIndividual))
+            state.output.fatal("Trying to produce bit vector individuals when you can't!");
+        
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (BitVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    boolean temp = ((BitVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((BitVectorIndividual)parents[j]).genome[i] = 
+                        ((BitVectorIndividual)parents[swapIndex]).genome[i];
+                    ((BitVectorIndividual)parents[swapIndex]).genome[i] = temp;                 
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (BitVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+    
+   
+    /** Crosses over the Byte Vector Individuals using a 
+        uniform crossover method.      
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default. 
+        */
+    public int multipleByteVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        if(!(inds[0] instanceof ByteVectorIndividual))
+            state.output.fatal("Trying to produce byte vector individuals when you can't!");
+        
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (ByteVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    byte temp = ((ByteVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((ByteVectorIndividual)parents[j]).genome[i] = ((ByteVectorIndividual)parents[swapIndex]).genome[i];
+                    ((ByteVectorIndividual)parents[swapIndex]).genome[i] = temp;                        
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (ByteVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+    
+    
+    /** Crosses over the Double Vector Individuals using a 
+        uniform crossover method.    
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default.   
+        */
+    public int multipleDoubleVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        
+        if(!(inds[0] instanceof DoubleVectorIndividual))
+            state.output.fatal("Trying to produce double vector individuals when you can't!");
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (DoubleVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+        
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    double temp = ((DoubleVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((DoubleVectorIndividual)parents[j]).genome[i] = ((DoubleVectorIndividual)parents[swapIndex]).genome[i];
+                    ((DoubleVectorIndividual)parents[swapIndex]).genome[i] = temp;                      
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (DoubleVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+
+    
+    /** Crosses over the Float Vector Individuals using a 
+        uniform crossover method.      
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default. 
+        */
+    public int multipleFloatVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        if(!(inds[0] instanceof FloatVectorIndividual))
+            state.output.fatal("Trying to produce float vector individuals when you can't!");
+        
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (FloatVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    float temp = ((FloatVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((FloatVectorIndividual)parents[j]).genome[i] = ((FloatVectorIndividual)parents[swapIndex]).genome[i];
+                    ((FloatVectorIndividual)parents[swapIndex]).genome[i] = temp;                       
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (FloatVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+    
+       
+    /** Crosses over the Gene Vector Individuals using a 
+        uniform crossover method.      
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default. 
+        */
+    public int multipleGeneVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        if(!(inds[0] instanceof GeneVectorIndividual))
+            state.output.fatal("Trying to produce gene vector individuals when you can't!");
+        
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (GeneVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    VectorGene temp = ((GeneVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((GeneVectorIndividual)parents[j]).genome[i] = ((GeneVectorIndividual)parents[swapIndex]).genome[i];
+                    ((GeneVectorIndividual)parents[swapIndex]).genome[i] = temp;                        
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (GeneVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+
+       
+    /**Crosses over the Integer Vector Individuals using a uniform crossover method.   
+     * 
+     * There is no need to call this method separately; produce(...) calls it
+     * whenever necessary by default.    
+     */
+    public int multipleIntegerVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        
+        if(!(inds[0] instanceof IntegerVectorIndividual))
+            state.output.fatal("Trying to produce integer vector individuals when you can't!");
+        
+
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+            
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source      
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (IntegerVectorIndividual)(parents[i].clone());
+
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    int temp = ((IntegerVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((IntegerVectorIndividual)parents[j]).genome[i] = ((IntegerVectorIndividual)parents[swapIndex]).genome[i];
+                    ((IntegerVectorIndividual)parents[swapIndex]).genome[i] = temp;                     
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (IntegerVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+ 
+       
+    /** Crosses over the Long Vector Individuals using a 
+        uniform crossover method.      
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default. 
+        */
+    public int multipleLongVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        if(!(inds[0] instanceof LongVectorIndividual))
+            state.output.fatal("Trying to produce long vector individuals when you can't!");
+        
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (LongVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    long temp = ((LongVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((LongVectorIndividual)parents[j]).genome[i] = ((LongVectorIndividual)parents[swapIndex]).genome[i];
+                    ((LongVectorIndividual)parents[swapIndex]).genome[i] = temp;                        
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (LongVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+    
+      
+    /** Crosses over the Short Vector Individuals using a 
+        uniform crossover method.      
+        * 
+        * There is no need to call this method separately; produce(...) calls it
+        * whenever necessary by default. 
+        */
+    public int multipleShortVectorCrossover(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread)
+        {
+        if(!(inds[0] instanceof ShortVectorIndividual))
+            state.output.fatal("Trying to produce short vector individuals when you can't!");
+        
+        
+        // check how many sources are provided
+        if(sources.length <= 2)
+            // this method shouldn't be called for just two parents 
+            state.output.error("Only two parents specified!"); 
+
+        
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+            
+        
+        
+        // fill up parents: 
+        for(int i = 0;i<parents.length; i++) // parents.length == sources.length
+            {                   
+            // produce one parent from each source 
+            sources[i].produce(1,1,i,subpopulation,parents,state,thread);
+            if (!(sources[i] instanceof BreedingPipeline))  // it's a selection method probably
+                parents[i] = (ShortVectorIndividual)(parents[i].clone());
+            }
+        
+        
+        VectorSpecies species = (VectorSpecies)inds[0].species; // doesn't really matter if 
+        //this is dblvector or vector as long as we
+        // can get the crossover probability
+
+        
+        // crossover
+        for(int i = 0; i < parents[0].genomeLength(); i++)
+            {
+            if(state.random[thread].nextBoolean(species.crossoverProbability))
+                {               
+                for(int j = parents.length-1; j > 0; j--)
+                    {                       
+                    int swapIndex = state.random[thread].nextInt(j); // not inclusive; don't want to swap with self                     
+                    short temp = ((ShortVectorIndividual) parents[j]).genome[i]; // modifying genomes directly. it's okay since they're clones
+                    ((ShortVectorIndividual)parents[j]).genome[i] = ((ShortVectorIndividual)parents[swapIndex]).genome[i];
+                    ((ShortVectorIndividual)parents[swapIndex]).genome[i] = temp;                       
+                    }                       
+                }
+            }
+        
+        // add to population
+        for(int i = 0, q = start; i < parents.length; i++, q++)
+            {         
+            parents[i].evaluated = false;
+            if(q<inds.length) // just in case
+                {           
+                inds[q] = (ShortVectorIndividual)parents[i];
+                }
+            }       
+        return n;       
+        }
+    }
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/README
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/README	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/README	(revision 6152)
@@ -0,0 +1,1 @@
+See the README file in the parent package for information on this one.
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/VectorCrossoverPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/VectorCrossoverPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/VectorCrossoverPipeline.java	(revision 6152)
@@ -0,0 +1,163 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector.breed;
+
+import ec.vector.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * VectorCrossoverPipeline.java
+ * 
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ * By: Sean Luke
+ */
+
+
+/**
+ *
+ VectorCrossoverPipeline is a BreedingPipeline which implements a simple default crossover
+ for VectorIndividuals.  Normally it takes two individuals and returns two crossed-over 
+ child individuals.  Optionally, it can take two individuals, cross them over, but throw
+ away the second child (a one-child crossover).  VectorCrossoverPipeline works by calling
+ defaultCrossover(...) on the first parent individual.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ 2 * minimum typical number of individuals produced by each source, unless tossSecondParent
+ is set, in which case it's simply the minimum typical number.
+
+ <p><b>Number of Sources</b><br>
+ 2
+
+ <p><b>Parameters</b><br>
+ <table>
+ <tr><td valign=top><i>base</i>.<tt>toss</tt><br>
+ <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</font>/td>
+ <td valign=top>(after crossing over with the first new individual, should its second sibling individual be thrown away instead of adding it to the population?)</td></tr>
+ </table>
+
+ <p><b>Default Base</b><br>
+ vector.xover
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class VectorCrossoverPipeline extends BreedingPipeline
+    {
+    public static final String P_TOSS = "toss";
+    public static final String P_CROSSOVER = "xover";
+    public static final int NUM_SOURCES = 2;
+
+    /** Should the pipeline discard the second parent after crossing over? */
+    public boolean tossSecondParent;
+
+    /** Temporary holding place for parents */
+    VectorIndividual parents[];
+
+    public VectorCrossoverPipeline() { parents = new VectorIndividual[2]; }
+    public Parameter defaultBase() { return VectorDefaults.base().push(P_CROSSOVER); }
+
+    /** Returns 2 */
+    public int numSources() { return NUM_SOURCES; }
+
+    public Object clone()
+        {
+        VectorCrossoverPipeline c = (VectorCrossoverPipeline)(super.clone());
+
+        // deep-cloned stuff
+        c.parents = (VectorIndividual[]) parents.clone();
+
+        return c;
+        }
+
+    public void setup(final EvolutionState state, final Parameter base)
+        {
+        super.setup(state,base);
+        Parameter def = defaultBase();
+        tossSecondParent = state.parameters.getBoolean(base.push(P_TOSS),
+            def.push(P_TOSS),false);
+        }
+        
+    /** Returns 2 * minimum number of typical individuals produced by any sources, else
+        1* minimum number if tossSecondParent is true. */
+    public int typicalIndsProduced()
+        {
+        return (tossSecondParent? minChildProduction(): minChildProduction()*2);
+        }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+
+        {
+        // how many individuals should we make?
+        int n = typicalIndsProduced();
+        if (n < min) n = min;
+        if (n > max) n = max;
+                
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, true);  // DO produce children from source -- we've not done so already
+
+        for(int q=start;q<n+start; /* no increment */)  // keep on going until we're filled up
+            {
+            // grab two individuals from our sources
+            if (sources[0]==sources[1])  // grab from the same source
+                {
+                sources[0].produce(2,2,0,subpopulation,parents,state,thread);
+                if (!(sources[0] instanceof BreedingPipeline))  // it's a selection method probably
+                    { 
+                    parents[0] = (VectorIndividual)(parents[0].clone());
+                    parents[1] = (VectorIndividual)(parents[1].clone());
+                    }
+                }
+            else // grab from different sources
+                {
+                sources[0].produce(1,1,0,subpopulation,parents,state,thread);
+                sources[1].produce(1,1,1,subpopulation,parents,state,thread);
+                if (!(sources[0] instanceof BreedingPipeline))  // it's a selection method probably
+                    parents[0] = (VectorIndividual)(parents[0].clone());
+                if (!(sources[1] instanceof BreedingPipeline)) // it's a selection method probably
+                    parents[1] = (VectorIndividual)(parents[1].clone());
+                }
+                
+            // at this point, parents[] contains our two selected individuals,
+            // AND they're copied so we own them and can make whatever modifications
+            // we like on them.
+    
+            // so we'll cross them over now.  Since this is the default pipeline,
+            // we'll just do it by calling defaultCrossover on the first child
+            
+            parents[0].defaultCrossover(state,thread,parents[1]);
+            parents[0].evaluated=false;
+            parents[1].evaluated=false;
+            
+            // add 'em to the population
+            inds[q] = parents[0];
+            q++;
+            if (q<n+start && !tossSecondParent)
+                {
+                inds[q] = parents[1];
+                q++;
+                }
+            }
+        return n;
+        }
+    }
+    
+    
+    
+    
+    
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/VectorMutationPipeline.java
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/VectorMutationPipeline.java	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/ec/vector/breed/VectorMutationPipeline.java	(revision 6152)
@@ -0,0 +1,85 @@
+/*
+  Copyright 2006 by Sean Luke
+  Licensed under the Academic Free License version 3.0
+  See the file "LICENSE" for more information
+*/
+
+
+package ec.vector.breed;
+
+import ec.vector.*;
+import ec.*;
+import ec.util.*;
+
+/* 
+ * VectorMutationPipeline.java
+ * 
+ * Created: Tue Mar 13 15:03:12 EST 2001
+ * By: Sean Luke
+ */
+
+
+/**
+ *
+ VectorMutationPipeline is a BreedingPipeline which implements a simple default Mutation
+ for VectorIndividuals.  Normally it takes an individual and returns a mutated 
+ child individual. VectorMutationPipeline works by calling defaultMutate(...) on the 
+ parent individual.
+ 
+ <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
+ (however many its source produces)
+
+ <p><b>Number of Sources</b><br>
+ 1
+
+ <p><b>Default Base</b><br>
+ vector.mutate (not that it matters)
+
+ * @author Sean Luke
+ * @version 1.0
+ */
+
+public class VectorMutationPipeline extends BreedingPipeline
+    {
+    public static final String P_MUTATION = "mutate";
+    public static final int NUM_SOURCES = 1;
+
+    public Parameter defaultBase() { return VectorDefaults.base().push(P_MUTATION); }
+    
+    /** Returns 1 */
+    public int numSources() { return NUM_SOURCES; }
+
+    public int produce(final int min, 
+        final int max, 
+        final int start,
+        final int subpopulation,
+        final Individual[] inds,
+        final EvolutionState state,
+        final int thread) 
+        {
+        // grab individuals from our source and stick 'em right into inds.
+        // we'll modify them from there
+        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
+
+        // should we bother?
+        if (!state.random[thread].nextBoolean(likelihood))
+            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
+
+        // clone the individuals if necessary
+        if (!(sources[0] instanceof BreedingPipeline))
+            for(int q=start;q<n+start;q++)
+                inds[q] = (Individual)(inds[q].clone());
+
+        // mutate 'em
+        for(int q=start;q<n+start;q++)
+            {
+            ((VectorIndividual)inds[q]).defaultMutate(state,thread);
+            ((VectorIndividual)inds[q]).evaluated=false;
+            }
+
+        return n;
+        }
+
+    }
+    
+    
Index: branches/OKBJavaConnector/ECJClient/src/tutorial1.params
===================================================================
--- branches/OKBJavaConnector/ECJClient/src/tutorial1.params	(revision 6152)
+++ branches/OKBJavaConnector/ECJClient/src/tutorial1.params	(revision 6152)
@@ -0,0 +1,53 @@
+# Copyright 2006 by Sean Luke and George Mason University
+# Licensed under the Academic Free License version 3.0
+# See the file "LICENSE" for more information
+
+# The parameters that were laid out in Tutorial 1 (see the documentation)
+
+verbosity	= 0
+
+breedthreads	= 1
+evalthreads	= 1
+seed.0		= 4357
+
+state		= ec.simple.SimpleEvolutionState
+
+pop		= ec.Population
+init		= ec.simple.SimpleInitializer
+finish		= ec.simple.SimpleFinisher
+breed		= ec.simple.SimpleBreeder
+eval		= ec.simple.SimpleEvaluator
+stat		= com.heuristiclab.okb.ecj.OKBStatistics
+exch		= ec.simple.SimpleExchanger
+
+generations		= 200
+quit-on-run-complete	= true
+checkpoint		= false
+prefix			= ec
+checkpoint-modulo	= 1
+
+stat.file		= $out.stat
+
+pop.subpops		= 1
+pop.subpop.0		= ec.Subpopulation
+
+pop.subpop.0.size 		= 10
+pop.subpop.0.duplicate-retries 	= 0
+pop.subpop.0.species 		= ec.vector.VectorSpecies
+
+pop.subpop.0.species.fitness 	= ec.simple.SimpleFitness
+pop.subpop.0.species.ind	= ec.vector.BitVectorIndividual
+
+pop.subpop.0.species.genome-size	= 20
+pop.subpop.0.species.crossover-type	= one
+pop.subpop.0.species.crossover-prob	= 1.0
+pop.subpop.0.species.mutation-prob	= 0.01
+
+pop.subpop.0.species.pipe			= ec.vector.breed.VectorMutationPipeline
+pop.subpop.0.species.pipe.source.0		= ec.vector.breed.VectorCrossoverPipeline
+pop.subpop.0.species.pipe.source.0.source.0	= ec.select.TournamentSelection
+pop.subpop.0.species.pipe.source.0.source.1	= ec.select.TournamentSelection
+
+select.tournament.size		= 2
+print-all-params = true
+eval.problem		= ec.app.tutorial1.MaxOnes
