【问题标题】:Function Values using Differential Evolution使用差分进化的函数值
【发布时间】:2012-02-17 00:05:47
【问题描述】:

如何使用微分进化求函数函数 f(x) = -x(x+1) 从 -500 到 500 的最大值?我正在制作的国际象棋程序需要这个,我已经开始研究差分进化,但仍然发现它很难理解,更不用说用于程序了。谁能帮助我以简单的方式向我介绍该算法,并可能提供一些此类程序的示例伪代码?

【问题讨论】:

  • 我不明白你为什么要使用差异进化。你知道一阶导数是-2x - 1,所以你可以通过这种方式找到临界点。然后你可以计算二阶导数-2,恰好是-2,这意味着图形是凹下的,这意味着你的临界点是你的最大值。您的最大值将为0 = -2x - 1x = -1/2
  • 顺便说一句,我喜欢你的头像图标。
  • 我也不懂……但是我的组长(这是一群朋友为了好玩而做的一个项目)希望我使用差分进化来得出答案。你能告诉我如何使用这种方法来完成吗?谢谢。编辑:感谢头像:D

标签: java chess evolutionary-algorithm differential-evolution


【解决方案1】:

首先,很抱歉回复晚了。

我敢打赌,您不会知道要尝试最大化的函数的导数,这就是您要使用差分进化算法而不是牛顿-拉夫森方法之类的原因。

我找到了一个很好的链接,它以简单的方式解释了差异进化:http://web.as.uky.edu/statistics/users/viele/sta705s06/diffev.pdf

在第一页,有一个部分解释了算法:

让每一代点由n个点组成,每个点有j项。

初始化一个大小为j 的数组。添加来自-500 to 500 的不同随机x 值的数字j,您现在正在考虑的区间。理想情况下,您会知道最大值在哪里,并且您的x 值更有可能在那里。

对于每个 j,从点集合 x 中均匀随机选择两个点 yj,1 和 yj,2 (男) . 构造一个候选点 cj = x (男) j + α(yj,1 - yj,2)。基本上这两个 y 值涉及 选择一个随机的方向和距离,然后通过添加该随机数来找到候选者 到当前值的方向和距离(按 α 缩放)。

嗯...这有点复杂。遍历您在上一步中创建的数组。对于每个 x 值,选择两个随机索引(yj1yj2)。使用cx = α(yj1 − yj2) 构造候选x 值,您可以在其中选择α。您可以尝试使用不同的 alpha 值。

检查哪个更大,候选值或j 处的 x 值。如果候选值较大,则将其替换为j 处的x 值。

这样做直到数组中的所有值都或多或少相似。 Tahdah,数组的任何值都将是最大值。只是为了减少随机性(或者这可能并不重要......),将它们平均在一起。

about 方法越严格,得到的近似值就越好,但需要的时间越长。

例如,我会使用Math.abs(a - b) <= alpha /10000 而不是Math.abs(a - b) <= alpha /10,以获得更好的近似值。

您将获得所需值的良好近似值。

编码愉快!

我为此响应编写的代码:

public class DifferentialEvolution {

public static final double alpha = 0.001;

public static double evaluate(double x) {
    return -x*(x+1);
}

public static double max(int N) { // N is initial array size.

    double[] xs  = new double[N];

    for(int j = 0; j < N; j++) {
        xs[j] = Math.random()*1000.0 - 500.0; // Number from -500 to 500.
    }

    boolean done = false;
    while(!done) {
        for(int j = 0; j < N; j++) {
            double yj1 = xs[(int)(Math.random()*N)]; // This might include xs[j], but that shouldn't be a problem.
            double yj2 = xs[(int)(Math.random()*N)]; // It will only slow things down a bit.

            double cj = xs[j] + alpha*(yj1-yj2);

            if(evaluate(cj) > evaluate(xs[j])) {
                xs[j] = cj;
            }
        }

        double average = average(xs); // Edited

        done = true;
        for(int j = 0; j < N; j++) { // Edited
            if(!about(xs[j], average)) { // Edited
                done = false;
                break;
            }
        }

    }
    return average(xs);

}

public static double average(double[] values) {
    double sum = 0;
    for(int i = 0; i < values.length; i++) {
        sum += values[i];
    }

    return sum/values.length;

}

public static boolean about(double a, double b) {
    if(Math.abs(a - b) <= alpha /10000) { // This should work.
        return true;
    }
    return false;
}

public static void main(String[] args) {

    long t = System.currentTimeMillis();
    System.out.println(max(3));
    System.out.println("Time (Milliseconds): " + (System.currentTimeMillis() - t));

}

}

如果您在阅读本文后有任何问题,请随时在 cmets 中提问。我会尽力帮忙的。

【讨论】:

  • 非常感谢!这个回复非常周到地解释了这个概念,并让我看到了代码以进一步理解。我还将注意研究牛顿-拉夫森方法。您详细的演练帮助我轻松了解如何解决问题。
  • @ProgramFun 该程序可能存在错误。当我检查数组值是否都相似时,我使用“相似性的传递属性”。不存在这样的事情。我现在将编辑程序以增加它生成的值的准确性。
  • 感谢您注意到这一点并帮助我了解更好的工作程序。
猜你喜欢
  • 2021-08-02
  • 2012-03-27
  • 2017-09-03
  • 1970-01-01
  • 2014-08-26
  • 1970-01-01
  • 2019-10-26
  • 2019-03-05
  • 2013-10-20
相关资源
最近更新 更多