Как реализовать гауссовский оператор мутации для генетического алгоритма в Java
Я пытаюсь изучить и реализовать простую библиотеку генетического алгоритма для моего проекта. В это время эволюция, выбор населения готов, и я пытаюсь реализовать простой оператор хорошей мутации, как гауссовский оператор мутации (GMO ) для моего механизма генетической эволюции в Java и Scala.
Я нахожу некоторую информацию о гауссовском операторе мутации (GMO) в статье Оператор мутации, основанный на ранжировании Парето для многоцелевых эволюционных алгоритмов (П. М. Матео, И. Альберто), стр. 6 и 7.
Но у меня есть некоторая проблема, чтобы найти другую информацию о том, как реализовать этот гауссовский оператор мутации и другие полезные варианты этого оператора в Java. Что мне делать?
Я использую функцию random.nextGaussian()
случайного использования Java, но этот метод возвращает только случайное число от 0 до 1.
Итак,
a) Как я могу изменить точность возвращаемого числа в этом случае? (Например, я хочу получить случайное двойное число между 0 и 1 с шагом, равным 0,00001.)
b) и как я могу указать mu
и sigma
для этой функции, потому что я хочу искать локально значение моего генома, а не между -1 и 1. Как я могу исправить это локальное исследование вокруг моего значение генома?
Изменить 1: После исследования я нашел ответ на вопрос b). Кажется, я могу вытеснить гауссовское случайное число следующим образом:
newGenomeValue = oldGenomeValue + (( gaussiandRndNumber * sigma ) + mean )
где mean
= мое значение генома.
(метод нижней страницы в Как я могу генерировать случайные числа с нормальным или гауссовским распределением?.
Ответы
Ответ 1
Чтобы ответить на вопрос 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
}
Ответ 2
Я настоятельно рекомендую НЕ использовать генератор случайных чисел Java. Он использует линейный конгруэнтный генератор который имеет известные ограничения:
Если необходимы более качественные случайные числа, и имеется достаточная память (~ 2 килобайта), тогда алгоритм Twers Mersenne обеспечивает значительно более длительный период (219937-1) и равномерность изменения. [9] Mersenne twister генерирует более качественные отклонения, чем почти любые LCG. [Править] Обычная реализация Mersenne twister, что интересно, использует LCG для генерации данных семян. * (Из Википедии)
Соответственно, я предлагаю вам рассмотреть реализацию Mersenne twister. В частности, я использую реализацию ECJ, которая также имеет возможность генерировать гауссовские числа.
Если вам нужна совместимость с интерфейсом Java Random, используйте 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 работает быстрее, но не реализует интерфейс Random.
Ответ 3
Чтобы изменить "точность" числа, сделайте следующее:
((int)(100*rand))/100.0
Это будет округлять переменную rand
до двух знаков после запятой. Конечно, вы должны быть осторожны с небольшими ошибками округления с плавающей запятой, поэтому это не обязательно будет точно.
Что касается внедрения ГИО, то в документе описывается, как это сделать довольно точно. Я не знаю, как это можно объяснить более ясными. Я предполагаю, что у вас есть x
и sigma
где-то в вашем коде, и вы просто преобразуете его, используя описанную математическую операцию.
Ответ 4
Здесь вы можете создать случайное число между 0 и n:
public static double random(int n)
{
return Math.random() * n;
}
Если вам нужно целое число, добавьте его в int
, но добавьте его в n, т.е. (int)random(n + 1)