|
遺傳演算(GA)程式設計 陳慶瀚 E-mail : pierre@isu.edu.tw |
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
1. 原理 1.1 天擇(Selection) 1.2 交配(Crossover) 1.3 突變(Mutation) 2. 演算法
3. C++實作
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
原理 遺傳演算是一種隨機最佳化(stochastic optimization)的技術,其計算原理仿傚達爾文進化論的「物競天擇、適者生存」的概念來搜尋問題的最佳解。當待解的問題被視為一個函數,最佳解即可視為函數的最大值,而遺傳演算的目的即在於求出此一函數的最大值。
近年來,遺傳演算成為一股極受重視的技術潮流,我們歸納幾個重要的理由: ─ 相對於其他最佳化技術─如最陡坡降法、模擬退火等方法,它可以應用在更多、更普遍的問題領域。當待解問題蘊含著非凸集(non-convex)、非連續(non-continuous)以及不可微分(non-differentiable)的特性時,甚至於待解問題本身無法以闡明(explicit)形式表達而僅能以程式來描述時,遺傳演算仍然具有解題的能力。 ─ 它具有本質上平行處理的機能(functionality)。在集體搜尋(population-based search)的策略下,遺傳演算平行地、多方向的搜尋問題領域的全域最佳解(global optimum),得以避開局部性最佳解。這種平行的機制有利於實現快速的大量平行處理器或者是VLSI的硬體架構。 ─ 它具有生物學或人類學的類比性。也就是說,遺傳演算是一種仿自然的計算(simulated natural computation),如同類神經網路一般,它模仿生物或自然界解決問題的方式。在普遍的生物系統中,到處可以觀察到自我組織、自我修復、自我改善的現象,對於這些智慧型機制的運作原理,我們的理解相當有限。但是自然界已經展示的這種機制的高度效能。遺傳演算應用演化理論來求解實境問題(real world problem)乃是朝向結合人造智慧與自然智慧的新趨勢之一。
1. 基本概念
考慮如下問題:若有一個6 位元的二元字串(binary string),每個位元可以填入0或1。現在定義函數 f(s) = 1在二元字串s的個數 當字串s = 000000, 我們得到f(000000) = 0, 而對於 s = 010010, f(010010) = 2。我們將使用遺傳演算來求解f(s)的最大值(亦即fmax(s*) = f(111111) = 6),藉由此一簡單的最佳化問題來觀察遺傳演算的運算過程。 首先將問題形式化,也就是將待解問題進行遺傳編碼。設有n個個體的族群P,n是一個固定的整數。族群的所有個體必須先以隨機的方式初值化,接著以f(s)分別評估其品質。在本例中,假設個體數目n = 5,以隨機的方式產生5個長度為6位元的二元字串後,分別得到評估函數值如下:
P(1)表示第一代族群,我們將用它來產生品質更為優良的第二代族群P(2)。在遺傳演算中,任一代族群P(t+1)總是從前一代族群P(t)演化而來,此一原則得以使得新一代的可能的解總是立足在前一代業已存在的解,同時我們應用三種遺傳機制來探索新的、可能更佳的解:天擇(selection)、交配(crossover)和突變(mutation),因此決定兩代之間的遺傳可以表示成 P(t) ─>天擇─>Ps(t)─>交配─>Pc(t)─>突變─>P(t+1) 1.1 天擇(Selection)
Ps(t)是從P(t)的個體中隨機地選出n個作為新的個體,每個個體被選中的機率並不相同,而是與其評估函數值成正比:
計算第一代所有個體被選中的機率:
輪盤(roulette wheel)方法被普遍應用在隨機選取個體。如圖一,每一個個體在輪盤上佔有一個正比於pselect的區間,一旦轉動輪盤,則目標落在任一個體的機率將與其所佔有的區間大小成正比。 -
依此概念,轉動輪盤5次,可以得到5個經由天擇的個體。這5個個體形成Ps(1)族群:
注意到這個天擇程序已經為我們複製較佳的個體s = 011011而淘汰了較差的個體s = 001010。
1.2 交配(Crossover)
交配在於從Ps(1)族群中任意兩個個體交換其內容或重新組合,以形成新的個體。每一個個體都有pcross的機率被選出來配對。每一對(兩個)個體以隨機的方式決定一個位置將個體切開成兩部分,並將其中一部分與另一個體對換,如此形成兩個新的個體,例如:
| 表示分割位置。新的個體產生後將取代它的父代個體,所形成的Pc(1)族群為:
"?"表示尚未進行評估的個體。
1.3 突變(Mutation)
根據一個固定的突變機率 pmut,我們對族群Pc(1)的所有位元進行隨機式選取,被選取的位元將逆轉其值(0變1,1變0),pmut的值一般在0.001到0.01之間。假使 pmut = 0.05,此意味平均每100個位元就可能有5個位元接受突變。下表顯示一個突變後的結果:
加上雙底線的1或0表示接受突變的位元。經過突變的運算後,我們最後得到了第二代族群P(2)。評估此一族群的品質:
無論是最佳個體的評估函數值或是族群的評估函數值都顯然較第一代族群為佳。
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2. 標準演算法和C++實作
2.1 標準的遺傳演算(或稱簡單遺傳演算─SGA)
步驟1:問題的編碼(Encoding) 將問題表示成二元字串的形式。上述範例欲求6位元的字串包含1的最大數目,這個簡單問題使我們可以使用6位元的二元字串作為族群的每一個個體的直接編碼。但對於一個參數最佳化的問題,每一個實數參數的二元編碼長度則視所須精確度來決定。對於變數x值域在 [a, b],如果需要小數點5位的精確度,意味x必須有(b - a)´105個可解析範圍,因此所須要的位元數目m可以由下式求出:
2m-1 < (b - a)´105 £ 2m-1
至於將二元字串解碼成實數公式如下:
x = a + decimal(binary_string)´
步驟2:族群的初始化(Initialization) a. 設定族群要進行演化的迭代次數。 b. 決定族群的個體的數目N,一般介於十到數百之間,數目愈大則找到全域最佳值的機會愈大,但相對的其收斂速度愈慢。 c. 設定交配機率pcross和突變機率pmut。 d. 隨機產生N個二元字串的個體vi, i = 1, 2, ..., N。
步驟3:個體的評估(Evaluation) a. 使用解碼公式把每一個體由二元字串binary_string轉成實數xi,i = 1, 2, ..., N。 b. 將xi將代入評估函數求f(xi)。 c. 轉換評估函數值為個體的品質指標(fitness)。對於最大化的問題,品質指標可簡單的令其等於評估函數值,亦即fitness(vi) = f(xi)。
步驟4:天擇(Selection) 使用輪盤(roulette wheel)方法: a. 先求出整體品質指標:
再針對每一個個體vi,計算其被選擇的機率:
最後依據個體的排序,計算累加機率qi:
接著對於每個個體,執行步驟b, c。 b. 產生一個範圍在 [0, 1] 的實數亂數r。 c. 如果r £ q1,則選擇第一個個體;否則選擇第k個個體使得 qk-1< r £qk
步驟5:交配(crossover) 根據交配機率pcross,預期將有pcross´100 %的個體進行交配。 a. 對於每個個體vi,產生一個範圍在 [0, 1] 的實數亂數ri,如果ri
£ pcross,選擇vi作為一個父代個體。所有被選出的父代個體 b. 對每一對交配的父代個體vi和vk,使用單點交配(one-point-cut)方法,隨機的選擇一個位置pos,使兩個個體互相交換pos以右的所有位元,因為形成兩個新的個體v'i和v'k。
步驟6:突變(Mutation) 在整個族群中,我們預期有pmut´100 %的位元要接受突變,也就是pmut´m´N個位元,m是個體的位元數,N是族群的個體數。每一個位元都有同樣的機率接受突變,所以執行以下程序: a. 隨機產生m´N個範圍在 [0, 1] 的實數亂數rj(j = 1, 2, ..., m´N), 如果rj < pmut,記錄其位元位置pos = j,表示該位置的位元值要接受突變。 b. 從所有突變的位置pos求出所屬的個體vi和處於該個體的位置bit_no: i = quotient(pos / m); bit_no = remainder (pos / m); 再反轉其位元值。
步驟7:判斷結束條件。 若已達到迭代次數G,就結束演算,否則回到步驟3,繼續下一代的演算。
|
最精簡的GA程式碼範例
1 |
#include <stdlib.h> |
2 |
#include <time.h> |
3 |
#include <math.h> |
4 |
#include <fstream.h> |
5 |
#include "randgen.h" |
6 |
#include "array.h" |
7 |
|
8 |
// |
9 |
// BitArray object class for Genetic Algorithm |
10 |
// |
11 |
|
12 |
class BitArray: public Array1D<bool> |
13 |
{ |
14 |
public: |
15 |
void Initialize(int n) |
16 |
{ |
17 |
Array1D<bool>::Initialize(n); |
18 |
for(int i=0;i<nb;i++)m[i]=0; |
19 |
} |
20 |
void Randomize(unsigned long seed); |
21 |
void SetBit(int ndx, bool bit){m[ndx]=bit;} |
22 |
void SetBits(ifstream &in){for(int i=0;i<nb;i++)in>>m[i];} |
23 |
bool GetBit(int ndx){return m[ndx];} |
24 |
long ToDecimal(); |
25 |
int HammingDistance(BitArray &by); |
26 |
void Print(ofstream& out){for(int i=0;i<nb;i++)out<<m[i];out<<endl;} |
27 |
void Print(){for(int i=0;i<nb;i++)cout<<m[i];cout<<endl;} |
28 |
bool operator==(BitArray &by); |
29 |
}; |
30 |
|
31 |
void BitArray::Randomize(unsigned long seed) |
32 |
{ |
33 |
RanBit32 rbg(seed); |
34 |
for(int i = 0; i<nb; i++) m[i] = rbg.Next(); |
35 |
} |
36 |
|
37 |
long BitArray::ToDecimal() |
38 |
{ |
39 |
long value = 0; |
40 |
for(int i = 0; i<nb; i++) |
41 |
{ |
42 |
if(m[i])value += m[i]<<i; |
43 |
} |
44 |
return value; |
45 |
} |
46 |
|
47 |
int BitArray::HammingDistance(BitArray &by) |
48 |
{ |
49 |
int dist=0; |
50 |
for(int i=0;i<nb;i++)if(by.m[i]!=m[i])dist++; |
51 |
return dist; |
52 |
} |
53 |
|
54 |
bool BitArray::operator==(BitArray &by) |
55 |
{ |
56 |
if(by.nb!=nb)return false; |
57 |
bool flag=true; |
58 |
for(int i=0;i<nb;i++)if(by.m[i]!=m[i]) |
59 |
{ |
60 |
flag = false; |
61 |
break; |
62 |
} |
63 |
return flag; |
64 |
} |
65 |
|
66 |
|
67 |
// |
68 |
// object class for Genetic Algorithm : Evaluator |
69 |
// |
70 |
|
71 |
class Evaluator |
72 |
{ |
73 |
protected: |
74 |
int nb_variables; |
75 |
i1D nb_bits; |
76 |
Array1D<BitArray> BinaryVariable; |
77 |
public: |
78 |
int GetTotalBits() |
79 |
{ |
80 |
int total_bits=0; |
81 |
for(int i=0;i<nb_variables;i++)total_bits += nb_bits[i]; |
82 |
return total_bits; |
83 |
} |
84 |
int GetNbVariable(){return nb_variables;} |
85 |
void Decompose(BitArray &bitarray); |
86 |
virtual double Evaluate(BitArray &bitarray, |
87 |
double (*userfunc)(f1D ¶))=0; |
88 |
virtual f1D& Decoding(BitArray &individ)=0; |
89 |
}; |
90 |
|
91 |
void Evaluator::Decompose(BitArray &bitarray) |
92 |
{ |
93 |
int count=0; |
94 |
for(int i=0;i<nb_variables;i++) |
95 |
{ |
96 |
for(int j=0;j<nb_bits.m[nb_variables-1-i];j++) |
97 |
{ |
98 |
BinaryVariable[nb_variables-1-i].m[j]=bitarray.m[count]; |
99 |
count++; |
100 |
} |
101 |
} |
102 |
} |
103 |
|
104 |
class NumericEvaluator : public Evaluator |
105 |
{ |
106 |
protected: |
107 |
int total_bits; |
108 |
f1D min; |
109 |
f1D max; |
110 |
public: |
111 |
f1D RealVariable; |
112 |
void Initialize(ifstream &in); |
113 |
f1D& Decoding(BitArray &individ); |
114 |
double Evaluate(BitArray &bitarray, |
115 |
double (*userfunc)(f1D ¶)); |
116 |
}; |
117 |
|
118 |
void NumericEvaluator::Initialize(ifstream &in) |
119 |
{ |
120 |
int required_precision; |
121 |
in>>nb_variables>>required_precision; |
122 |
int i,j, morder = required_precision-1; |
123 |
max.Initialize(nb_variables); |
124 |
min.Initialize(nb_variables); |
125 |
nb_bits.Initialize(nb_variables); |
126 |
BinaryVariable.Initialize(nb_variables); |
127 |
RealVariable.Initialize(nb_variables); |
128 |
// define by case |
129 |
for(i=0;i<nb_variables;i++) |
130 |
{in>>min[i]>>max[i];} |
131 |
double *t=new double[nb_variables]; |
132 |
for(i=0;i<nb_variables;i++) |
133 |
t[i] = double(max[i] - min[i])*pow10(morder); |
134 |
for(i=0;i<nb_variables;i++)nb_bits[i]=0; |
135 |
for(i=0;i<nb_variables;i++) |
136 |
{ |
137 |
for(j=1;j<32;j++)if((t[i]>pow(2,j-1))&&(t[i]<=pow(2,j))) |
138 |
{nb_bits[i]=j; break;} |
139 |
} |
140 |
delete t; |
141 |
total_bits=0; |
142 |
for(i=0;i<nb_variables;i++)total_bits+=nb_bits[i]; |
143 |
for(i=0;i<nb_variables;i++) |
144 |
BinaryVariable[i].Initialize(nb_bits[i]); |
145 |
} |
146 |
|
147 |
double NumericEvaluator::Evaluate(BitArray &bitarray, |
148 |
double (*userfunc)(f1D ¶)) |
149 |
{ |
150 |
if(bitarray.nb!=total_bits)return double(0.0); |
151 |
Decoding(bitarray); |
152 |
return userfunc(RealVariable); |
153 |
} |
154 |
|
155 |
f1D& NumericEvaluator::Decoding(BitArray &individ) |
156 |
{ |
157 |
Decompose(individ); |
158 |
for(int i=0;i<nb_variables;i++) |
159 |
{ |
160 |
RealVariable[i]=BinaryVariable[i].ToDecimal(); |
161 |
RealVariable[i]=min.m[i]+RealVariable[i]*(max.m[i]-min.m[i]) |
162 |
/(pow(2,nb_bits.m[i])-1.0); |
163 |
} |
164 |
return RealVariable; |
165 |
} |
166 |
|
167 |
// |
168 |
// object class for Genetic Algorithm : population |
169 |
// |
170 |
|
171 |
class Population |
172 |
{ |
173 |
protected: |
174 |
int generation; |
175 |
int nb_individ; |
176 |
int nb_bit; |
177 |
int optimal_individ_ndx; |
178 |
float CrossoverP; |
179 |
float MutationP; |
180 |
float ReserveP; |
181 |
float total_fitness; |
182 |
Ran32 GlbRan; |
183 |
Array1D<BitArray> individ, individtmp; |
184 |
f1D Fitness, AccFitness; |
185 |
f1D ProbaTable; |
186 |
Array1D<bool> Survivor; |
187 |
i1D ndx; |
188 |
int NSurvivor; |
189 |
BitArray CrossoverMask; |
190 |
void IndividCrossOver(BitArray &b1, BitArray &b2, int pos); |
191 |
void ConvertFitnessByOrder(); |
192 |
void FindNBestIndivids(f1D &fit, int N); |
193 |
public: |
194 |
void Initialize(int nindivid, int nbit); |
195 |
void Recording(Evaluator &eva, ofstream &out); |
196 |
|
197 |
// Genetic mecanism |
198 |
f1D& Evaluate(Evaluator &eva, double (*userfunc)(f1D ¶)); |
199 |
void Evolution(); |
200 |
void CrossOverOnePointCut(); // one-point-cut crossover |
201 |
void CrossOverByMask(unsigned long seed); // mask crossover |
202 |
void Mutation(); |
203 |
void Selection(); |
204 |
|
205 |
// User interface |
206 |
void SetCrossOverProbability(float p){CrossoverP=p;} |
207 |
void SetMutationProbability(float p){MutationP=p;} |
208 |
int Get_Nb_Individ(){return nb_individ;} |
209 |
int Get_Nb_Bit(){return nb_bit;} |
210 |
BitArray& GetIndivid(int index); |
211 |
BitArray& GetOptimalIndivid(); |
212 |
double GetOptimalFitness(); |
213 |
double GetFitness(int index){return Fitness[index];} |
214 |
double GetTotalFitness(){return total_fitness;} |
215 |
void Print(ofstream& out); |
216 |
int GetOptimalIndividIndex(){return optimal_individ_ndx;} |
217 |
}; |
218 |
|
219 |
void Population::Initialize(int nindivid, int nbit) |
220 |
{ |
221 |
nb_individ=nindivid; |
222 |
nb_bit=nbit; |
223 |
// default values for CrossoverP, MutationP |
224 |
CrossoverP = 0.6; |
225 |
MutationP = 0.005; |
226 |
ReserveP = 0.1; |
227 |
unsigned long seed = (unsigned long)time(0); |
228 |
GlbRan.Reset(seed); |
229 |
for(int i=0;i<GlbRan.Next(0,10000);i++)seed=GlbRan.Next(); |
230 |
GlbRan.Reset(seed); |
231 |
individ.Initialize(nb_individ); |
232 |
individtmp.Initialize(nb_individ*ReserveP); |
233 |
Fitness.Initialize(nb_individ); |
234 |
AccFitness.Initialize(nb_individ); |
235 |
ProbaTable.Initialize(nb_individ); |
236 |
Survivor.Initialize(nb_individ); |
237 |
ndx.Initialize(nb_individ); |
238 |
for(int i=0;i<individ.nb;i++) |
239 |
{ |
240 |
individ.m[i].Initialize(nb_bit); |
241 |
individtmp.m[i].Initialize(nb_bit); |
242 |
individ.m[i].Randomize(GlbRan.Next()); |
243 |
} |
244 |
CrossoverMask.Initialize(nb_bit); |
245 |
CrossoverMask.Randomize(GlbRan.Next()); |
246 |
generation=0; |
247 |
} |
248 |
|
249 |
void Population::Recording(Evaluator &evaluator, ofstream &out) |
250 |
{ |
251 |
int i,j; |
252 |
f1D t; |
253 |
out<<endl<<"generation : "<<generation<<endl; |
254 |
for(i=0;i<nb_individ;i++) |
255 |
{ |
256 |
t = evaluator.Decoding(individ[i]); |
257 |
out<<i<<"\tf("; |
258 |
for(j=0;j<evaluator.GetNbVariable();j++)out<<t[j]<<", ";out<<") = "; |
259 |
out<<Fitness[i]<<endl; |
260 |
} |
261 |
out<<"average fitness : "<<total_fitness/float(nb_individ)<<endl; |
262 |
out<<"optimal individual is : "<<optimal_individ_ndx<<endl; |
263 |
t = evaluator.Decoding(individ.m[optimal_individ_ndx]); |
264 |
out<<"optimal solution : "<<"\tf("; |
265 |
for(j=0;j<evaluator.GetNbVariable();j++)out<<t[j]<<", ";out<<") = "; |
266 |
out<<Fitness[optimal_individ_ndx];out<<endl; |
267 |
} |
268 |
|
269 |
void Population::IndividCrossOver(BitArray &b1, BitArray &b2, int pos) |
270 |
{ |
271 |
bool b; |
272 |
for(int i=0;i<pos;i++) |
273 |
{ |
274 |
b=b1.m[i]; |
275 |
b1.m[i]=b2.m[i]; |
276 |
b2.m[i]=b; |
277 |
} |
278 |
} |
279 |
|
280 |
void Population::ConvertFitnessByOrder() |
281 |
{ |
282 |
int i,j; |
283 |
for(i=0;i<nb_individ;i++) |
284 |
{ |
285 |
AccFitness.m[i]=0; |
286 |
for(j=0;j<nb_individ;j++)if(Fitness.m[i]>Fitness.m[j])AccFitness.m[i]++; |
287 |
} |
288 |
for(i=0;i<nb_individ;i++)Fitness.m[i]=AccFitness.m[i]; |
289 |
} |
290 |
|
291 |
void Population::Selection() |
292 |
{ |
293 |
int i,j; |
294 |
float sum=0.0; |
295 |
ConvertFitnessByOrder(); |
296 |
for(i=0;i<nb_individ;i++)sum+=Fitness.m[i]; |
297 |
for(i=0;i<nb_individ;i++)AccFitness.m[i]=Fitness.m[i]/sum; |
298 |
for(i=1;i<nb_individ;i++)AccFitness.m[i]+=AccFitness.m[i-1]; |
299 |
fRan32 rg(GlbRan.Next()); |
300 |
for(i=0;i<nb_individ;i++)ProbaTable.m[i]=rg.Next(0.0, 1.0); |
301 |
NSurvivor=0; |
302 |
for(i=0;i<nb_individ;i++)if(ProbaTable.m[i]<CrossoverP) |
303 |
{ |
304 |
Survivor.m[i] = true; |
305 |
ndx.m[NSurvivor] = i; |
306 |
NSurvivor++; |
307 |
} |
308 |
NSurvivor = (NSurvivor/2)*2; |
309 |
} |
310 |
|
311 |
void Population::CrossOverOnePointCut() |
312 |
{ |
313 |
int i,n,a,b; |
314 |
Ran32 rg(GlbRan.Next()); |
315 |
for(i=0;i<NSurvivor/2;i++) |
316 |
{ |
317 |
a = rg.Next(0,NSurvivor); |
318 |
b = rg.Next(0,NSurvivor); |
319 |
n=rg.Next(0,nb_bit); |
320 |
IndividCrossOver(individ[ndx[a]],individ[ndx[b]],n); |
321 |
} |
322 |
} |
323 |
|
324 |
void Population::CrossOverByMask(unsigned long seed) |
325 |
{ |
326 |
int i,j,a,b; |
327 |
RanBit32 rbg(seed); |
328 |
for(i = 0; i< CrossoverMask.nb; i++) CrossoverMask.m[i] = rbg.Next(); |
329 |
Ran32 rg(GlbRan.Next()); |
330 |
bool t; |
331 |
for(i=0;i<NSurvivor/2;i++) |
332 |
{ |
333 |
a = rg.Next(0,NSurvivor); |
334 |
b = rg.Next(0,NSurvivor); |
335 |
for(j=0;j<CrossoverMask.nb;j++)if(CrossoverMask.m[j]==1) |
336 |
{ |
337 |
t = individ[ndx[a]].m[j]; |
338 |
individ[ndx[a]].m[j] = individ[ndx[b]].m[j]; |
339 |
individ[ndx[b]].m[j] = t; |
340 |
} |
341 |
} |
342 |
} |
343 |
|
344 |
void Population::Mutation() |
345 |
{ |
346 |
long length = nb_individ*nb_bit; |
347 |
int x, xd, xm; |
348 |
int nb_mt = int(MutationP*float(length)+0.5); |
349 |
for(int i=0;i<nb_mt;i++) |
350 |
{ |
351 |
x = GlbRan.Next(0, length-1); |
352 |
xd = x/nb_bit; |
353 |
xm = x%nb_bit; |
354 |
if(individ[xd].m[xm]==0)individ[xd].m[xm]=1; |
355 |
else individ[xd].m[xm]=0; |
356 |
} |
357 |
} |
358 |
|
359 |
f1D& Population::Evaluate(Evaluator &evaluator, double (*userfunc)(f1D ¶)) |
360 |
{ |
361 |
int i; |
362 |
for(i=0;i<nb_individ;i++) |
363 |
Fitness.m[i]=evaluator.Evaluate(individ.m[i], userfunc); |
364 |
float max=-1e30; |
365 |
for(i=0;i<nb_individ;i++)if(Fitness.m[i]>max) |
366 |
{ |
367 |
max=Fitness.m[i]; |
368 |
optimal_individ_ndx=i; |
369 |
} |
370 |
total_fitness=0; |
371 |
for(i=0;i<nb_individ;i++)total_fitness += Fitness.m[i]; |
372 |
return Fitness; |
373 |
} |
374 |
|
375 |
void Population::FindNBestIndivids(f1D &fit, int N) |
376 |
{ |
377 |
|
378 |
} |
379 |
|
380 |
void Population::Evolution() |
381 |
{ |
382 |
Selection(); |
383 |
// CrossOverByMask(GlbRan.Next()); |
384 |
CrossOverOnePointCut(); |
385 |
Mutation(); |
386 |
generation++; |
387 |
} |
388 |
|
389 |
BitArray& Population::GetIndivid(int ndx) |
390 |
{ |
391 |
return individ[ndx]; |
392 |
} |
393 |
|
394 |
BitArray& Population::GetOptimalIndivid() |
395 |
{ |
396 |
return individ[optimal_individ_ndx]; |
397 |
} |
398 |
|
399 |
double Population::GetOptimalFitness() |
400 |
{ |
401 |
return Fitness[optimal_individ_ndx]; |
402 |
} |
403 |
|
404 |
void Population::Print(ofstream& out) |
405 |
{ |
406 |
for(int i=0;i<nb_individ;i++)individ[i].Print(out); |
407 |
} |
408 |
|
409 |
|
410 |
double user_evaluation_function(f1D &v) |
411 |
{ |
412 |
return -(v[0]*v[0] + v[1]*v[1]); |
413 |
} |
|
|
|
|
|
|
414 |
// Testing main program |
415 |
main() |
416 |
{ |
417 |
char key; |
418 |
char filename[128]; |
419 |
cout<<"Input filename of parameter description data : "; |
420 |
cin>>filename; |
421 |
ifstream in(filename); |
422 |
ofstream out("ga.dat"); |
423 |
if(!in){cout<<"Cannot open file! Any key to terminate...";cin>>key;exit(1);} |
424 |
NumericEvaluator evaluator; |
425 |
evaluator.Initialize(in); |
426 |
Population population; |
427 |
SetCrossOverProbability(0.6); |
428 |
SetMutationProbability(0.02); |
429 |
int generation, nb_individ; |
430 |
cout<<"\nEnter number of individuals in the population : ";cin>>nb_individ; |
431 |
cout<<"\nEnter number of iteration for evolution : ";cin>>generation; |
432 |
population.Initialize(nb_individ, evaluator.GetTotalBits()); |
433 |
population.Evaluate(evaluator, user_evaluation_function); |
434 |
for(int i=0;i<generation;i++) |
435 |
{ |
436 |
population.Evolution(); |
437 |
population.Evaluate(evaluator,user_evaluation_function); |
438 |
population.Recording(evaluator, out); |
439 |
cout<<i<<endl; |
440 |
} |
441 |
cout<<endl<<"The evolution process is saved in ga.dat"<<endl; |
442 |
cout<<"any key to terminate..."; |
443 |
cin>>key; |
444 |
} |