Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/vector/DoubleVectorIndividual.java @ 13067

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

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

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