有效实施适合度比例的“轮盘赌” 选择

发布于 2024-08-01 14:58:55 字数 1620 浏览 11 评论 0 原文

我目前正在用 C 语言编写一种键盘布局优化算法(例如 Peter Klausler 设计的算法),并且我想实现此处所述的适应度比例选择(PDF 链接):

通过轮盘赌选择您选择的 人口成员基于 轮盘赌轮模型。 做一个馅饼 图表,其中成员的面积 切片与整个圆的比例是 成员的适应度与总适应度的比值 人口。 正如你所看到的,如果一个点 在圆的圆周上是 随机挑选那些人口 体质较高的会员将获得 被选中的概率更高。 这确保了自然选择 地点。

问题是,我不知道如何有效地实施它。 我想到了两种方法:一种不可靠,另一种慢。

第一个是慢的:

对于长度为 N 的键盘池,创建一个长度为 N 的数组,其中数组的每个元素实际上包含两个元素:最小值和最大值。 每个键盘都有相应的最小值和最大值,范围取决于键盘的适合度。 例如,如果键盘 0 的适合度为 10,键盘 1 的适合度为 20,键盘 2 的适合度为 25,则它看起来像这样: 代码:(

array[0][0] = 0; // minimum
array[0][1] = 9; // maximum
array[1][0] = 10;
array[1][1] = 30;
array[2][0] = 31;
array[2][1] = 55;

在这种情况下,适应度越低越好,因为这意味着需要更少的努力。)

然后生成一个随机数。 无论该数字属于哪个范围,相应的键盘都会被“杀死”并替换为不同键盘的后代。 根据需要重复此操作多次。

这样做的问题是速度非常慢。 需要 O(N^2) 次操作才能完成。

接下来是快速的:

首先弄清楚键盘的最低和最高适合度是什么。 然后生成一个介于(最低适应度)和(最高适应度)之间的随机数,并杀死所有适应度高于生成数字的键盘。 这很有效,但不能保证只能杀死一半的键盘。 它的机制也与“轮盘赌”选择有些不同,因此它甚至可能不适用。

那么问题来了,什么是高效的实施呢?

本书第 36 页有一个比较有效的算法(链接),但问题是,只有轮盘选择一次或几次才有效。 有没有有效的方法可以并行进行许多轮盘赌选择?

I am currently writing a keyboard layout optimization algorithm in C (such as the one designed by Peter Klausler) and I want to implement a fitness-proportionate selection as described here (PDF Link):

With roulette selection you select
members of the population based on a
roullete wheel model. Make a pie
chart, where the area of a member’s
slice to the whole circle is the ratio
of the members fitness to the total
population. As you can see if a point
on the circumfrence of the circle is
picked at random those population
members with higher fitness will have a
higher probability of being picked.
This ensures natural selection takes
place.

The problem is, I don't see how to implement it efficiently. I've thought of two methods: one is unreliable, and the other is slow.

First, the slow one:

For a keyboard pool of length N, create an array of length N where each element of the array actually contains two elements, a minimum and a maximum value. Each keyboard has a corresponding minimum and maximum value, and the range is based on the fitness of the keyboard. For example, if keyboard zero has a fitness of 10, keyboard one has a fitness of 20, and keyboard two has a fitness of 25, it would look like this:
Code:

array[0][0] = 0; // minimum
array[0][1] = 9; // maximum
array[1][0] = 10;
array[1][1] = 30;
array[2][0] = 31;
array[2][1] = 55;

(In this case a lower fitness is better, since it means less effort is required.)

Then generate a random number. For whichever range that number falls into, the corresponding keyboard is "killed" and replaced with the offspring of a different keyboard. Repeat this as many times as desired.

The problem with this is that it is very slow. It takes O(N^2) operations to finish.

Next the fast one:

First figure out what the lowest and highest fitnesses for the keyboards are. Then generate a random number between (lowest fitness) and (highest fitness) and kill all keyboards with a fitness higher than the generated number. This is efficient, but it's not guaranteed to only kill half the keyboards. It also has somewhat different mechanics from a "roulette wheel" selection, so it may not even be applicable.

So the question is, what is an efficient implementation?

There is a somewhat efficient algorithm on page 36 of this book (Link), but the problem is, it's only efficient if you do the roulette selection only one or a few times. Is there any efficient way to do many roulette selections in parallel?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

橘虞初梦 2024-08-08 14:58:55

一方面,如果您想“杀死”您的选择(很可能是具有分数的键盘),听起来您正在谈论不适合分数。

我认为没有必要维护两个数组。 我认为最简单的方法是维护一个分数数组,然后迭代该数组以做出选择:

/* These will need to be populated at the outset */
int scores[100];
int totalScore;

for (gen = 0; gen < nGenerations; ++gen) {
    /* Perform a selection and update */
    int r = rand() % totalScore;        /* HACK: using % introduces bias */
    int t = 0;
    for (i = 0; i < 100; ++i) {
        t += scores[i];
        if (r < t) {
            /* Bingo! */
            totalScore -= scores[i];
            keyboards[i] = generate_new_keyboard_somehow();
            scores[i] = score_keyboard(keyboards[i]);
            totalScore += scores[i];    /* Now totalScore is correct again */
        }
    }
}

对于 n 个键盘,每次选择/更新都需要 O(n) 时间。

For one thing, it sounds like you are talking about unfitness scores if you want to "kill off" your selection (which is likely to be a keyboard with high score).

I see no need to maintain two arrays. I think the simplest way is to maintain a single array of scores, which you then iterate through to make a choice:

/* These will need to be populated at the outset */
int scores[100];
int totalScore;

for (gen = 0; gen < nGenerations; ++gen) {
    /* Perform a selection and update */
    int r = rand() % totalScore;        /* HACK: using % introduces bias */
    int t = 0;
    for (i = 0; i < 100; ++i) {
        t += scores[i];
        if (r < t) {
            /* Bingo! */
            totalScore -= scores[i];
            keyboards[i] = generate_new_keyboard_somehow();
            scores[i] = score_keyboard(keyboards[i]);
            totalScore += scores[i];    /* Now totalScore is correct again */
        }
    }
}

Each selection/update takes O(n) time for n keyboards.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文