Bài toán lấy thƣ hằng ngày:

Một phần của tài liệu Tìm hiểu bài toán tìm đường đi ngắn nhất & ứng dụng giải thuật di truyền cho bài toán phát thư (Trang 36)

1. Xác định vấn đề:

Cho một danh sách gồm một số bƣu cục trong thành phố và khoảng cách giữa chúng , nhiệm vụ là phải tìm đƣờng đi ngắn nhất có thể, mà chỉ ghé mỗi bƣu cục đúng một lần và cuối cùng trở về bƣu cục trung tâm. Trong báo cáo này, em xin sử dụng thuật giải di truyền trong khai phá dữ liệu phân lớp để tìm tuyến đƣờng ngắn nhất .

2. Các bƣớc thực hiện giải thuật:

a. Mã hóa : Trong giải thuật di truyền, mỗi nhiễm sắc thể biểu diễn một lời giải theo một cách nào đó mà chứa đủ các thông tin cần thiết về lời giải. Các nhiễm sắc thể tạo nên một quần thể, là không gian lời giải của bài toán mà ta khảo sát.

Mỗi nhiễm sắc thể biểu diễn một cách sắp xếp lộ trình đi qua các bƣu cục của thành phố. Do đó, mỗi cách biểu diễn nhiễm sắc thể chính là một hoán vị của N số nguyên dƣơng

đầu tiên, việc thao tác trên các nhiễm sắc thể chính là hoán vị các số trong chuỗi đó làm thay đổi trình tự của nó. Áp dụng mã hóa hoán vị cho bài toán.

Code:

{

public class Mutator {

public void ChromoseCompraror(GAChromosome chromosome) {

int length = StaticMember.ListCities.Count;

double[,] NighborMatrix = new double[length, length]; for (int i = 0; i < length; i++)

NighborMatrix[i, i] = -1; for (int i = 0; i < length - 1; i++) {

int City1Index = chromosome[i]; for (int j = i + 1; j < length; j++) {

int City2Index = chromosome[j];

double distance = StaticMember.MatrixDistance[City1Index,

City2Index];

NighborMatrix[City1Index, City2Index] = distance; NighborMatrix[City2Index, City1Index] = distance; }

}

GAChromosome newChromosome = new GAChromosome(); int iCurrentSel = StaticMember.RndObj.Next(0, length); int Gene = chromosome[iCurrentSel];

newChromosome.AddGene(Gene); int iLeftPoints = length - 1; int iCurrentCitySel = Gene; do

{

int iNearstNeighbor = GetNearstNeighbor(NighborMatrix, iCurrentCitySel, StaticMember.ListCities); newChromosome.AddGene(iNearstNeighbor); iLeftPoints--; iCurrentCitySel = iNearstNeighbor; } while (iLeftPoints > 0); chromosome.CopyChromosome(newChromosome); }

private int GetNearstNeighbor(double[,] NighborMatrix, int iCurrentCitySel, List<Point> Points)

{

int Index = 0;

double distance = 1000000000;

for (int i = 0; i < Points.Count; i++) {

if (NighborMatrix[iCurrentCitySel, i] != -1

&& distance > NighborMatrix[iCurrentCitySel, i]) {

distance = NighborMatrix[iCurrentCitySel, i]; Index = i; (adsbygoogle = window.adsbygoogle || []).push({});

} }

for (int i = 0; i < Points.Count; i++) { NighborMatrix[i, iCurrentCitySel] = -1; NighborMatrix[i, Index] = -1; } return Index; }

public void SwapMutator(GAChromosome chromose) {

Random rnd = new Random();

int ChromoLen = chromose.GeneLength; int iSelection1 = rnd.Next(0, ChromoLen); int iSelection2 = iSelection1;

while (iSelection2 == iSelection1)

iSelection2 = rnd.Next(0, ChromoLen);

int temp = chromose[iSelection1];

chromose[iSelection1] = chromose[iSelection2]; chromose[iSelection2] = temp;

}

public void InversionMutator(GAChromosome chromose) {

int ChromoLen = chromose.GeneLength;

int iSelection1 = StaticMember.RndObj.Next(0, ChromoLen); int iSelection2 = iSelection1;

while (iSelection2 == iSelection1)

iSelection2 = StaticMember.RndObj.Next(0, ChromoLen); int temp; if (iSelection1 > iSelection2) { temp = iSelection1; iSelection1 = iSelection2; iSelection2 = temp; }

while (iSelection1 < iSelection2) { temp = chromose[iSelection1]; chromose[iSelection1] = chromose[iSelection2]; chromose[iSelection2] = temp; iSelection1++; iSelection2--; } }

public void TraslocationMutator(GAChromosome chromose) {

int cutPoint1 = StaticMember.RndObj.Next(0, mid - numberOfGene); int cutPoint2 = StaticMember.RndObj.Next(mid + 1, (mid + 1) + mid - numberOfGene);

int i; int temp;

for (i = 0; i < numberOfGene; i++) {

temp = chromose[cutPoint1 + i];

chromose[cutPoint1 + i] = chromose[cutPoint2 + i]; chromose[cutPoint2 + i] = temp;

} }

} }

b. Khởi tạo: Khởi tạo quần thể ban đầu là bƣớc đầu tiên trong giải thuật di truyền. Thông thƣờng để khởi tạo quần thể trong bài toán tối ƣu, ta tạo ra một cách ngẫu nhiên các lời giải có thể (thƣờng là các lời giải thỏa mãn ràng buộc của bài toán nhƣng chƣa biết là đại lƣợng cần tối ƣu đã là tối ƣu hay chƣa). Tuỳ vào từng bài toán cụ thể mà ta có các phƣơng pháp khởi tạo khác nhau. Với bài toán này ta khởi tạo bằng phƣơng pháp tham lam. Tại mỗi vị trí trong nhiễm sắc thể, ta chọn một bƣu cục gần nhất với bƣu cục hiện tại và chƣa đƣợc ghé đến lấy thƣ để đƣa vào vị trị tiếp theo trong nhiễm sắc thể . Chất lƣợng của quần thể ban đầu càng cao thì lời giải mà giải thuật di truyền đƣa ra càng tốt.

Code:

{

public class Initializer {

/// <summary> ///

/// </summary> (adsbygoogle = window.adsbygoogle || []).push({});

/// <param name="chromose"></param> public void Init(GAChromosome chromose) {

//if (chromose.Count >= StaticMember.ListCities.Count)

// return;

chromose.Clear();

bool[] PointSel = new bool[StaticMember.ListCities.Count]; bool bStop = false;

do {

int iSel = StaticMember.RndObj.Next(0, StaticMember.ListCities.Count); if (!PointSel[iSel]) { PointSel[iSel] = true; chromose.AddGene(iSel); }

for (int i = 0; i < StaticMember.ListCities.Count; i++) {

if (!PointSel[i]) break; if (i == StaticMember.ListCities.Count - 1) bStop = true; } } while (!bStop); } } }

c. Chọn lọc: Cơ chế lựa chọn đƣợc áp dụng khi chọn các cá thể từ quần thể ban đầu để thực hiện việc lai ghép và đột biến, tạo ra quần thể con . Có nhiều cách để lựa chọn các cá thể từ một quần thể, ở bài toán này ta dùng phƣơng pháp chọn lọc cạnh tranh(Tournament selection). Nghĩa là lấy một số NST trong quần thể, NST nào có độ thích nghi cao nhất đƣợc chọn. Lặp lại thao tác trên N lần.

Code:

{

public class Fitness {

public void FitnessCalculator(GAChromosome chromosome) { if (chromosome.GeneLength > 1) { double fitness = 0; int CityIndex1 = 0; int CityIndex2 = 1;

int Pointindex1, PointIndex2;

while (CityIndex2 < chromosome.GeneLength) { Pointindex1 = chromosome[CityIndex1]; PointIndex2 = chromosome[CityIndex2]; fitness += StaticMember.MatrixDistance[Pointindex1, PointIndex2]; CityIndex1++; CityIndex2++; } Pointindex1 = chromosome[0]; PointIndex2 = chromosome[chromosome.GeneLength - 1]; fitness += StaticMember.MatrixDistance[Pointindex1, PointIndex2]; chromosome.Fitness = 1000/fitness; } } } }

d. Lai ghép: Sử dụng phép lai thứ tự(OX – Ordered Crossover) .

Code:

{

public class CrossOver {

public bool GreedyCrossOver(GAChromosome Dad, GAChromosome Mum, ref GAChromosome child1, ref GAChromosome child2)

{

if (!GreedyCrossOver(Dad, Mum, ref child1)) return false;

if (!GreedyCrossOver(Mum, Dad, ref child2)) return false;

return true; }

private bool GreedyCrossOver(GAChromosome Dad, GAChromosome Mum, ref GAChromosome child) { if (Dad.Count == 0 || Mum.Count == 0) { return false; } child.Clear();

int length = Dad.GeneLength; int MumIndex = -1;

int DadIndex = StaticMember.RndObj.Next(0, length); int DadGene = Dad[DadIndex];

MumIndex = Mum.HasThisGene(DadGene); if (MumIndex < 0)

throw new Exception("Không tìm thấy"); child.Add(DadGene); (adsbygoogle = window.adsbygoogle || []).push({});

bool bDadAdded = true; bool bMumAdded = true; do { int obMumGene = -1; int obDadGene = -1; if (bDadAdded) { if (DadIndex > 0) DadIndex = DadIndex - 1; else DadIndex = length - 1; obDadGene = Dad[DadIndex]; } else { bDadAdded = false; } if (bMumAdded) { if (MumIndex < length - 1)

MumIndex = MumIndex + 1; else MumIndex = 0; obMumGene = Mum[MumIndex]; } else { bMumAdded = false; }

if (bDadAdded && child.HasThisGene(obDadGene) < 0) {

child.Insert(0, obDadGene); }

else

bDadAdded = false;

if (bMumAdded && child.HasThisGene(obMumGene) < 0) {

child.AddGene(obMumGene); }

else

bMumAdded = false; } while (bDadAdded || bMumAdded); while (child.GeneLength < length) {

bool bDone = false; do

{

int iRandom = StaticMember.RndObj.Next(0, length); if (child.HasThisGene(iRandom) < 0) { child.Add(iRandom); bDone = true; } } while (!bDone); } return true; }

public bool OrderCrossOver(GAChromosome Dad, GAChromosome Mum, ref GAChromosome child1, ref GAChromosome child2)

{

child1.CopyChromosome(Dad); child2.CopyChromosome(Mum); int cutPoint1, cutPoint2;

int length = Dad.Count;

cutPoint1 = StaticMember.RndObj.Next(1, Dad.Count - 1); do

{

cutPoint2 = StaticMember.RndObj.Next(1, Dad.Count - 1); } while (cutPoint1 == cutPoint2);

int i;

i = cutPoint1; cutPoint1 = cutPoint2; cutPoint2 = i; } int indexChild1 = 0; int indexChild2 = 0;

for (i = cutPoint1; i <= cutPoint2; i++) {

if (!IsExistInRange(Dad, Mum[i], cutPoint1, cutPoint2)) {

child1[indexChild1] = Mum[i]; indexChild1++;

}

if (!IsExistInRange(Mum, Dad[i], cutPoint1, cutPoint2)) {

child2[indexChild2] = Dad[i]; indexChild2++;

} }

for (i = cutPoint1; i <= cutPoint2; i++) { child1[indexChild1] = Dad[i]; child2[indexChild2] = Mum[i]; indexChild1++; indexChild2++; } (adsbygoogle = window.adsbygoogle || []).push({});

for (i = cutPoint2 + 1; i < length; i++) {

if (!IsExistInRange(Dad, Mum[i], cutPoint1, cutPoint2)) {

child1[indexChild1] = Mum[i]; indexChild1++;

}

if (!IsExistInRange(Mum, Dad[i], cutPoint1, cutPoint2)) {

child2[indexChild2] = Dad[i]; indexChild2++;

} }

for (i = 0; i < cutPoint1; i++) {

if (!IsExistInRange(Dad, Mum[i], cutPoint1, cutPoint2)) {

child1[indexChild1] = Mum[i]; indexChild1++;

}

if (!IsExistInRange(Mum, Dad[i], cutPoint1, cutPoint2)) {

child2[indexChild2] = Dad[i]; indexChild2++;

} }

if (indexChild1 != indexChild2) return false;

return true; }

private bool IsExistInRange(GAChromosome chromosome, int gene, int lower, int upper)

{

for (int i = lower; i <= upper; i++ ) { if (chromosome[i] == gene) return true; } return false; } } }

e. Đột biến: bằng cách hoán vị hai gen hoặc đảo ngƣợc hoặc dịch chuyển các gen trên cùng nhiễm sắc thể.

f. Hàm mục tiêu g(x) đƣợc tính là tổng chiều dài của hành trình. Nhƣ vậy, giá trị này càng bé càng tốt.

Chƣơng trình:

Mô tả chƣơng trình:

1. Nút stop: dùng để stop chƣơng trình(đang thực thi thuật toán) khi đang chạy 2. Nút Clear: xóa sách các điểm trên giao diện hiển thị phía dƣới

3. Chọn số bƣu cục để thực hiện thuật toán

4. Nút Run: chạy chƣơng trình sau khi khi đã khởi tạo các điểm( bƣu cục)( PO) 5. Nút Radomize: Khởi tạo ngẫu nhiên các điểm (bƣu cục)

6. Nút Open: mở các bƣu cục theo file đã lƣu( trong chƣơng trình lƣu trong file PO.xml)

7. Các điểm(biểu hiện cho 1 bƣu cục)

KẾT LUẬN

Trong ngành khoa học máy tính, tìm kiếm lời giải tối ƣu cho các bài toán là vấn đề đƣợc các nhà khoa học máy tính đặc biệt rất quan tâm. Mục đích chính của các thuật toán tìm kiếm lời giải là tìm ra lời giải tối ƣu nhất cho bài toán trong thời gian nhỏ nhất. Tuy nhiên, trong thực tiễn có rất nhiều bài toán tối ƣu với không gian tìm kiếm rất lớn cần phải giải quyết. Vì vậy, việc đòi hỏi thuật giải chất lƣợng cao và sử dụng kỹ thuật trí tuệ nhân tạo đặc biệt rất cần thiết khi giải quyết các bài toán có không gian tìm kiếm lớn. Thuật giải di truyền (genetic algorithm) là một trong những kỹ thuật tìm kiếm lời giải tối ƣu đã đáp ứng đƣợc yêu cầu của nhiều bài toán và ứng dụng. (adsbygoogle = window.adsbygoogle || []).push({});

Qua bài thu hoạch này em đã bƣớc đầu nắm bắt đƣợc những bƣớc cơ bản xây dựng nên một giải thuật. Đồng thời tìm hiểm về giải thuật di truyền. Áp dụng xây dựng demo giải bài toán phát thƣ khu vực TPHCM.

TÀI LIỆU THAM KHẢO

[1]. Mitsuo Gen, Runwei Cheng, “Genetic Algorithms & Engineering Optimization, John Wiley & Son, 2000, pages 27 – 80.

[2]. S.N. Sivanandam, S.N. Deepa, “Introduction to Genetic Algorithms, Springer, 2008, pages 32 – 105.

[3]. Lê Minh Hoàng ,” Cấu trúc dữ liệu và giải thuật” , Đại học sƣ phạm Hà nội, 2006

[4]. Thomas Cormen, “Introduction to Algorithm 3rd,MIT Press,2009

Một phần của tài liệu Tìm hiểu bài toán tìm đường đi ngắn nhất & ứng dụng giải thuật di truyền cho bài toán phát thư (Trang 36)