Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/vector/FloatVectorIndividual.java @ 10501

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

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

File size: 23.7 KB
Line 
1package ec.vector;
2
3import ec.*;
4import ec.util.*;
5
6import java.io.*;
7
8/*
9 * FloatVectorIndividual.java
10 * Created: Thu Mar 22 13:13:20 EST 2001
11 */
12
13/**
14 * FloatVectorIndividual is a VectorIndividual whose genome is an array of
15 * floats. Gene values may range from species.mingene(x) to species.maxgene(x),
16 * inclusive. The default mutation method randomizes genes to new values in this
17 * range, with <tt>species.mutationProbability</tt>. It can also add gaussian noise
18 * to the genes, if so directed in the FloatVectorSpecies. If the gaussian noise
19 * pushes the gene out of range, a new noise value is generated.
20 *
21 *
22 * <p>
23 * <P><b>From ec.Individual:</b> 
24 *
25 * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
26 *
27 * <ul>
28 * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
29 * transmits or receives an individual in binary.  It is the most efficient approach to sending
30 * individuals over networks, etc.  These methods write the evaluated flag and the fitness, then
31 * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your
32 * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
33 * You don't need to implement them if you don't plan on using read/writeIndividual.
34 *
35 * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
36 * approach transmits or receives an indivdual in text encoded such that the individual is largely readable
37 * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will encode numbers
38 * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
39 * files for inspection, slight modification, then reading back in later on.  <b>readIndividual</b> reads
40 * in the fitness and the evaluation flag, then calls <b>parseGenotype</b> to read in the remaining individual.
41 * You are responsible for implementing parseGenotype: the Code class is there to help you.
42 * <b>printIndividual</b> writes out the fitness and evaluation flag, then calls <b>genotypeToString</b>
43 * and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
44 * a way that parseGenotype can read back in the individual println'd with genotypeToString.  The default form
45 * of genotypeToString simply calls <b>toString</b>, which you may override instead if you like.  The default
46 * form of <b>parseGenotype</b> throws an error.  You are not required to implement these methods, but without
47 * them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
48 *
49 * <li><b>printIndividualForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
50 * approach prints an individual in a fashion intended for human consumption only.
51 * <b>printIndividualForHumans</b> writes out the fitness and evaluation flag, then calls <b>genotypeToStringForHumans</b>
52 * and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
53 * The default form of genotypeToStringForHumans simply calls <b>toString</b>, which you may override instead if you like
54 * (though note that genotypeToString's default also calls toString).  You should handle one of these methods properly
55 * to ensure individuals can be printed by ECJ.
56 * </ul>
57
58 * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
59 * they read/write the evaluated flag, and they read/write the gene array.  If you add instance variables to
60 * a VectorIndividual or subclass, you'll need to read/write those variables as well.
61 * <b>Default Base</b><br>
62 * vector.float-vect-ind
63 *
64 * @author Liviu Panait
65 * @version 2.0
66 */
67
68public class FloatVectorIndividual extends VectorIndividual
69    {
70    public static final String P_FLOATVECTORINDIVIDUAL = "float-vect-ind";
71
72    public float[] genome;
73
74    public Parameter defaultBase()
75        {
76        return VectorDefaults.base().push(P_FLOATVECTORINDIVIDUAL);
77        }
78
79    public Object clone()
80        {
81        FloatVectorIndividual myobj = (FloatVectorIndividual) (super.clone());
82
83        // must clone the genome
84        myobj.genome = (float[]) (genome.clone());
85
86        return myobj;
87        }
88
89    public void setup(final EvolutionState state, final Parameter base)
90        {
91        super.setup(state, base); // actually unnecessary (Individual.setup()
92        // is empty)
93
94        // since VectorSpecies set its constraint values BEFORE it called
95        // super.setup(...) [which in turn called our setup(...)], we know that
96        // stuff like genomeSize has already been set...
97
98        Parameter def = defaultBase();
99
100        if (!(species instanceof FloatVectorSpecies))
101            state.output.fatal(
102                "FloatVectorIndividual requires an FloatVectorSpecies",
103                base, def);
104        FloatVectorSpecies s = (FloatVectorSpecies) species;
105
106        genome = new float[s.genomeSize];
107        }
108
109    public void defaultCrossover(EvolutionState state, int thread,
110        VectorIndividual ind)
111        {
112        FloatVectorSpecies s = (FloatVectorSpecies) species;
113        FloatVectorIndividual i = (FloatVectorIndividual) ind;
114        float tmp;
115        int point;
116
117        if (genome.length != i.genome.length)
118            state.output
119                .fatal("Genome lengths are not the same for fixed-length vector crossover");
120        switch (s.crossoverType)
121            {
122            case VectorSpecies.C_ONE_POINT:
123                point = state.random[thread]
124                    .nextInt((genome.length / s.chunksize) + 1);
125                for (int x = 0; x < point * s.chunksize; x++)
126                    {
127                    tmp = i.genome[x];
128                    i.genome[x] = genome[x];
129                    genome[x] = tmp;
130                    }
131                break;
132            case VectorSpecies.C_TWO_POINT:
133                int point0 = state.random[thread]
134                    .nextInt((genome.length / s.chunksize) + 1);
135                point = state.random[thread]
136                    .nextInt((genome.length / s.chunksize) + 1);
137                if (point0 > point)
138                    {
139                    int p = point0;
140                    point0 = point;
141                    point = p;
142                    }
143                for (int x = point0 * s.chunksize; x < point * s.chunksize; x++)
144                    {
145                    tmp = i.genome[x];
146                    i.genome[x] = genome[x];
147                    genome[x] = tmp;
148                    }
149                break;
150            case VectorSpecies.C_ANY_POINT:
151                for (int x = 0; x < genome.length / s.chunksize; x++)
152                    if (state.random[thread].nextBoolean(s.crossoverProbability))
153                        for (int y = x * s.chunksize; y < (x + 1) * s.chunksize; y++)
154                            {
155                            tmp = i.genome[y];
156                            i.genome[y] = genome[y];
157                            genome[y] = tmp;
158                            }
159                break;
160            case VectorSpecies.C_LINE_RECOMB:
161            {
162            double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
163            double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
164            double t,u,min,max;
165            for (int x = 0; x < genome.length; x++)
166                {
167                min = s.minGene(x);
168                max = s.maxGene(x);
169                t = alpha * genome[x] + (1 - alpha) * i.genome[x];
170                u = beta * i.genome[x] + (1 - beta) * genome[x];
171                if (!(t < min || t > max || u < min || u > max))
172                    {
173                    genome[x] = (float)t;
174                    i.genome[x] = (float)u;
175                    }
176                }
177            }
178            break;
179            case VectorSpecies.C_INTERMED_RECOMB:
180            {
181            double t,u,min,max;
182            for (int x = 0; x < genome.length; x++)
183                {
184                do
185                    {
186                    double alpha = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
187                    double beta = state.random[thread].nextDouble() * (1 + 2*s.lineDistance) - s.lineDistance;
188                    min = s.minGene(x);
189                    max = s.maxGene(x);
190                    t = alpha * genome[x] + (1 - alpha) * i.genome[x];
191                    u = beta * i.genome[x] + (1 - beta) * genome[x];
192                    } while (t < min || t > max || u < min || u > max);
193                genome[x] = (float)t;
194                i.genome[x] = (float)u;
195                }
196            }
197            break;
198            case VectorSpecies.C_SIMULATED_BINARY:
199            {
200            simulatedBinaryCrossover(state.random[thread], i, s.crossoverDistributionIndex);
201            }
202            break;
203            }
204        }
205
206
207    public void simulatedBinaryCrossover(MersenneTwisterFast random, FloatVectorIndividual other, double eta_c)
208        {
209        final double EPS = FloatVectorSpecies.SIMULATED_BINARY_CROSSOVER_EPS;
210        FloatVectorSpecies s = (FloatVectorSpecies) species;
211        float[] parent1 = genome;
212        float[] parent2 = other.genome;
213        double[] min_realvar = s.minGenes;
214        double[] max_realvar = s.maxGenes;
215               
216        double y1, y2, yl, yu;
217        double c1, c2;
218        double alpha, beta, betaq;
219        double rand;
220               
221        for(int i = 0; i < parent1.length; i++)
222            {
223            if (random.nextBoolean())  // 0.5f
224                {
225                if (Math.abs(parent1[i] - parent2[i]) > EPS)
226                    {
227                    if (parent1[i] < parent2[i])
228                        {
229                        y1 = parent1[i];
230                        y2 = parent2[i];
231                        }
232                    else
233                        {
234                        y1 = parent2[i];
235                        y2 = parent1[i];
236                        }
237                    yl = min_realvar[i];
238                    yu = max_realvar[i];   
239                    rand = random.nextDouble();
240                    beta = 1.0 + (2.0*(y1-yl)/(y2-y1));
241                    alpha = 2.0 - Math.pow(beta,-(eta_c+1.0));
242                    if (rand <= (1.0/alpha))
243                        {
244                        betaq = Math.pow((rand*alpha),(1.0/(eta_c+1.0)));
245                        }
246                    else
247                        {
248                        betaq = Math.pow((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0)));
249                        }
250                    c1 = 0.5*((y1+y2)-betaq*(y2-y1));
251                    beta = 1.0 + (2.0*(yu-y2)/(y2-y1));
252                    alpha = 2.0 - Math.pow(beta,-(eta_c+1.0));
253                    if (rand <= (1.0/alpha))
254                        {
255                        betaq = Math.pow((rand*alpha),(1.0/(eta_c+1.0)));
256                        }
257                    else
258                        {
259                        betaq = Math.pow((1.0/(2.0 - rand*alpha)),(1.0/(eta_c+1.0)));
260                        }
261                    c2 = 0.5*((y1+y2)+betaq*(y2-y1));
262                    if (c1<yl)
263                        c1=yl;
264                    if (c2<yl)
265                        c2=yl;
266                    if (c1>yu)
267                        c1=yu;
268                    if (c2>yu)
269                        c2=yu;
270                    if (random.nextBoolean())
271                        {
272                        parent1[i] = (float)c2;
273                        parent2[i] = (float)c1;
274                        }
275                    else
276                        {
277                        parent1[i] = (float)c1;
278                        parent2[i] = (float)c2;
279                        }
280                    }
281                else
282                    {
283                    // do nothing
284                    }
285                }
286            else
287                {
288                // do nothing
289                }
290            }
291        }
292
293
294
295
296
297
298
299
300    /**
301     * Splits the genome into n pieces, according to points, which *must* be
302     * sorted. pieces.length must be 1 + points.length
303     */
304    public void split(int[] points, Object[] pieces)
305        {
306        int point0, point1;
307        point0 = 0;
308        point1 = points[0];
309        for (int x = 0; x < pieces.length; x++)
310            {
311            pieces[x] = new float[point1 - point0];
312            System.arraycopy(genome, point0, pieces[x], 0, point1 - point0);
313            point0 = point1;
314            if (x >= pieces.length - 2)
315                point1 = genome.length;
316            else
317                point1 = points[x + 1];
318            }
319        }
320
321    /** Joins the n pieces and sets the genome to their concatenation. */
322    public void join(Object[] pieces)
323        {
324        int sum = 0;
325        for (int x = 0; x < pieces.length; x++)
326            sum += ((float[]) (pieces[x])).length;
327
328        int runningsum = 0;
329        float[] newgenome = new float[sum];
330        for (int x = 0; x < pieces.length; x++)
331            {
332            System.arraycopy(pieces[x], 0, newgenome, runningsum,
333                ((float[]) (pieces[x])).length);
334            runningsum += ((float[]) (pieces[x])).length;
335            }
336        // set genome
337        genome = newgenome;
338        }
339
340    /**
341     * Destructively mutates the individual in some default manner. The default
342     * form simply randomizes genes to a uniform distribution from the min and
343     * max of the gene values. It can also add gaussian noise to the genes,
344     * if so directed in the FloatVectorSpecies. If the gaussian noise
345     * pushes the gene out of range, a new noise value is generated.
346     *
347     *  * @author Liviu Panait and Gabriel Balan
348     */
349    public void defaultMutate(EvolutionState state, int thread)
350        {
351        FloatVectorSpecies s = (FloatVectorSpecies) species;
352        if (!(s.mutationProbability > 0.0))
353            return;
354        boolean mutationIsBounded = s.mutationIsBounded;
355        MersenneTwisterFast rng = state.random[thread];
356
357        if (s.mutationType == FloatVectorSpecies.C_GAUSS_MUTATION)
358            {
359            for (int x = 0; x < genome.length; x++)
360                if (rng.nextBoolean(s.mutationProbability))
361                    {
362                    float val;
363                    float min = (float) s.minGene(x);
364                    float max = (float) s.maxGene(x);
365                    float stdev = (float)s.gaussMutationStdev;
366                    int outOfBoundsLeftOverTries = s.outOfBoundsRetries;
367                    boolean givingUpAllowed =  s.outOfBoundsRetries!=0;
368                    do
369                        {
370                        val = (float) (rng.nextGaussian() * stdev + genome[x]);
371                        outOfBoundsLeftOverTries--;
372                        if (mutationIsBounded && (val > max || val < min))
373                            {
374                            if(givingUpAllowed && (outOfBoundsLeftOverTries==0))
375                                {
376                                val = (float) (min + rng.nextFloat() * (max - min));
377                                s.outOfRangeRetryLimitReached(state);//it better get inlined
378                                break;
379                                }
380                            }
381                        else break;
382                        } while (true);
383                    genome[x] = val;
384                    }
385            }
386        else if (s.mutationType == FloatVectorSpecies.C_POLYNOMIAL_MUTATION)
387            {
388            polynomialMutate(state.random[thread], this, s.mutationDistributionIndex, s.polynomialIsAlternative, s.mutationIsBounded);
389            }
390        else
391            {// C_RESET_MUTATION
392            for (int x = 0; x < genome.length; x++)
393                if (rng.nextBoolean(s.mutationProbability))
394                    genome[x] = (float) ((float) s.minGene(x) + rng.nextFloat() * ((float) s.maxGene(x) - (float) s.minGene(x)));
395            }
396                       
397        }
398
399    /** This function is broken out to keep it identical to NSGA-II's mutation.c code. eta_m is the distribution
400        index.  */
401    public void polynomialMutate(MersenneTwisterFast random, FloatVectorIndividual individual, double eta_m, boolean alternativePolynomialVersion, boolean mutationIsBounded)
402        {
403        FloatVectorSpecies s = (FloatVectorSpecies) individual.species;
404        float[] ind = individual.genome;
405        double[] min_realvar = s.minGenes;
406        double[] max_realvar = s.maxGenes;
407               
408        double rnd, delta1, delta2, mut_pow, deltaq;
409        double y, yl, yu, val, xy;
410        double y1;
411        for (int j=0; j < ind.length; j++)
412            {
413            if (random.nextBoolean(s.mutationProbability))
414                {
415                y1 = y = ind[j];
416                yl = min_realvar[j];
417                yu = max_realvar[j];
418                delta1 = (y-yl)/(yu-yl);
419                delta2 = (yu-y)/(yu-yl);
420
421                int totalTries = s.outOfBoundsRetries;
422                int tries = 0;
423                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.
424                    {
425                    rnd = (random.nextDouble());
426                    mut_pow = 1.0/(eta_m+1.0);
427                    if (rnd <= 0.5)
428                        {
429                        xy = 1.0-delta1;
430                        val = 2.0*rnd + (alternativePolynomialVersion ? (1.0-2.0*rnd)*(Math.pow(xy,(eta_m+1.0))) : 0.0);
431                        deltaq =  Math.pow(val,mut_pow) - 1.0;
432                        }
433                    else
434                        {
435                        xy = 1.0-delta2;
436                        val = 2.0*(1.0-rnd) + (alternativePolynomialVersion ? 2.0*(rnd-0.5)*(Math.pow(xy,(eta_m+1.0))) : 0.0);
437                        deltaq = 1.0 - (Math.pow(val,mut_pow));
438                        }
439                    y1 = y + deltaq*(yu-yl);
440                    if (mutationIsBounded && (y1 >= yl && y1 <= yu)) break;  // yay, found one
441                    }
442                                       
443                // at this point, if tries is totalTries, we failed
444                if (totalTries != 0 && tries == totalTries)
445                    {
446                    // just randomize
447                    y1 = (float)(min_realvar[j] + random.nextFloat() * (max_realvar[j] - min_realvar[j]));
448                    }
449                ind[j] = (float) y1;
450                }
451            }
452                       
453        }
454
455
456    /**
457     * Initializes the individual by randomly choosing floats uniformly from
458     * mingene to maxgene.
459     */
460    public void reset(EvolutionState state, int thread)
461        {
462        FloatVectorSpecies s = (FloatVectorSpecies) species;
463        for (int x = 0; x < genome.length; x++)
464            genome[x] = (float) ((float) s.minGene(x) + state.random[thread]
465                .nextFloat()
466                * ((float) s.maxGene(x) - (float) s.minGene(x)));
467        }
468
469    public int hashCode()
470        {
471        // stolen from GPIndividual. It's a decent algorithm.
472        int hash = this.getClass().hashCode();
473
474        hash = (hash << 1 | hash >>> 31);
475        for (int x = 0; x < genome.length; x++)
476            hash = (hash << 1 | hash >>> 31) ^ Float.floatToIntBits(genome[x]);
477
478        return hash;
479        }
480
481    public String genotypeToStringForHumans()
482        {
483        String s = "";
484        for (int i = 0; i < genome.length; i++)
485            s = s + " " + genome[i];
486        return s;
487        }
488
489    public String genotypeToString()
490        {
491        StringBuffer s = new StringBuffer();
492        s.append(Code.encode(genome.length));
493        for (int i = 0; i < genome.length; i++)
494            s.append(Code.encode(genome[i]));
495        return s.toString();
496        }
497
498    protected void parseGenotype(final EvolutionState state,
499        final LineNumberReader reader) throws IOException
500        {
501        // read in the next line. The first item is the number of genes
502        String s = reader.readLine();
503        DecodeReturn d = new DecodeReturn(s);
504        Code.decode(d);
505        int lll = (int) (d.l);
506
507        genome = new float[lll];
508
509        // read in the genes
510        for (int i = 0; i < genome.length; i++)
511            {
512            Code.decode(d);
513            genome[i] = (float) (d.d);
514            }
515        }
516
517    public boolean equals(Object ind)
518        {
519        if (!(this.getClass().equals(ind.getClass())))
520            return false; // SimpleRuleIndividuals are special.
521        FloatVectorIndividual i = (FloatVectorIndividual) ind;
522        if (genome.length != i.genome.length)
523            return false;
524        for (int j = 0; j < genome.length; j++)
525            if (genome[j] != i.genome[j])
526                return false;
527        return true;
528        }
529
530    public Object getGenome()
531        {
532        return genome;
533        }
534
535    public void setGenome(Object gen)
536        {
537        genome = (float[]) gen;
538        }
539
540    public int genomeLength()
541        {
542        return genome.length;
543        }
544
545    public void writeGenotype(final EvolutionState state,
546        final DataOutput dataOutput) throws IOException
547        {
548        dataOutput.writeInt(genome.length);
549        for (int x = 0; x < genome.length; x++)
550            dataOutput.writeFloat(genome[x]);
551        }
552
553    public void readGenotype(final EvolutionState state,
554        final DataInput dataInput) throws IOException
555        {
556        int len = dataInput.readInt();
557        if (genome == null || genome.length != len)
558            genome = new float[len];
559        for (int x = 0; x < genome.length; x++)
560            genome[x] = dataInput.readFloat();
561        }
562
563    /** Clips each gene value to be within its specified [min,max] range. 
564        NaN is presently considered in range but the behavior of this method
565        should be assumed to be unspecified on encountering NaN. */
566    public void clamp()
567        {
568        FloatVectorSpecies _species = (FloatVectorSpecies)species;
569        for (int i = 0; i < genomeLength(); i++)
570            {
571            float minGene = (float)_species.minGene(i);
572            if (genome[i] < minGene)
573                genome[i] = minGene;
574            else
575                {
576                float maxGene = (float)_species.maxGene(i);
577                if (genome[i] > maxGene)
578                    genome[i] = maxGene;
579                }
580            }
581        }
582               
583    public void setGenomeLength(int len)
584        {
585        float[] newGenome = new float[len];
586        System.arraycopy(genome, 0, newGenome, 0,
587            genome.length < newGenome.length ? genome.length : newGenome.length);
588        genome = newGenome;
589        }
590
591    /** Returns true if each gene value is within is specified [min,max] range.
592        NaN is presently considered in range but the behavior of this method
593        should be assumed to be unspecified on encountering NaN. */
594    public boolean isInRange()
595        {
596        FloatVectorSpecies _species = (FloatVectorSpecies)species;
597        for (int i = 0; i < genomeLength(); i++)
598            if (genome[i] < _species.minGene(i) ||
599                genome[i] > _species.maxGene(i)) return false;
600        return true;
601        }
602
603    public double distanceTo(Individual otherInd)
604        {
605        if (!(otherInd instanceof FloatVectorIndividual))
606            return super.distanceTo(otherInd);  // will return infinity!
607               
608        FloatVectorIndividual other = (FloatVectorIndividual) otherInd;
609        float[] otherGenome = other.genome;
610        double sumSquaredDistance =0.0;
611        for(int i=0; i < other.genomeLength(); i++)
612            {
613            double dist = this.genome[i] - otherGenome[i];
614            sumSquaredDistance += dist*dist;
615            }
616        return StrictMath.sqrt(sumSquaredDistance);
617        }
618    }
Note: See TracBrowser for help on using the repository browser.