【问题标题】:How to implement the Gaussian mutation operator for a genetic algorithm in Java如何在 Java 中实现遗传算法的高斯变异算子
【发布时间】:2011-09-10 16:12:06
【问题描述】:

我尝试为我的项目学习和实现一个简单的遗传算法库。此时,进化、种群选择已经准备就绪,我正在尝试用 Java 和 Scala 为我的基因进化引擎实现一个简单的好变异算子,例如 Gaussian mutation operator (GMO)。

我在论文 A mutation operator based on a Pareto ranking for multi-objective evolutionary algorithms (P.M. Mateo, I. Alberto) 第 6 和 7 页中找到了一些关于高斯变异算子 (GMO) 的信息。

但是我有一些问题要找到关于如何在 Java 中实现这个高斯变异算子和这个算子的其他有用变体的其他信息。我该怎么办?

我使用的是random Java util的random.nextGaussian()函数,但是这个方法只返回一个0到1之间的随机数。

所以,

a) 在这种情况下如何修改返回数字的精度? (例如,我想得到一个介于 0 和 1 之间的随机双数,步长等于 0.00001。)

b) 以及如何为这个函数指定 musigma,因为我想在本地搜索我的基因组的值,而不是在 -1 和 1 之间。我怎样才能调整我周围的本地研究基因组价值?

经过研究,我找到了 b) 问题的答案。看来我可以像这样置换高斯随机数:

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

mean = 我的基因组值。

(参见How can I generate random numbers with a normal or Gaussian distribution?中的底部页面方法。)

【问题讨论】:

  • “返回数字的精度”到底是什么意思?
  • 你想以什么方式“修改”“逗号后面的数字”? nextGaussian 给你一个double。您是说这还不足以满足您的需求吗?
  • 我在模拟中使用这个数字来校准概率定律。我需要介于 0,01 和 0.00000001 之间的数字,所以如果我在 coma 之后添加一个只有一个数字精度的双精度数(例如 0.11111 0.255525 0.114182 等),这是有问题的,因为我需要像这样添加随机数:0.001、0.001252、0 ,000352 等
  • 您的评论实际上包含了您所需要的一切。该论文中的 z、z_k、z_k' 都是 0 均值、stddev 1 随机变量(就像您从 nextGaussian() 获得的一样),您只需要以与论文中相同的方式缩放它们(即, x_k 的平均值, x_k 的 sigma_k 的 stddev 和 sigma 的乘法更新的 exp(tau'z+tauz_k)。

标签: java random artificial-intelligence genetic-algorithm gaussian


【解决方案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 的随机数生成器。它使用linear congruential generator,它有已知的限制:

    如果需要更高质量的随机数,并且有足够的可用内存(约 2 KB),则 Mersenne twister 算法可提供更长的周期 (219937-1) 和变化的均匀性。[9] Mersenne twister 生成的偏差几乎比任何 LCG 都高。[需要引用] 有趣的是,一个常见的 Mersenne twister 实现使用 LCG 生成种子数据。*(来自 Wikipedia)

    因此,我建议您考虑使用 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 接口。

    【讨论】:

    • 我忘了说... nextGaussian 返回正态分布的样本。由于您想更改均值和方差,因此您应该应用您在评论中提到的标准转换。有关更多信息,请参阅people.math.sfu.ca/~cschwarz/Stat-301/Handouts/node70.html
    • 感谢帮助,我在 SSJ 库和 math.commons(apache 基金会)中使用来自 lecuyer 的随机生成器,例如 WEll。我没有关于在我的随机双精度中产生更多小变化的答案:/ 实际上,我使用 1 和 1E6 之间的随机数(int)来划分我的随机数(双精度)...
    【解决方案3】:

    以下是生成介于 0 和 n 之间的随机数的方法:

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

    如果您需要一个整数,请将其转换为int,但将 n 加一,即(int)random(n + 1)

    【讨论】:

      【解决方案4】:

      要更改数字的“精度”,请执行以下操作:

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

      这会将变量rand 舍入到小数点后两位。当然,您必须注意小的浮点舍入误差,因此不一定准确。

      关于 GMO 的实施,本文描述了如何非常精确地实施。我不确定如何更清楚地解释它。我假设你的代码中有一个x 和一个sigma,你只需使用描述的数学运算对其进行转换。

      【讨论】:

        猜你喜欢
        • 2017-03-05
        • 2015-06-25
        • 1970-01-01
        • 2012-09-23
        • 2016-11-28
        • 2014-10-02
        • 2017-10-10
        • 2015-03-01
        • 2020-08-04
        相关资源
        最近更新 更多