Как реализовать гауссовский оператор мутации для генетического алгоритма в 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)