Ví dụ về các bài toán đƣợc giải quyết bằng Choco:

Một phần của tài liệu Hướng tiếp cận quy hoạch ràng buộc trong việc giải các bài toán tối ưu (Trang 48)

2.4.1. Ví dụ 1: Bài toán con hậu N-Queens

Cho bàn cờ kích thước n*n có n con hậu. Cách sắp xếp n con hậu trên bàn cờ sao cho không có con nào có thể ăn lẫn nhau.

package example; import choco.Choco; import choco.Options; import choco.cp.model.CPModel; import choco.cp.solver.CPSolver; import choco.kernel.model.variables.integer.IntegerVariable; public class QUEENS {

public static void main (String [] args) {

// Khai báo biến

int n=8;

IntegerVariable[] queens=new IntegerVariable[n]; IntegerVariable[] diag1=new IntegerVariable[n]; IntegerVariable[] diag2=new IntegerVariable[n];

// Xây dựng mẫu

CPModel m=new CPModel();

// Đối với từng biến, xác định tên và giới hạn miền của chúng

for (int i=0;i<n;i++) {

queens[i]=Choco.makeIntVar("Q"+i,1,n); diag1[i]=Choco.makeIntVar("D1"+i, 1,2*n);

47

diag2[i]=Choco.makeIntVar("D2"+i,-n+1,n); }

// Khai báo ràng buộc

// - Mỗi con hậu phải ở trên 1 dòng

m.addConstraint(Choco.allDifferent(queens));

// - Không có bất kỳ 2 con hậu nào cùng nằm trên một đường chéo

for (int i=0;i<n;i++) { m.addConstraint(Choco.eq(diag1[i],Choco.plus(queens[i], i))); m.addConstraint(Choco.eq(diag2[i],Choco.minus(queens[i],i))); } m.addConstraint(Choco.allDifferent(diag1)); m.addConstraint(Choco.allDifferent(diag2));

// Xây dựng lời giải

CPSolver s=new CPSolver();

// Đọc mẫu s.read(m); // Giải mẫu s.solve(); // In giải pháp for(int i=0;i<n;i++) { System.out.print(" "+s.getVar(queens[i]).getVal()); } }

48

2.4.2. Ví dụ 2: Bài toán Magic square

Ma phương bậc n (ma trận kỳ ảo bậc n) là một cách sắp xếp n2

số, thường là các số nguyên phân biệt, trong một mảng dữ liệu cùng kiểu vuông, sao cho tổng n số trên mỗi hàng, cột, và đường chéo đều bằng nhau. Ma trận kỳ ảo chuẩn chứa các số nguyên từ 1 đến n2

.

Hằng số là tổng của mỗi hàng, cột và đường chéo được gọi là hằng số kỳ ảo hay tổng số kỳ ảo M. Hằng số kỳ ảo của một ma phương cổ điển chỉ phụ thuộc vào bậc n và có giá trị n(n2

+ 1)/2. package example; import choco.Choco; import choco.cp.model.CPModel; import choco.cp.solver.CPSolver; import choco.kernel.model.variables.integer.IntegerVariable; public class Magic {

public static void main(String [] args) {

// Khai báo hằng số

int n=3; // Lệnh của ma phương

int tong=n*(n*n+1)/2; // Tổng số kỳ ảo // Tạo mảng biến cùng kiểu

IntegerVariable [][] x=new IntegerVariable[n][n];

// Đối với từng biến, xác định tên và giới hạn miền D của biến

for (int i=0;i<n;i++) { for (int j=0;j<n;j++) { x[i][j]=Choco.makeIntVar(" x ", 1,n*n); } } // Xây dựng mẫu

49

// Ràng buộc hàng: Tổng hàng phải bằng tổng số kỳ ảo

for (int i=0;i<n;i++) { IntegerVariable[] temp=Choco.makeIntVarArray("temp", n,1,1000000); for(int j=0;j<n;j++) { temp[j]=x[i][j]; } m.addConstraint(Choco.eq(tong,Choco.sum(temp))); }

// Ràng buộc cột: Tổng cột phải bằng tổng số kỳ ảo

for(int i=0;i<n;i++) { IntegerVariable[][]tt=Choco.makeIntVarArray("tt", n, n,1,n*n); for (int j=0;j<n;j++) { tt[i][j]=x[j][i]; } }

for (int i=0;i<n;i++) { IntegerVariable[] temp=Choco.makeIntVarArray("temp", n,1,1000000); for(int j=0;j<n;j++) { temp[j]=x[i][j]; } m.addConstraint(Choco.eq(tong,Choco.sum(temp) ));

50

}

// Ràng buộc chéo: Tổng đường chéo bằng tổng số kỳ ảo

for (int i=0;i<n;i++) { IntegerVariable[] cheo1=Choco.makeIntVarArray("cheo1",n,1,n*n); IntegerVariable[] cheo2=Choco.makeIntVarArray("cheo2",n,1,n*n); for (int j=0;j<n;j++) { cheo1[i]=x[i][i]; cheo2[i]=x[n-1-i][i]; } m.addConstraint(Choco.eq(tong, Choco.sum(cheo1))); m.addConstraint(Choco.eq(tong, Choco.sum(cheo2))); }

// Các ô của ma trận phải khác nhau

IntegerVariable[] t2=Choco.makeIntVarArray("t2", n*n,1,n*n); for (int i=0;i<n;i++)

{ for(int j=0;j<n;j++) { t2[i*n+j]=x[i][j]; } m.addConstraint(Choco.allDifferent(t2)); } // Xây dựng Solver

CPSolver s=new CPSolver();

// Đọc mẫu

51

// Giải mẫu

s.solve();

// In giải pháp

for (int i=0;i<n;i++) { for (int j=0;j<n;j++) { System.out.print(" "+s.getVar(x[i][j]).getVal()+"---"); } System.out.println(); } } }

52

CHƢƠNG 3: ÁP DỤNG THƢ VIỆN CHOCO VÀO BÀI TOÁN ỨNG DỤNG: “XẾP LỊCH HỌC CHO CÁC LỚP CAO HỌC BÁCH KHOA”

3.1. Phát biểu bài toán:

Bài toán xếp lịch học luôn là một bài toán khó, mang tính khoa học đồng thời mang tính thực tiễn rất cao. Trên thế giới, bài toán Xếp lịch học (TimeTabling) đã được rất nhiều các nhà khoa học quan tâm, nghiên cứu. Đã có hơn 1000 bài báo khoa học được viết về đề tài này, trong đó có khoảng 300 luận án Tiến sĩ và Thạc sỹ được bảo vệ xung quanh về bài toán Thời khóa biểu. Riêng đối với Việt Nam, đặc biệt trong các trường Đại học, các trường phổ thông hay Cao học, từ lâu việc xếp lịch học đã trở thành một vấn đề có tính thời sự, một bài toán gây được sự chú ý, quan tâm của nhiều người.

Một thực tế hiện nay tại Việt Nam, việc xếp thời khóa biểu phần lớn là đều được thực hiện thủ công bằng tay. Phương pháp này vừa tốn nhiều chi phí, thời gian, công sức mà hiệu quả lại không cao. Nhu cầu thực tiễn hiện nay là tin học hóa bài toán xếp lịch học với tính năng sắp thời khóa biểu chính xác, hiệu quả, giảm bớt thời gian, chi phí công sức của con người. Tính phức tạp của bài toán xếp lịch học là các quy định, ràng buộc môn học chặt chẽ, các ràng buộc về lịch dạy của giáo viên, lớp học … hết sức phức tạp, đa dạng. Chính vì vậy, bài toán lập thời khóa biểu là một bào toán khó, có rất ít phần mềm lập thời khóa biểu được viết và sử dụng tại Việt Nam.

Dựa trên mô hình đào tạo sau đại học của trường Đại học Bách Khoa, đối với mỗi kỳ học, phòng đào tạo quy định danh sách các lớp học, danh sách các môn học tương ứng cho từng lớp học và danh sách giảng viên tương ứng với mỗi môn cho từng lớp. Trong luận văn, bài toán xếp lịch học cho các lớp cao học Bách Khoa phải đáp ứng được tất cả các điều kiện ràng buộc sau:

- Mỗi môn học ứng với một danh sách các ngày mà môn đó có thể được phân bổ vào (mỗi môn học đó đã được phân trước cho giảng viên và mỗi giảng viên chỉ có thời gian rảnh rỗi vào một số ngày nhất định)

53

- Số ngày của môn học ứng với số tín chỉ

- Mỗi lớp ứng với một danh sách các môn học mà lớp đó đăng ký.

- Xếp mỗi môn học vào một ngày nào đó sao cho không có xung đột xảy ra (hai môn học có chung lớp đăng ký thì phải xếp vào hai ngày khác nhau.)

3.2. Mô hình hóa với CHOCO

Bài toán xếp lịch học hoạt động hiệu quả nhất thì phải đáp ứng được các yêu cầu nghiệp vụ của bào toán. Do đó, chúng ta sẽ lần lượt giải quyết từng ràng buộc của bài toán. Với bài toán này tôi đưa ra hai mô hình.

Dữ liệu đầu vào:

• n: số môn học, các buổi học đánh số 0, 1, …, n-1

• b[i]: số buổi học của môn i (tùy thuộc số tín chỉ), với mọi i = 0,1,…,n-1 • f[i]: danh sách những buổi học bị cấm xếp của môn i do giảng viên của môn

này bận, với mọi i = 0,1,…,n-1

• D: số buổi của học kỳ, các môn sẽ được xếp vào các buổi 0, 1, 2,…, D-1 • Conflict[i,j] =1, nếu 2 môn i và j có xung đột với nhau(chung giảng viên dạy

hoặc chung lớp đăng ký học) và Conflict[i,j] = 0 nếu ngược lại, với mọi i,j = 0,1…,n-1,

3.2.1. Mô hình 1 (stateModel 1)

• Biến: X[i,d], với i = 0,1,…,n-1, d = 0,1,…, D-1

• Miền giá trị: D(X[i,d]) = {0,1}. Nếu X[i,d] = 1 nghĩa là môn i được xếp vào ngày d, bằng 0 ngược lại môn i không được xếp vào ngày d.

• Ràng buộc:

 Ràng buộc về ngày học đưa ra danh sách các ngày mà môn đó được phân bổ vào: X[i,0] + X[i,1] + … + X[i,D-1] = b[i],  i = 0,1,…,n-1

 Ràng buộc xung đột: X[i,d] + X[j,d] ≤ 1, 0 ≤ i < j ≤ n-1 trong đó Conflict[i,j] = 1

54

 Ràng buộc về những ngày cấm học: f[i] là những ngày học môn i bị cấm,Với d  f[i] thì X[i,d] = 0 tức là môn i không xếp lịch vào những ngày bị cấm đó.

3.2.2. Mô hình 2 (stateModel 2)

• Biến: X[i, j] là ngày mà buổi học thứ j của môn i được phân bổ vào. .

• Ràng buộc:

 Ràng buộc về thứ tự tương đối và ngày học của mỗi môn: X[i,j] < X[i,j+1] với mọi i = 0,…,n-1, với mọi j = 0,…,b[i]-2

 Ràng buộc về những ngày cấm học: X[i,j] ≠ d với mọi d  f[i], với mọi i = 0,…,n-1, j=0,..,b[i]-1.

 Ràng buộc xung đột: Với mọi i ≠ j trong đó Conflict[i,j] = 1 thì X[i,h] ≠ X[j,k] với mọi h = 0,…,b[i]-1, k = 0,…,b[j]-1

55

3.3. Thử nghiệm

Trong phần này, chúng tôi thử nghiệm và so sánh 2 mô hình trên 10 bộ dữ liệu sinh ngẫu nhiên. Chúng tôi xin đưa ra ví dụ 1 bộ dữ liệu đầu vào sau đây:

56

Sau đây là kết quả chạy thử nghiệm của 2 mô hình:

STT Bộ dữ liệu Số môn Số ngày Số lớp Mô hình 1 Mô hình 2

1 Test-5-50-1 5 50 1 34.094 0.356 2 Test-6-60-1 6 60 1 379.431 0.496 3 Test-7-70-1 7 70 1 - 0.38 4 Test-8-80-1 8 80 1 - 0.512 5 Test-9-90-1 9 90 1 - 0.46 6 Test-15-70-3 15 70 3 - 0.548 7 Test-18-80-3 18 80 3 - 0.492 8 Test-21-80-3 21 80 3 - 0.66 9 Test-28-80-4 28 80 4 - 0.74 10 Test-32-90-4 32 90 4 - 0.856

Bảng 1: Kết quả thử nghiệm 2 mô hình, Thời gian thử nghiệm đo bằng dây

Nhận xét: Kết quả thực nghiệm cho thấy mô hình 2 chạy nhanh hơn rất nhiều so với mô hình 1 do số lượng biến của mô hình 2 ít hơn.

57

KẾT LUẬN VÀ HƢỚNG PHÁT TRIỂN

Trong luận văn này, chúng tôi đã tìm hiểu cơ sở lý thuyết của bài toán quy hoạch ràng buộc và thư viện CHOCO. Thư viện CHOCO hỗ trợ người lập trình các công cụ để mô hinh hóa một cách linh hoạt nhiều bài toán tối ưu thỏa mãn ràng buộc khác nhau. Việc thay đổi, thêm bớt ràng buộc của bài toán được thực hiện một cách dễ dàng. Điều này đã giảm bớt công sức cũng như thời gian lập trình. Đóng góp cá nhân của luận văn là đã ứng dụng quy hoạch ràng buộc và thư viện CHOCO vào giải một bài toán thỏa mãn ràng buộc thực tế đó là bài toán “Xếp lịch học cho các lớp cao học Bách Khoa”. Trong đó chúng tôi đề xuất và thử nghiệm 2 cách mô hình hóa, kết quả cho thấy mô hình 2 tốt hơn mô hình 1.

Trong tương tai, Chúng tôi tiếp tục cải tiến mô hình, khảo sát thêm các yếu tố thực tế của bài toán tại trường Bách Khoa để đưa ra được những mô hình nâng cao, có thêm nhiều ràng buộc sát với thực tế hơn, đáp ứng được nhu cầu hiện tại đang rất cần những phần mềm xếp lịch giúp ích cho quá trình quản lý.

58

TÀI LIỆU THAM KHẢO

[1] Joseph Y-T. Leung. Handbook of Scheduling. Chapman & Hall/crc computer and information science series, 2000.

[2] Association for Constraint Programming. http://www.a4cp.org/

[3] Journal of Constraints. http://link.springer.com/journal/10601

[4]International Conference on Principles and Practice of Constraint Programming. http://www.a4cp.org/events/cp-conference-series

[5] Comet. Dynadec.

[6] F.Rossi, P.VanBeek and T.Walsh “Handbook of Constraint Programming”, Elsevier, 2006

[7] Choco_doc_2.1.5 http://choco.mines-nantes.fr/

[8]. Michael Marte. Models and Algorithms for School Timetabling – A Constraint- Programming Approach. PhD thesis, 2002.

[9]. Bruce Golden, S. Raghavan, Edward Wasil. The vehicle routing problem: latest advances new challenges, 2008.

[10]. Mohammed Hadwan, Masri Ayob, Naser R.Sabar, Roug Quc. A harmony search algorithm for nurse rostering problems. Information Sciences, 2013, Pages 126-140

[11]. GECODE. http://www.gecode.org/

59

PHỤ LỤC

Lập trình bài toán “Xếp lịch học tín chỉ cho các lớp cao học Bách Khoa”

import choco.Choco; import choco.cp.model.CPModel; import choco.cp.solver.CPSolver; import choco.kernel.model.variables.integer.IntegerExpressionVariable; import choco.kernel.model.variables.integer.IntegerVariable; import java.util.*; import java.io.*;

public class MasterTimeTabling {

ArrayList<Integer>[] f;// f[i][j] = d: mon i bi cam khong duoc xep vao ngay d

int[][] conflict;

int[][] student_course;

int[] b; // so buoi can hoc

int n;

int h;

int D;

public void readData(String filename) {

try{

Scanner in = new Scanner(new File(filename)); String line = in.nextLine();

n = in.nextInt(); D = in.nextInt(); h = in.nextInt(); b = new int[n]; line = in.nextLine(); line = in.nextLine();

System.out.println("n = " + n + ", D = " + D + ", h = " + h

+ ", linr = " + line);

for (int i=0;i<n;i++) {

int mh = in.nextInt();

int songay = in.nextInt();

b[mh] =songay; } f = new ArrayList[n]; line = in.nextLine(); line = in.nextLine(); //System.out.println("line = " + line + ", n = " + n); for (int i=0;i<n;i++) { int mh = in.nextInt(); //System.out.println("i = " + i + ", mh = " + mh); f[mh] = new ArrayList<Integer>(); int L = in.nextInt(); for (int j = 0; j <= L-1; j++) {

60 int d = in.nextInt(); f[mh].add(d); } } line = in.nextLine(); line = in.nextLine();

student_course = new int[h][n];

for(int i = 0; i < h; i++) for(int j = 0; j < n; j++) student_course[i][j] = 0; while(true){ int s = in.nextInt(); if(s == -1) break; int c = in.nextInt(); student_course[s][c] = 1; } /* for(int i = 0; i < h; i++){ for(int j = 0; j < n; j++) System.out.print(student_course[i][j] + " "); System.out.println(); } */ in.close(); }catch(Exception ex){ ex.printStackTrace(); }

conflict = new int[n][n];

for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { conflict[i][j] = 0; } else { for(int s = 0; s < h; s++) if(student_course[s][i] == 1 && student_course[s][j] == 1) conflict[i][j] = 1; } } } }

public void solveModel2(int timeLimit){

double t0 = System.currentTimeMillis();

ArrayList<IntegerVariable>[] x = new ArrayList[n];

for(int i = 0; i < n; i++){ x[i] = new ArrayList<IntegerVariable>(); for(int j = 0; j < b[i]; j++) x[i].add(Choco.makeIntVar("x["+ i + ","+ j + "]",0,D- 1)); }

61

for(int i = 0; i < n-1; i++){

for(int j = i+1; j < n; j++){

if(conflict[i][j] > 0){

for(int ii = 0; ii < x[i].size(); ii++){

for(int jj = 0; jj < x[j].size(); jj++){ IntegerVariable xi = x[i].get(ii); IntegerVariable xj = x[j].get(jj); m.addConstraint(Choco.neq(xi, xj)); } } } } } for(int i = 0; i < n; i++){

for(int j1 = 0; j1 < x[i].size()-1; j1++){ IntegerVariable x1 = x[i].get(j1);

for(int j2 = j1+1; j2 < x[i].size(); j2++){ IntegerVariable x2 = x[i].get(j2);

m.addConstraint(Choco.lt(x1, x2)); }

}

for(int j = 0; j < x[i].size(); j++){ IntegerVariable xj = x[i].get(j);

for(int jj = 0; jj < f[i].size(); jj++){

int fd = f[i].get(jj);

m.addConstraint(Choco.neq(xj, fd)); }

} }

CPSolver s = new CPSolver();

s.read(m);

s.setTimeLimit(timeLimit); //s.setFirstSolution(false);

s.solve();

double t = System.currentTimeMillis() - t0;

t = t*0.001;

System.out.println("Solve2 --> Number of solutions = " +

s.getNbSolutions());

for (int i = 0; i < n; i++) {

System.out.print("Course " + i + "\t:");

for (int d = 0; d < D; d++) {

boolean ok = false;

for(int j = 0; j < x[i].size(); j++){

if(s.getVar(x[i].get(j)).getVal() == d){

ok = true; break; }

62

if(ok) System.out.print("1 "); else

System.out.print("0 "); }

System.out.println(); }

System.out.println("SolveModel2 Finished, time = " + t); }

public void solveModel1(int timeLimit) {

double t0 = System.currentTimeMillis();

IntegerVariable[][] x = new IntegerVariable[n][D];

for (int i = 0; i < n; i++)

for (int d = 0; d < D; d++)

x[i][d] = Choco.makeIntVar("x[" + i + "," + d + "]", 0, 1); CPModel m = new CPModel();

// rang buoc ngay hoc

for (int i = 0; i < n; i++) {

IntegerVariable[] y = new IntegerVariable[D];

for (int d = 0; d < D; d++)

y[d] = x[i][d];

m.addConstraint(Choco.eq(Choco.sum(y), b[i])); System.out.println("b[" + i + "] = " + b[i]); }

// rang buoc xung dot

for (int d = 0; d < D; d++) {

for (int i = 0; i < n - 1; i++) {

for (int j = i + 1; j < n; j++) {

if (conflict[i][j] > 0) {

m.addConstraint(Choco.leq(Choco.plus(x[i][d], x[j][d]),1)); }

} }

}

// rang buoc nhung ngay cam hoc

for (int i = 0; i < n; i++) {

System.out.println("f[" + i + "] = " + f[i].size());

for (int j = 0; j < f[i].size(); j++) {

m.addConstraint(Choco.eq(x[i][f[i].get(j)], 0)); }

}

CPSolver s = new CPSolver();

s.read(m);

s.setTimeLimit(timeLimit);

s.solve();

double t = System.currentTimeMillis() - t0;

63

System.out.println("Solve1 --> Number of solutions = " +

s.getNbSolutions());

for (int i = 0; i < n; i++) {

for (int d = 0; d < D; d++) {

System.out.print(" " + s.getVar(x[i][d]).getVal()); }

System.out.println(); }

System.out.println("Solve Finish time = " + t); }

public static void main(String[] args) {

MasterTimeTabling mtt = new MasterTimeTabling();

mtt.readData("data\\MasterTimeTabling\\test-15-70-3.txt"); //mtt.readData("data\\MasterTimeTabling\\test-original.txt"); mtt.solveModel2(10000); //mtt.solveModel1(5000); } }

Một phần của tài liệu Hướng tiếp cận quy hoạch ràng buộc trong việc giải các bài toán tối ưu (Trang 48)

Tải bản đầy đủ (PDF)

(65 trang)