【问题标题】:Simulated Binary Crossover (SBX) crossover operator in Scala genetic algorithm (GA) libraryScala 遗传算法 (GA) 库中的模拟二元交叉 (SBX) 交叉算子
【发布时间】:2012-02-13 16:09:55
【问题描述】:

我在一个很小的研究团队工作,在 Scala 中创建/调整遗传算法库,用于使用 Scientific Worklow System 进行分布式计算,在我们的例子中,我们使用开源 OpenMole 软件 (http://www.openmole.org/)。

最近,我尝试理解并重新实现用 JMetal Metaheuristics 库 (http://jmetal.sourceforge.net/) 编写的 SBX 交叉算子,以适应我们 Scala 库中的函数版本。

我写了一些代码,但我需要我们的建议或您对 java 库中定义的 SBX 的验证,因为源代码 (src in svn) 看起来不等于这里写的原始方程式:http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.33.7291&rep=rep1&type=pdf 在页面30,在附件A中

第一个问题,我不明白 JMetal 的 java 版本,为什么它们使用两个不同的 beta 值?!

  • beta1 在等式中使用 min[(y1 - yL), ...] 和
  • 的第一个参数
  • beta2 使用 min [... , (yu - y2)]) 的第二个参数

Beta 1 和 2 用于计算 alpha 值和 2(所以这里和 jmetal 中我们也有两个不同的 alpha 值 alpha1 和 2)...

同样的问题/问题,我们在 jmetal 中对 betaq(java 代码)或 Deb 方程进行了两次计算,结果为:

第二个问题,SBX伪算法(2)和(3)过程中使用的符号是什么意思,和简单的beta有什么区别?尤其是当我们想要计算交叉父母的孩子/后代时,就像这里:

编辑

  • 更正空操作 if/else 块

  • jmetal 中的代码作者给了我 Nsga-II 算法的原始源代码的链接,他解释说 Deb 对 SBX 的描述与他的实现不同:/

    http://www.iitk.ac.in/kangal/codes.shtml

    我不明白jmetal和原始源代码中描述和实现的区别,你有解释吗?

  • 正确的 if/else 返回地图

开始翻译成scala

  class SBXBoundedCrossover[G <: GAGenome, F <: GAGenomeFactory[G]](rate: Random => Double = _.nextDouble) extends CrossOver [G, F] {

  def this(rate: Double) = this( _ => rate)

  def crossOver (genomes : IndexedSeq [G], factory: F) (implicit aprng : Random) = {
    val g1 = genomes.random
    val g2 = genomes.random
    val crossoverRate = rate(aprng)
    val EPS =  1.0e-14
    val numberOfVariables = g1.wrappedValues.size
    val distributionIndex = 2

    val variableToMutate = (0 until g1.wrappedValues.size).map{x => !(aprng.nextDouble < 0.5)}

    //crossover probability
    val offspring = {

      if (aprng.nextDouble < crossoverRate) {      
        (variableToMutate zip (g1.wrappedValues zip g2.wrappedValues)) map {
          case (b, (g1e, g2e)) =>
            if(b) {
              if (abs(g1e - g2e) > EPS){

                val y1 = min(g1e, g2e)
                val y2 = max(g2e, g1e)

                var yL = 0.0 //g1e.getLowerBound
                var yu = 1.0 //g1e.getUpperBound  
                var rand = aprng.nextDouble   // ui

                var beta1 = 1.0 + (2.0 * (y1 - yL)/(y2 - y1))
                var alpha1 = 2.0 - pow(beta1,-(distributionIndex+1.0))
                var betaq1 = computebetaQ(alpha1,distributionIndex,rand)

                //calcul offspring 1 en utilisant betaq1, correspond au β barre
                var c1 = 0.5 * ((y1 + y2) - betaq1 * (y2 - y1)) 

                // -----------------------------------------------

                var beta2 = 1.0 + (2.0 * (yu - y2) / (y2 - y1))
                var alpha2 = 2.0 - pow(beta2, -(distributionIndex + 1.0))

                var betaq2 = computebetaQ(alpha2,distributionIndex,rand)

                //calcul offspring2 en utilisant betaq2
                var c2 = 0.5 * ((y1 + y2) + betaq2 * (y2 - y1))

                if (c1 < yL) c1 = yL
                if (c1 > yu) c1 = yu

                if (c2 < yL) c2 = yL
                if (c2 > yu) c2 = yu   

                if (aprng.nextDouble <= 0.5) {
                  (c2,c1)
                } else {
                  (c1, c2) 
                }

              }else{
                (g1e, g2e)
              }

            }else{
              (g2e, g1e)
            }
        }

      }else{
        // not so good here ...
        (g1.wrappedValues zip g2.wrappedValues)
      }
    }
    (factory.buildGenome(offspring.map{_._1}),  factory.buildGenome(offspring.map{_._2}))
  }

  def computebetaQ(alpha:Double,  distributionIndex:Double,  rand:Double):Double = { 
    if (rand <= (1.0/alpha)){
      pow ((rand * alpha),(1.0 / (distributionIndex + 1.0)))
    } else {
      pow ((1.0 / (2.0 - rand * alpha)),(1.0 / (distributionIndex + 1.0)))
    } 
  }

非常感谢您的建议,或帮助解决这个问题。

SR

【问题讨论】:

  • 你想用if (g1e &lt; g2e){ var y1 = g1e var y2 = g2e } else { var y1 = g2e var y2 = g1e }完成什么?该代码无效。为什么不只是val y1 = min(g1e, g2e), y2 = max(g2e, g1e);
  • 整个 if-else 代码都是 No-Op。
  • @reyman64,Scala 块不是作用域吗?
  • @MikeSamuel,你是对的,对不起,我更新了代码

标签: java scala artificial-intelligence genetic-algorithm mathematical-optimization


【解决方案1】:

Reyman64,你的问题就是我一直在寻找的答案。谢谢。

我拿了你链接的论文和 Deb 的实现代码,并试图理解两者。为此,我几乎注释了代码的每一行。它们仅在 beta 的计算上有所不同。

由于 Deb 在他的 NSGA-II 实现中使用了这段代码,所以我会坚持使用这个版本的算法。

如果有人遇到与我相同的情况(不了解如何实现 SBX),我将我的评论留在以下要点中,看看。

https://gist.github.com/Tiagoperes/1779d5f1c89bae0cfdb87b1960bba36d

【讨论】:

    【解决方案2】:

    我为 HeuristicLab (C#) 实现了 SBX(它被称为 Simulated Binary Crossover btw)。你可以看看我们SimulatedBinaryCrossover的实现。然而,我从不同的参考资料中获取了描述(论文标题:1995 年的“连续搜索空间的模拟二进制交叉”)。完整的引用在源代码中给出。

    【讨论】:

    • 我更正了我的问题的标题 :) 看起来这是第一个没有有界变量管理的 SBX 版本,但是阅读不同的实现真是太好了!今晚看了源码,谢谢!
    • 帮助自己,我仔细检查了参考资料和网上找到的一些材料(某处有一个有用的演示文稿)。如果您发现错误,请告诉我。
    • 我对您的代码有一个问题,您似乎只返回一个父母,或者恕我直言交叉返回两个父母不?为什么只计算交叉的一部分(第 92 行的概率 result1[i] 和第 95 行的 result2[i],不?
    • 杂交产生两个后代还是只产生一个并不重要。我们对父母数量的两倍进行抽样,每对产生一个后代。如果您在实现中返回两个后代,那很好。
    • 好吧,似乎 Deb 使用了与本文对 SBX 的描述相比不同的实现,我们可以在他的 NSGA-II 源代码中看到(参见更新后的帖子)
    猜你喜欢
    • 1970-01-01
    • 2014-08-12
    • 2016-08-31
    • 1970-01-01
    • 2015-06-29
    • 2015-07-03
    • 2016-09-16
    • 1970-01-01
    相关资源
    最近更新 更多