Значения функций с использованием дифференциальной эволюции - PullRequest
3 голосов
/ 17 февраля 2012

Как я могу использовать дифференциальную эволюцию, чтобы найти максимальные значения функции функции f (x) = -x (x + 1) от -500 до 500? Мне это нужно для шахматной программы, которую я делаю, я начал изучать дифференциальную эволюцию и до сих пор считаю ее довольно трудной для понимания, не говоря уже об использовании программы. Может ли кто-нибудь помочь мне, введя меня в алгоритм простым способом и, возможно, приведя пример псевдокода для такой программы?

1 Ответ

3 голосов
/ 17 февраля 2012

Во-первых, извините за поздний ответ.

Могу поспорить, что вы не будете знать производных функции, которую вы будете пытаться максимизировать, поэтому вы хотите использовать алгоритм дифференциальной эволюции, а не что-то вроде метода Ньютона-Рафсона.

Я нашел отличную ссылку, которая объясняет Дифференциальную Эволюцию в прямой форме: http://web.as.uky.edu/statistics/users/viele/sta705s06/diffev.pdf.

На первой странице есть раздел с объяснением алгоритма:

Пусть каждое поколение точек состоит из n точек с j членами в каждом.

Инициализировать массив размером j. Добавьте число j различных случайных значений x из -500 to 500 - интервал, который вы сейчас рассматриваете. В идеале вы должны знать, где будет находиться максимальное значение, и увеличите вероятность того, что ваши значения x будут там.

Для каждого j случайным образом выбрать две точки yj, 1 и yj, 2 из набора точек x. (М) , Построить точку-кандидата cj = x (М) j + α (yj, 1 - yj, 2). В основном два значения у включают в себя выбрать случайное направление и расстояние, и кандидат будет найден путем добавления этого случайного направление и расстояние (в масштабе α) до текущего значения.

Хммм ... Это немного сложнее. Переберите массив, который вы создали на последнем шаге. Для каждого значения x выберите два случайных индекса (yj1 и yj2). Создайте значение кандидата x с cx = α(yj1 − yj2), где вы выбираете α. Вы можете попробовать поэкспериментировать с различными значениями альфа.

Проверьте, какой из них больше, значение кандидата или значение x в j. Если значение кандидата больше, замените его значением x на j.

Делайте все это, пока все значения в массиве не будут более или менее похожи. Тахда, любое из значений массива будет максимальным значением. Просто чтобы уменьшить случайность (или, может быть, это не важно ....), усредните их все вместе.

Чем строже вы применяете метод about, тем лучше приближения, но тем больше времени это займет.

Например, вместо Math.abs(a - b) <= alpha /10 я бы сделал Math.abs(a - b) <= alpha /10000, чтобы получить лучшее приближение.

Вы получите хорошее приближение к нужному значению.

Удачного кодирования!

Код, который я написал для этого ответа:

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));

}

}

Если после прочтения у вас возникнут вопросы, не стесняйтесь задавать их в комментариях. Я сделаю все возможное, чтобы помочь.

...