Lập trình Hàm bằng ngôn ngữ Scheme và lập trình Prolog là các công cụ cơ bản và rất quan trọng trong việc giải quyết các bài toán Trí tuệ nhân tạo.. Trong các ngôn ngữ lập trình hàm, hàm
Trang 1đại học đà nẵng trờng đại học bách khoa -
-tiểu luận
lập trình trí tuệ nhân tạo
Giảng viên hớng dẫn: PGS.TS Phan Huy Khánh Học viên thực hiện:
Đặng Ngọc Tuấn
Lê Công Vợng Trần Lơng Vơng Lớp Cao học Khoa học máy tính K24 Quảng Bình
Đồng Hới, 02/2013
LỜI NểI ĐẦU
-Trớ tuệ nhõn tạo trở thành một mụn học với mục đớch chớnh là cung cấp lời
Trang 2tạo rất đa dạng và phong phú, áp dụng cho nhiều lĩnh vực như điều khiển tự động, các loại robot, các hệ dịch tự động cho các ngôn ngữ tự nhiên, các hệ nhận dạng, trò chơi điện tử,…
Thuật ngữ trí tuệ nhân tạo được dùng để nói đến các máy tính có những mục đích khác nhau, xử lý các lĩnh vực khác nhau trong đời sống Ngành khoa học nghiên cứu lý thuyết và các ứng dụng của trí tuệ nhân tạo ngày càng phát triển Đây là một ngành trọng yếu của tin học, liên quan đến cách cư xử, sự học hỏi và khả năng thích ứng thông minh của máy móc Lập trình Hàm bằng ngôn ngữ Scheme và lập trình Prolog là các công cụ cơ bản và rất quan trọng trong việc giải quyết các bài toán Trí tuệ nhân tạo
Lập trình hàm là phong cách lập trình dựa trên định nghĩa hàm sử dụng phép tính lambda (λ-calculus) Trong các ngôn ngữ lập trình hàm, hàm đóng vai trò trung tâm, thay vì thực hiện lệnh, máy tính sẽ thực hiện tính toán các biểu thức Ngôn ngữ Scheme có tính phổ dụng cao, giải quyết thích hợp các bài toán trong lĩnh vực công nghệ thông tin Một chương trình được lập trình dưới ngôn ngữ Scheme là một dãy các định nghĩa hàm tích hợp lại để định nghĩa một hàm hoặc nhiều hàm phức tạp hơn
Prolog là ngôn ngữ lập trình logic, Prolog còn được gọi là ngôn ngữ lập trình ký hiệu tương tự lập trình hàm Nguyên lý lập trình logic dựa trên phép suy đoán logic, liên quan đến những khái niệm toán học Prolog thích hợp để giải quyết những bài toán liên quan đến các đối tượng và mối quan hệ giữa các đối tượng đó
Có rất nhiều lĩnh vực liên quan đến lập trình trí tuệ nhân tạo, xong với điều kiện và thời gian cho phép chúng em xin trình bày một số lĩnh vực nghiên cứu sau đây:
Phần I: LÝ THUYẾT LẬP TRÌNH HÀM
Đề tài: Áp dụng kiểu dữ liệu trừu tượng, xây dựng kiểu cấu trúc dữ liệu
truyền thống ngăn xếp (Stack) trong Scheme Cho ví dụ minh hoạ vận dụng ngăn xếp để chuyển đổi một số từ hệ thập phân sang hệ nhị phân
Phần II: BÀI TOÁN LẬP TRÌNH HÀM
Trang 3Đề tài: Hãy viết chương trình Scheme mô phỏng các hàm đệ quy thực hiện
kiểm tra số nguyên tố (Test for Prime).
Phần III: BÀI TOÁN LẬP TRÌNH PROLOG
Đề tài: Cài đặt thuật toán tìm ước số chung lớn nhất sử dụng thuật toán
Euclide (Euclidean Algorithm)
Với thời gian và việc nghiên cứu của chúng tôi còn nhiều hạn chế nên không tránh khỏi có những sai sót Rất mong được sự góp ý và định hướng của Thầy PGS.TS Phan Huy Khánh và các anh chị cùng lớp để chúng tôi có thể tiếp tục nghiên cứu và đạt được kết quả tốt hơn trong thời gian tới
Xin chân thành cảm ơn PGS.TS Phan Huy Khánh đã nhiệt tình giảng dạy, góp ý để nhóm em hoàn thành tiểu luận này
Nhóm học viên thực hiện:
Đặng Ngọc Tuấn
Lê Công Vượng Trần Lương Vương
Trang 4MỤC LỤC
§ång Híi, 02/2013 1
Trang 5Phần I
LÝ THUYẾT LẬP TRÌNH HÀM
Đề tài: Áp dụng kiểu dữ liệu trừu tượng, xây dựng kiểu cấu trúc dữ liệu truyền thống ngăn xếp (Stack) trong Scheme Cho ví dụ minh hoạ vận dụng ngăn xếp để đổi một số từ hệ thập phân sang hệ nhị phân
I Tổng quan về ngăn xếp (Stack)
Ngăn xếp (Stack) là một kiểu danh sách tuyến tính đặc biệt mà phép bổ sung hay loại bỏ luôn luôn thực hiện ở một đầu gọi là đỉnh (Top)
Có thể hình dung nó như cơ cấu của một hộp chứa đạn súng trường hoặc súng tiểu liên Lắp đạn vào hay lấy đạn ra cũng chỉ ở một đầu hộp Viên đạn mới nạp vào sẽ nằm ở đỉnh (Top) còn viên đạn nặp vào đầu tiên sẽ nằm ở đáy(Bottom) Viên nạp vào sau cùng chính là viên lên nòng súng đầu tiên
Nguyên tắc “Vào sau ra trước” như vậy của Stack đã đưa đến một tên gọi khác: Danh sách kiểu LIFO (last - in - first - out) Stack có thể rỗng hoặc bao gồm một số phần tử
Có thể dùng cấu trúc dữ liệu vector (mảng) hoặc cấu trúc dữ liệu danh sách móc nối để lưu trữ dữ liệu cho các Stack
Ta có nguyên tắc hoạt động của Stack như sau:
Vào
Ra
Trang 6II Xây dựng kiểu cấu trúc dữ liệu truyền thống ngăn xếp (Stack) trong Scheme
1 Đặc tả cấu trúc dữ liệu kiểu ngăn xếp:
Types Stack(T)
functions
empty-stack : → Stack(T)
empty-stack? : Stack(T) → boolean
push-stack : T × Stack(T) → Stack(T)
pop-stack : Stack(T) -/→ Stack(T)
top-stack : Stack(T) -/→ T
preconditions
pop-stack(s: Stack(T))
chỉ xác định khi và chỉ khi (not empty-stack?(S))
top-stack(s: Stack(T))
chỉ xác định khi và chỉ khi (not empty-stack?(S))
axioms
var x: T, s : Stack(T)
empty-stack?(empty-stack) = true
empty-stack?(push-stack (x, S)) = false
pop-stack(push-stack (x, S)) = S
top-stack(push-stack (x, S)) = x
Trang 7Ta cần xây dựng các hàm Scheme thao tác trên ngăn xếp như sau :
(empty-stack? (empty-stack))
#t
(empty-stack? (push-stack x S))
#f
(pop-stack (push-stack x S))
> S
(top-stack (push-stack x S)
> x
2 Xây dựng ngăn xếp:
Có nhiểu các để biểu diễn cấu trúc dữ liệu ngăn xếp trong Scheme Phương pháp tự nhiên hơn cả là biểu diễn ngăn xếp dưới dạng một danh sách
mà các thao tác bổ sung và loại bỏ một phần tử được thực hiện ở một đầu của
Trang 8danh sách Trong Scheme, mỗi lần bổ sung một phần tử vào danh sách kéo theo việc tạo ra một bộ đôi (dotted pair) mới:
Ta có các hàm Scheme như sau:
(define (empty-stack) ’())
(define empty-stack? null?)
(define (push-stack x S)
(cons x S)) (define (pop-stack S)
(if (empty-stack? S)
(display ”ERROR: stack is empty!”) (cdr S)))
(define (top-stack S)
(if (empty-stack? S)
(display ”ERROR: stack is empty!”) (car S)))
III Ví dụ minh hoạ vận dụng ngăn xếp để chuyển một số hệ thập phân sang hệ nhị phân
Ta biết rằng dữ liệu lưu trong bộ nhớ của máy tính đều được biểu diễn nhị phân Như vậy nghĩa là các số xuất hiện trong chương trình đều phải chuyển đổi
từ thập phân sang nhị phân trước khi thực hiện các phép xử lý
Trang 9Đối với hệ thập phân: khi ta viết 437 thì nó biểu diễn con số mà giá trị là 4.102 + 3.101 + 7.100
Với số ở hệ nhị phân cũng tương tự
Chẳng hạn: 110101112 thì biểu diễn số:
1.27 + 1.26 + 0.25 + 1.24 + 0.23 + 1.22 + 1.21 + 1.20 = (215)10
Khi đổi một số nguyên từ hệ thập phân sang hệ nhị phân thì người ta dùng phép chia liên tiếp cho 2 và lấy số dư (là các chữ số nhị phân) theo chiều ngược lại
Ví dụ:
215 1
2 107 1
2
53 1
2
26 0
2
13 1
2
6 0
2 3 1
2
1 1
2 0
11010111
2
437
1
2
218
0
2
109 1
2
54 0
2
27 1
2
13 1
2 6 0
2
3 1
2 0
110110101 2
1 1
2 0
Trang 10Như vậy rõ ràng trong cách biến đổi này các số dư được tạo ra sau lại được hiển thị trước Cơ chế sắp xếp này chính là cơ chế của Stack Để thực hiện biến đổi ta sẽ dùng một Stack để lưu trữ số dư qua từng phép chia: Khi thực hiện phép chia thì nạp số dư vào Stack, sau đó lấy chúng lần lượt từ Stack ra
Ví dụ: với số (26)10 (0 1 0 1 1) = (11010)2
PUSH
1
POP
1
1 1 0 1 0
Trang 11Phần II BÀI TOÁN LẬP TRÌNH HÀM
Đề tài: Hãy viết chương trình Scheme mô phỏng các hàm đệ quy thực hiện kiểm tra số nguyên tố (Test for Prime)
Cho một số nguyên n, cần tìm các số nguyên tố trong khoảng từ 2 n Có nhiều thuật toán tìm số nguyên tố, sau đây là thuật toán sử dụng sàng (sieve) Eratosthènes viết bằng ngôn ngữ mệnh lệnh:
1 Khởi động tập hợp kết quả S chứa các số nguyên tố
2 Xây dựng sàng sieve chứa danh sách các số từ 2 n
3 Repeat
Tìm số nguyên tố prime
Thêm prime vào tập hợp kết quả S
Loại trừ khỏi sàng (sieve) các bội số của Prime là 2*prime, 3*prime, … until sieve = rỗng
Sau đây là chương trình Scheme :
(define (interval-list m n)
(if (> m n)
’() (cons m (interval-list (+ 1 m) n)))) (define (sieve L)
(define (remove-multiples n L)
(if (null? L)
’() (if (= (modulo (car L) n) 0) ; division test
(remove-multiples n (cdr L)) (cons (car L)
(remove-multiples n (cdr L)))))) (if (null? L)
’()
Trang 12(sieve (remove-multiples (car L) (cdr L)))))) (define (primes<= n)
(sieve (interval-list 2 n))) (primes<= 500)
> ’(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67
71 73 79 83 89 97 101 103 107 109 113 127 131 137 139
149 151 157 163 167 173 179 181 191 193 197 199 211 223
227 229 233 239 241 251 257 263 269 271 277 281 283 293
307 311 313 317 331 337 347 349 353 359 367 373 379 383
389 397 401 409 419 421 431 433 439 443 449 457 461 463
467 479 487 491 499)
Trang 13Phần III BÀI TOÁN LẬP TRÌNH PROLOG
Đề tài: Cài đặt thuật toán tìm ước số chung lớn nhất sử dụng thuật toán Euclide (Euclidean Algorithm)
Hàm gcd tìm ước số chung lớn nhất của hai số
Cách 1:
gcd(A,B,GCD):-A=B,GCD=A
gcd(A,B,GCD):-A<B,
NB is B-A, gcd(A,NB,GCD)
gcd(A,B,GCD):-A>B,
NA is A-B, gcd(NA,B,GCD)
?- gcd(3,5,N)
N=1
Yes
?- gcd(4,6,N)
N=2
Yes
?- gcd(8,9,N)
N=1
Trang 14?- gcd(5,15,N).
N=5
Yes
Cách 2:
ucln(A,0,A)
ucln(A,B,N):-A<0,
NA is -A,
ucln(NA,B,N)
ucln(A,B,N):-B<0,
NB is -B, ucln(A,NB,N)
ucln(A,B,N):-A<B,
ucln(B,A,N)
ucln(A,B,N):-D is (A mod B),
ucln(B,D,N).?
ucln(4,5,N)
N=1
Yes
?- ucln(6,8,N)
N=2
Trang 15?- ucln(4,8,N)
N=4
Yes
?- ucln(4,8,4)
Yes
?- ucln(4,8,7)
ERROR: mod/2: Arithmetic: evaluation error: `zero_divisor`
^ Exception: (9) _G262 is 4 mod 0 ? creep
Exception: (6) ucln(4, 8, 7) ? creep?- ucln(3,4,1)
Yes
?- ucln(3,4,2)
ERROR: mod/2: Arithmetic: evaluation error: `zero_divisor`
^ Exception: (10) _G265 is 1 mod 0 ? creep
Exception: (6) ucln(3, 4, 2) ? creep
Trang 16TÀI LIỆU THAM KHẢO
[1] PGS TS Phan Huy Khánh – Lập trình hàm - Nhà xuất bản Khoa học
kỹ thuật
[2] PGS TS Phan Huy Khánh – Lập trình Logic trong Prolog - Nhà xuất
bản Đại học Quốc gia Hà Nội, 2004
[3] Đinh Mạnh Tường – Trí Tuệ nhân tạo - Nhà xuất bản Khoa học kỹ
thuật
[4] Các tài liệu trên Internet