13

I try to learn and implement a simple genetic algorithm library for my project. At this time, evolution, selection of population is ready, and I'm trying to implement a simple good mutation operator like the Gaussian mutation operator (GMO) for my genetic evolution engine in Java and Scala.

I find some information on Gaussian mutation operator (GMO) into the paper A mutation operator based on a Pareto ranking for multi-objective evolutionary algorithms (P.M. Mateo, I. Alberto), page 6 and 7.

But I have some problem to find other information on how to implement this Gaussian mutation operator and other useful variants of this operator in Java. What should I do?

I'm using the random.nextGaussian() function of random Java util, but this method only returns a random number between 0 and 1.

So,

a) How can I modify the precision of the return number in this case? (For example, I want to get a random double number between 0 and 1 with step equal to 0.00001.)

b) and how can I specify mu and sigma for this function, because I want to search locally about a value of my genome, not between -1 and 1. How can I ajust that local research around my genome value?

After research, I found an answer for the b) question. It seems I can displace the Gaussian random number like this:

 newGenomeValue = oldGenomeValue + (( gaussiandRndNumber * sigma ) + mean )

where mean = my genome value.

(Cf. method of bottom page in How can I generate random numbers with a normal or Gaussian distribution?.)

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
reyman64
  • 523
  • 4
  • 34
  • 73
  • What exactly do you mean by "precision of the return number"? – NPE Jun 08 '11 at 10:13
  • The numbers of number after comma : http://en.wikipedia.org/wiki/Double_precision_floating-point_format – reyman64 Jun 08 '11 at 10:36
  • In what way to you want to "modify" "the numbers of number after comma"? `nextGaussian` gives you a `double`. Are you saying that's not enough for your needs? – NPE Jun 08 '11 at 10:38
  • I'm using this number to calibrate probability law in my simulation. I need number between 0,01 and 0.00000001, so if i add a double with only one number precision after coma (for example 0.11111 0.255525 0.114182 etc. ), it's problematic because i need to add random number like this : 0.001, 0.001252, 0,000352, etc. – reyman64 Jun 08 '11 at 11:20
  • 4
    Your comment actually contains all you need. The z, z_k, z_k' from that paper are all 0-mean, stddev 1 random variables (like you'd get from nextGaussian()) and you just need to scale them in the same way as they do in the paper (i.e., mean of x_k, stddev of sigma_k for the x_k and exp(tau'*z+tau*z_k) for the multiplicative update to sigma. – Yannick Versley Jun 13 '11 at 09:49
  • I don't know if OP added the tag of AI for a GA question (or an editor), but GAs are not Artificial Intelligence unless considered in the most banal sense. – alphazero Jun 20 '11 at 06:05

4 Answers4

5

To answer question a, all you have to do is round to the nearest 0.00001 to get your answer in those units. For example:

  step = 0.00001;
  quantized_x = step * Math.rint(x / step);

Now for part b, you have the right idea and the code you presented should work. All you need to do is rescale your variable to the desired range. The only thing I can add is that the underlying reason this works is the change of variables theorem from calculus: http://en.wikipedia.org/wiki/Integration_by_substitution

If you work out this formula in the case of a Gaussian distribution with 0 mean and standard deviation 1 being transformed by a linear shift and a rescaling, then you will see that what you wrote out was indeed correct.

Putting it all together, here is some code that should do the trick:

double next_gaussian()
{
    double x = rng.nextGaussian();  //Use whichever method you like 
                                    //here to generate an initial [-1,1] gaussian distribution

    y = (x * 0.5) + 0.5;                //Rescale to [0,1]

    return Math.rint(y * 100000.0) * 0.00001; //Quantize to step size 0.00001
}
Mikola
  • 9,176
  • 2
  • 34
  • 41
3

I strongly suggest to DO NOT use the Java's random number generator. It uses the linear congruential generator, which has known limitations:

If higher quality random numbers are needed, and sufficient memory is available (~ 2 kilobytes), then the Mersenne twister algorithm provides a vastly longer period (219937-1) and variate uniformity.[9] The Mersenne twister generates higher-quality deviates than almost any LCG.[citation needed] A common Mersenne twister implementation, interestingly enough, uses an LCG to generate seed data.* (From Wikipedia)

Accordingly, I suggest you to consider a Mersenne twister implementation. In particular, I'm using the ECJ's implementation, which also has the ability to generate Gaussian numbers.

If you need compatibility with Java's Random interface use http://code.google.com/p/ecj/source/browse/trunk/ecj/ec/util/MersenneTwister.java.

http://code.google.com/p/ecj/source/browse/trunk/ecj/ec/util/MersenneTwisterFast.java is faster, but it does not implement the Random interface.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matteo
  • 1,367
  • 7
  • 25
  • 1
    I forgot to say... the nextGaussian returns a sample from a Normal distribution. Since you want to change the mean and the variance, you should apply the standard transformations you were mentioning in your comment. For additional information see http://people.math.sfu.ca/~cschwarz/Stat-301/Handouts/node70.html – Matteo Jun 17 '11 at 08:00
  • Thx for help, i'm using a random generator from lecuyer in SSJ library and math.commons (apache fundation) like WEll. I have no answer about generating more little variation in my random double :/ Actually, i'm using a random(int) between 1 and 1E6 to divide my random(double) ... – reyman64 Jun 17 '11 at 09:15
-1

Here's how you can generate a random number between 0 and n:

public static double random(int n)
{
    return Math.random() * n;
}

If you need an integer, cast it to int but add one to n, ie (int)random(n + 1)

Bohemian
  • 412,405
  • 93
  • 575
  • 722
-1

To change the "precision" of the number, do something like:

((int)(100*rand))/100.0

This will round the variable rand to 2 decimal places. Of course, you'll have to be careful about small floating point rounding errors so it won't necessarily be exact.

As for the implementing the GMO, the paper describes how to do it pretty precisely. I'm not sure how it could be explained any clearer. I'm assuming you have an x and a sigma somewhere in your code and you just transform it using the mathematical operation described.

tskuzzy
  • 35,812
  • 14
  • 73
  • 140