Как реализовать гауссовский оператор мутации для генетического алгоритма в Java

Я пытаюсь изучить и реализовать простую библиотеку генетических алгоритмов для моего проекта. В это время эволюция, отбор популяции готов, и я пытаюсь реализовать простой хороший оператор мутации, такой как гауссов оператор мутации (GMO) для моего движка генетической эволюции в Java и Scala.

Я нахожу некоторую информацию о гауссовском операторе мутации (GMO) в документе оператор мутации на основе ранжирования Парето для многоцелевых эволюционные алгоритмы (П. М. Матео, И. Альберто), стр. 6 и 7.

но у меня есть проблема найти другую информацию о том, как реализовать этот гауссовский оператор мутации и другие полезные варианты этого оператора в Java. Что мне делать?

я использую random.nextGaussian() функция случайного Java util, но этот метод возвращает только случайное число между 0 и 1.

и

a) как я могу изменить точность возвращаемого номера в это дело? (Например, я хочу получить случайное двойное число между 0 и 1 с шагом, равным 0.00001.)

B) и как я могу указать mu и sigma для этой функции, потому что я хочу искать локально о значении моего генома, а не между -1 и 1. Как я могу изменить это локальное исследование вокруг моей ценности генома?

после исследования я нашел ответ на вопрос б). Кажется, я могу сместить гауссово случайное число, как это:

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

здесь mean = значение моего генома.

(МФ. метод нижней страницы в как я могу генерировать случайные числа с нормальным или гауссовым распределением?.)

4 ответов


чтобы ответить на вопрос a, все, что вам нужно сделать, это округлить до ближайшего 0.00001, чтобы получить ответ в этих единицах. Например:

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

теперь для части b у вас есть правильная идея, и код, который вы представили, должен работать. Все, что вам нужно сделать, это изменить переменную на нужный диапазон. Единственное, что я могу добавить, что основная причина, по которой это работает, - это изменение теоремы переменных из исчисления: http://en.wikipedia.org/wiki/Integration_by_substitution

Если вы разработаете эту формулу в случае гауссова распределения с 0 средним и стандартным отклонением 1, преобразуемым линейным сдвигом и масштабированием, то вы увидите, что то, что вы написали, было действительно правильным.

собирая все это вместе, вот некоторый код, который должен сделать трюк:

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
}

Я настоятельно рекомендую, чтобы НЕ используйте генератор случайных чисел Java. Он использует линейный конгруэнтный генератор, который имеет известные ограничения:

Если необходимы более качественные случайные числа и имеется достаточная память (~ 2 килобайта), то алгоритм Mersenne twister обеспечивает значительно более длительный период (219937-1) и варьирует однородность.[9] Mersenne twister генерирует более качественные отклонения, чем почти любые LCG.[нужная цитата] общая реализация Mersenne twister, что интересно, использует LCG для генерации исходных данных.* (Из Википедии)

соответственно, я предлагаю вам рассмотреть реализацию Mersenne twister. В частности, я использую реализацию ECJ, которая также имеет возможность генерировать гауссовых чисел.

Если вам нужна совместимость со случайным интерфейсом Java 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 быстрее, но он не реализует случайный интерфейс.


чтобы изменить "точность" числа, сделайте что-то вроде:

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

это будет округлять переменную rand до 2 знаков после запятой. Конечно, вы должны быть осторожны с небольшими ошибками округления с плавающей запятой, поэтому это не обязательно будет точным.

что касается реализации ГИО, в статье описывается, как это сделать довольно точно. Не знаю, как это можно объяснить яснее. Я предполагаю, что у вас есть x и sigma где-то в коде и вы просто преобразуете его, используя описанную математическую операцию.


вот как вы можете генерировать случайное число от 0 до n:

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

Если вам нужно целое число, бросил его в int но добавьте один к n, т. е. (int)random(n + 1)