這裏有一些代碼可能有幫助(我剛剛寫道):GA for ordering 10 values spaced by 1.0。它從100個完全隨機的等位基因開始,這正是您的代碼開始的方式。
我給GA解決的目標是按遞增順序對值進行排序,間隔爲1.0。它在適應函數Eval_OrderedDistance
中通過計算每對樣本的標準偏差從1.0開始。當適應度趨於0.0時,等位基因應開始按順序出現。
0代的最適合的染色體是完全隨機的,其餘的染色體也是如此。你可以看到鍛鍊價值是非常高的(即壞):
GEN: fitness (allele, ...)
0: 375.47460 (583.640, -4.215, -78.418, 164.228, -243.982, -250.237, 354.559, 374.306, 709.859, 115.323)
隨着世代延續,健身(標準差1.0)下降,直到它幾乎是完美的一代100000:
100: 68.11683 (-154.818, -173.378, -170.846, -193.750, -198.722, -396.502, -464.710, -450.014, -422.194, -407.162)
...
10000: 6.01724 (-269.681, -267.947, -273.282, -281.582, -287.407, -293.622, -302.050, -307.582, -308.198, -308.648)
...
99999: 0.67262 (-294.746, -293.906, -293.114, -292.632, -292.596, -292.911, -292.808, -292.039, -291.112, -290.928)
代碼的有趣的部分是適應度函數:
// try to pack the aleles together spaced apart by 1.0
// returns the standard deviation of the samples from 1.0
static float Eval_OrderedDistance(Chromosome c) {
float sum = 0;
int n = c.alele.Length;
for(int i=1; i<n; i++) {
float diff = (c.alele[i] - c.alele[i-1]) - 1.0f;
sum += diff*diff; // variance from 1.0
}
return (float)Math.Sqrt(sum/n);
}
而突變。我用一個簡單的交叉和一個「完全變異一個等位基因」:
Chromosome ChangeOne(Chromosome c) {
Chromosome d = c.Clone();
int i = rand.Next() % d.alele.Length;
d.alele[i] = (float)(rand.NextDouble()*2000-1000);
return d;
}
我用精英主義始終保持最好的染色體的一個完全相同的副本。然後使用突變和交叉產生100個新的染色體。
這聽起來像是你正在計算健身的方差,當然這會告訴你,你的人口的適合度都差不多。我發現它是非常重要重要的是你如何定義你的健身功能。適應度函數越精細,就越能區分染色體。顯然,由於你的gen 0返回的適應性方差爲68e-19,所以你的適應度函數返回的是完全不同的染色體的相似值。
你能分享你的健身計算嗎?或者您要求GA解決什麼問題?我認爲這可能會幫助我們幫助你。
[編輯:添加顯式健身共享/小生境]
我重新考慮這一點,並updated my code。如果你想保持獨特的染色體,你必須比較它們的內容(如其他人所提到的)。一種方法是計算它們之間的標準偏差。如果它低於某個閾值,則可以認爲它們相同。來自類染色體:
// compute the population standard deviation
public float StdDev(Chromosome other) {
float sum = 0.0f;
for(int i=0; i<alele.Length; i++) {
float diff = other.alele[i] - alele[i];
sum += diff*diff;
}
return (float)Math.Sqrt(sum);
}
我認爲Niching會給你你想要的。它比較人羣中的所有染色體以確定它們的相似性,併爲每個染色體分配一個「利基」值。然後使用稱爲顯式健身分享的技術來對屬於利基的染色體進行「處罰」。適應值除以每個生態位中的染色體數量。因此,如果您有三個小組(A,A,A),而不是該小生選擇的可能性的3倍,則將其視爲單個實體。
我比較了我的示例與顯式健身共享的開啓和關閉。最大STDDEV爲500,Niching爲OFF時,大約有18-20個生態位(基本上每100個人口中有5個重複項)。隨着Niching開啓,大約有85個壁龕。這就是人口中85%獨特的染色體。在我的測試輸出中,您可以看到diversity after 17000 generations。
這裏的小生境代碼:
// returns: total number of niches in this population
// max_stddev -- any two chromosomes with population stddev less than this max
// will be grouped together
int ComputeNiches(float max_stddev) {
List<int> niches = new List<int>();
// clear niches
foreach(var c in population) {
c.niche = -1;
}
// calculate niches
for(int i=0; i<population.Count; i++) {
var c = population[i];
if(c.niche != -1) continue; // niche already set
// compute the niche by finding the stddev between the two chromosomes
c.niche = niches.Count;
int count_in_niche = 1; // includes the curent Chromosome
for(int j=i+1; j<population.Count; j++) {
var d = population[j];
float stddev = c.StdDev(d);
if(stddev < max_stddev) {
d.niche = c.niche; // same niche
++count_in_niche;
}
}
niches.Add(count_in_niche);
}
// penalize Chromosomes by their niche size
foreach(var c in population) {
c.niche_scaled_fitness = c.scaled_fitness/niches[c.niche];
}
return niches.Count;
}
[編輯:安東的代碼後的分析和更新]
我知道這可能不是解決家庭作業問題的適當論壇,但因爲在做這件事之前我做了一些努力,而且我做了很多樂趣,所以我認爲這隻對Anton有幫助。
Genotip.cs,Kromosom.cs,KromoMain.cs
此代碼保持良好的多樣性,以及我能在一個運行獲得「原始適應」下調至47,這是你的情況的均方誤差。那非常接近!
正如我在評論中指出的那樣,我想嘗試在編程中幫助你,而不僅僅是幫助你做家庭作業。請閱讀這些工作分析。
正如我們預料的那樣,從一開始就沒有必要創造一個「更多元化」的人口。只需生成一些完全隨機的染色體。
你的突變和交叉是非常具有破壞性的,你只有其中的幾個。我添加了幾個新的運營商,似乎更好地解決了這個問題。
你扔掉了最好的解決方案。當我的代碼只運行錦標賽選擇時,會有一個Kromo比其他所有的都好99%。選擇錦標賽時,最有價值的東西很可能會被遺忘。我加了一點「精英主義」,爲下一代保留了這個價值的副本。
考慮面向對象技術。比較我寫給你的原始代碼的重寫。
請勿複製代碼。您有兩個不同類別的採樣參數。
保持您的代碼清潔。有幾個未使用的代碼部分。特別是在向SO提交問題時,儘量縮小範圍,刪除未使用的代碼並進行一些清理。
評論您的代碼!我已經評論重新工作。我知道這是塞爾維亞語,但即使是一些評論也會幫助別人瞭解你在做什麼以及你打算做什麼。
總的來說,不錯實施一些像錦標賽選擇了更復雜的事情
身高雙[]數組,而不是名單。開銷較少。此外,您的幾個List temp變量甚至不需要。你的結構
List temp = new List();對於(...){ temp.add(value); } 用於(在每個溫度值){ 總和+ =值 } 平均=總和/ temp.Count
可以很容易地被寫爲:
sum = 0
for(...) {
sum += value;
}
average = sum/count;
在幾個地方你忘了初始化一個循環變量,這可能很容易加到你的問題中。這樣的事情會引起嚴重的問題,並且這是在你的代碼以及其他一個或兩個地方
雙擬合= 0; (每個染色體){ //你應該初始化適合於這裏內部 LOOP (對於每個等位基因){ fit + = ...; } fit/= count; }
祝您好運!
問:我不明白。 .Net「Random()」究竟有什麼問題?只是默認種子(滴答)?問:這個鏈接是否有幫助:http://matthewlynch.net/dotnet/good-seed-for-random/ – paulsm4
這不是種子,問題是我必須做染色體,然後檢查它們的適應性。如果它與列表中已有的(健身)過於相似,則重複創建新染色體的過程,直到它的健身ID足夠不同。但是這需要很長時間,所以我的問題是有沒有更快的方式讓種子多樣化? –
問:這是否給你更好的東西:'隨機隨機=新的隨機(Guid.NewGuid()的GetHashCode());' – paulsm4