HIỆN THỰC GIẢI THUẬT GEN
II-SINH SẢN, GHÉP CHÉO VÀ ĐỘT BIẾN:
Trước khi tìm hiểu từng thủ tục kể trên chúng ta cần nhớ sợi dây chung xuyên suốt 3 thao tác sinh sản ,ghép chéo và đột biến là các phép chọn ngẫu nhiên .Trong các đoạn chương trình dưới đây , chúng ta giả thiết đã có 3 thủ tục ngẫu nhiên :
Random : trả về số thực nhẫu nhiên , nằm giữa 0 và 1 .
Flip: trả về giá trị boolean là true cùng với xác suất đặc tả ( giá trị ngẫu nhiên bernoully)
Rnd: trả về giá trị nguyên nằm giữa các giới hạn dưới và trên đã chỉ ra (biến ngẫu nhiên đồng nhất trên tập con các số nguyên kề nhau ).
Trong giải thuật gen đơn giản , việc sinh sản được hiện thực trong thủ tục select , như việc tìm kiếm tuyến tính thông qua bánh xe roulete với các khe hở trọng số tỉ lệ với giá trị thích nghi của chuẩn . Trong đoạn chương trình trên hình 3.4 , chúng ta thấy select trả về giá trị chỉ số dân số tương ứng với cá thể đã chọn . Để làm điều này , tổng riêng phần của các giá trị thích nghi được cộng dồn vào biến thực partsum . Biến thực rand chứa vị trí nơi bánh xe chiếm sau khi quay , theo tính toán sau :
Rand: = randdom* sumfitness
Ơ đây , tổng các độ thích nghi của dân số (được tính trong thủ tục statistics) được nhân với số ngẫu nhiên giả lặp tạo bởi thủ tục random . Cuối cùng , cấu trúc repeat- untill tìm kiếm thông qua bánh xe roulet có trọng số , cho đến khi tổng riêng phần lớn hơn hoặc bằng điểm dừng rand .Hàm trả về với giá trị chỉ số dân số hiện tại j được gán cho select .
Hình 3.4 hàm select hiện thực phép chọn của bánh xe roulet . function select(popize : integer; sumfitness :real;
var pop: integer) :integer;
{một cá thể qua phép chọn củ bánh xe roulette} var rand, partsum :real;{điểm ngẫu niên trên bánh xe roulette}
j :integer;{chỉ số dân số} begin
partsum := 0.0; j:= 0; {gán 0 cho bộ đếm và bộ tích luỹ} rand := random*sumfitness;
{tínt toán điểm trên bánh xe roulette, sử dụng số ngẫu nhiên[0,1]} repeat
j := j+1;
partsum := partsum + pop[j].fitness; until (partsum >= rand) or (j =popsize);
{trả về số cá thể} select := j;
Đây có lẽ là cách đơn giản nhất để hiện thực việc chọn lựa . Đoạn chương trình select cho chúng ta cách chọn trực tiếp con cháu cho thế hệ kế . Bước kế tiếp là ghép chéo , thực hiện bằng thủ tục crossover trên hình 3.5 :
Hình 3.5: thủ tục crossover hiện thực sự ghép chéo đơn giản Procedure crossover(var parent1,parent2,child1,child2 : chromosome; var lchrom,ncross,pmutation,jcross :integer;
var pcross,pmutation:real);
{ghép chéo 2 chuỗi bố mẹ đặt vào 2chuỗi con} var j :integer;
begin
if flip(pcross) then begin {ghép chéo với (pcross)}
jcross := rnd(1,lchrom-1); {ghép giữa 1 và lchrom –1} ncross := ncross + 1; {tăng bộ đếm lần ghép chéo} end else
jcross := lchrom;
{ trao đổi lần 1, giữa 1 với 1 và 2 với 2} for j := 1 to jcross do begin
child1[j] := mutation(parent1[j],pmutation,nmutation); child2[j] := mutation(parent2[j],pmutation,nmutation); end;
{ trao đổi lần 1, giữa 1 với 2 và 2 với 1} if jcross < > lchrom then
{bỏ qua nếu mặt ghép là lchrom –không ghép} for j := 1 to jcross do begin
child1[j] := mutation(parent2[j],pmutation,nmutation); child2[j] := mutation(parent1[j],pmutation,nmutation); end;
end;
Thủ tục crossover nhận 2 chuỗi bố mẹ là parent 1 và parent 2 và sinh ra 2 chuỗi con child1 và child2. Các xác suất ghép chéo và đột biến pcross và pmutation được chuyển cho crossover , cùng với chiều dài chuỗi lchrom , bộ đếm tích lũy số lần đột biến nmutation .
Trong crossover , các thao tác phản ảnh các mô tả của chúng ta trong chương 1 . Đầu thủ tục , chúng ta xác định khi nào sẽ thực hiện ghép chéo trên cặp nhiễm sắc thể bố mẹ hiện tại . Chúng ta búng đồng tiền , để đạt được mặt ngửa với xác suất
pcross .Mô phỏng việc búng đồng tiền qua thủ tục boolean là flip , trong đó flip gọi thủ tục random giả lập số ngẫu nhiên .Nếu cần ghép chéo , vị trí ghép chéo được chọn giữa 1 và vị trí ghép cuối cùng .Chỗ ghép chéo được chọn qua hàm rnd , hàm này trả về một số nguyên ngẫu nhiên nằm giữa các giới hạn dưới và trên (giữa 1 và lchrom- 1 ) .Nếu không có sự ghép nào được chọn , chỗ ghép chéo được lấy là lchrom (chuỗi đầy đủ dài 1) , qua đó sự đột biến theo từng bit được tiến hành cho dù thiếu mặt sự ghép chéo .Cuối cùng , sự trao đổi các phần trong ghép chéo được thực hiện qua 2 cấu trúc for-do ở cuối đoạn chương trình .Đoạn for-do đảm nhận chuyển từng bit nằm giữa parent1 và child1 , và giữa parent2 và child2 .Đoạn for –do thứ 2 đảm nhận chuyển và trao đổi từng phần chất liệu giữa parent1 và child2 , và giữa parent2 và
child1 .Trong trường hợp này , đột biến theo từng bit được tiến hành bởi hàm boolean mutation .
Đột biến tại 1 điểm được thực hiện bằng thủ tục mutation trên hình 3.6. Hình 3.6: Thủ tục Mutation thực hiện ghép chéo điểm, bit đơn:
function mutation(alleleval :allele; pmutation :real; var nmutation :integer) :allele;
var mutate :boolean; Begin
mutate := flip(pmutation); {búng đồng tiền} if mutate begin
nmutation := nmutation + 1;
mutation := not alleleval; {đổi giá trị bit} end else
mutation := alleleval; {không đổi} end;
Thủ tục này dùng hàm flip (tung đồng tiền 2 mặt ) để xác định khi nào thay đổi từ true sang false và ngược lại .Thủ tục flip chỉ đưa ra tỉ lệ phần trăm mặt ngửa
pmutation theo thời gian , như kết quả bộ tạo số tự nhiên random nằm bên trong bản thân thủ tục flip .Hàm này cũng giữ các mốc trên số các đột biến bằng cách tăng biến pmutation .Như vậy , với sự sinh sản có nhiều cách để cải thiện biến dị đơn. Ví dụ , có thể tránh việc sinh ra quá nhiều số ngẫu nhiên nếu chúng ta quyết định khi nào thế hệ kế phải có mặt hơn là gọi hàm flip mỗi lần .
III-GIAI ĐOẠN SINH SẢN VÀ GHÉP CHÉO:
Thủ tục tạo thế hệ mới từ thế hệ cũ , bắt đầu với chỉ số ban đầu j = 1 và tiếp tục cho tới khi vượt quá kích thước dân số popsize, ta chọn 2 cặp mate1 và mate2 bằng cách gọi hàm select . Việc lai ghép và đôy biến chuỗi nhờ thủ tục crossover , giải mã cặp chromosomes , tính các giá trị hàm mục tiêu và tăng dân số lên 2 đơn vị.
Hình 3.7 : Thủ tục generation tạo thế hệ mới từ thế hệ cũ. procedure generation;
{tạo thế hệ mới thông qua chọn lựa ghép chéo và đột biến} var j,mate1,mate2,jcross :integer;
Begin j := 1; repeat
{chọn đột biến và ghép chéo cho đến khi newpop được lấp đâỳ} mate1:= select(popsize,sumfitness,olpop); {chọn cặp ghép đôi} mate2:= select(popsize,sumfitness,olpop);
{ghép chéo và đột biến –đột biến bên trong quá trình ghép chéo} crossover(oldpop[mate1].chrom, oldpop[mate2].chrom,
newpop[j].chrom,newpop[j+1].chrom,lchrom,ncross, nmutation,jcross,pcross,pmutation);
with newpop[j] do begin x := decode(chrom,lchrom); fitness := objfunc(x); parent1 := mate1; parent2 := mate2; xsite := jcross; end;
with newpop[j+1] do begin
x := decode(chrom,lchrom); fitness := objfunc(x); parent1 := mate1; parent2 := mate2; xsite := jcross; end; {tăng chỉ số dân số} j := j + 2; until j > popsize; end;
Với bài toá bất kỳ chúng ta phải tạo thủ tục giải mã các chuỗi, để tạo thông số hoặc bộ thông số phù hợp với bài toán . chúng ta cũng tạo thủ tục nhận thông số hay bộ các thông số đã cho. Các thủ tục này được đặt tên là decode và objfunc. với các bài toán phức tạp ,chúng ta cần các thủ tục giải mã khác nhau ,các thủ tục tính hàm thích nghi khác nhau .Để thống nhất với phần dã trình bày,chúng ta tiếp tục dùng cách mã hoá số nguyên nhị phân không dấu, và dùng hàm luỹ thừa đơn giản biểu diễn hàm thích nghi :f(x) = x10 .
Sau đây chúng ta xây dựng tủ tục decode. Trong thủ tục này, chromosome đơn được giải mã bắt đầu từ bit thấp nhất và map từ phả sang trái bằng cách trích lũy vào lũy thừa cơ số 2 hiện tại ,được cất vào biến poweroftwo .Khi bit tương ứng được thiết lập .giá trị tích lũy này được cất vào biến accum ,cuối cùng được trả về cho hàm decode.
Hình 3.8 : thủ tục decode giãi mã chuỗi nhị phân là số nguyên khop6ng dấu. function decode(chrom :chromosome; lbits :integer) :real;
{giải mã chuỗi thành số nguyên không dấu} var j : integer;
accum, powerof2 : real; Begin
accum := 0.0powerof2 :=1; for j:= 1 to lbits do begin
if chrom[j] then accum := accum + powerof2; powerof2 := powerof2 * 2;
end;
decode := accum; end;
Hàm mục tiêu ta dùng ở đây là hàm lũy thừa đơn giản :f(x) = (x/coeff)10
.Giá trị coeff được chọn để chuẩn hóa thông số x khi chuỗi bit có chiều dài lchrom = 30 được chọn : coeff = 230 –1 = 1073741823.0 Từ đó giá trị x được chuẩn hóa , giá trị tối đa của hàm là f(x) = 1.0 ,khi x = 230 –1 cho trường hợp lchrom = 30
Hình 3.9: Thủ tục objfunc tính hàm thích nghi f(x) = cx10 từ thông số giải mã x. function objfunc (x :real) :real;
const coeff = 1073741823.0; {hệ số chuẩn hóa vùng} n = 10;
Begin
objfunc := power(x/coeff,n) end;