You are on page 1of 29

MỤC LỤC

CHƯƠNG 1. MÁY TURING VÀ THUẬT TOÁN................................................1

1. Mô tả và định nghĩa về máy Turing..............................................................1


1.1. Mô tả phi hình thức về máy turing .....................................................................1
1.2. Định nghĩa hình thức của máy Turing (máy Turing đơn băng – Single tape
Turing machine) ........................................................................................................3
1.4. Ví dụ về máy Turing...........................................................................................4
1.5. Sơ đồ chuyển vị cho máy Turing .......................................................................5
2. Giới thiệu về máy Turing phổ dụng .............................................................6
3. Máy turing với biểu diễn thuật toán...........................................................10
3.1. Khái niệm thuật toán .......................................................................................10
3.2. Biểu diễn thuật toán một cách hình thức bằng máy Turing..............................11
CHƯƠNG 2. TÍNH KHẢ QUYẾT CỦA THUẬT TOÁN............................16
1. Tổng quan về tính khả quyết của thuật toán..............................................16
2. Luận đề Church-Turing..............................................................................17
3. Các chương trình như các bộ nhận dạng ngôn ngữ...................................18
3.1. Các chương trình và máy Turing.....................................................................20
3.2. Các hàm tính toán..............................................................................................20
4. Máy Turing và vấn đề khả quyết................................................................22
4.1. Các tập đệ quy kể được và khả quyết................................................................22
4.1.1. Một số định nghĩa...........................................................................................22
4.1.2. So sánh RE và tính khả quyết.........................................................................22
4.1.3. Tính kể được...................................................................................................23
4.2. Các ngôn ngữ đệ quy liệt kê .............................................................................24
4.2.1. Ngôn ngữ đệ quy............................................................................................24
4.2.2. Ngôn ngữ đệ quy liệt kê ................................................................................24
4.3. Các bài toán khả quyết .....................................................................................24
5. Một số vấn đề máy Turing không giải được...............................................26
5.1. Bài toán in (printing problem) và bài toán dừng(halting problem)...................26
5.2. Hàm dừng..........................................................................................................26
5.3. Entscheidungsproblem......................................................................................26
TÀI LIỆU THAM KHẢO...............................................................................28
...........................................................................................................................28
Máy Turing và tính khả quyết của thuật toán 1

CHƯƠNG 1. MÁY TURING VÀ THUẬT TOÁN

1. Mô tả và định nghĩa về máy Turing


1.1. Mô tả phi hình thức về máy turing
Khái niệm của máy Turing dựa trên ý tưởng của một người đã thực hiện một
thủ tục rất rõ ràng bằng cách thay đổi những nội dụng của một băng giấy vô hạn, mà
nó được phân thành các ô vuông có thể chứa một trong các tập hữu hạn các ký hiệu.
Người này cần nhớ một trong các tập trạng thái hữu hạn và một thủ tục được trình
bày trong nhiều bước cơ bản dưới dạng “Nếu trạng thái của bạn là 42 và ký hiệu mà
bạn thấy là ‘0’ thì thay thế nó bằng ‘1’, di chuyển một ký hiệu sang phải, và thừa
nhận rằng trạng thái 17 như một trạng thái mới của bạn”.

Trong một số mô hình, đầu đọc (head) di chuyển dọc theo băng tĩnh
(Stationary tape). Chỉ thị để được thực hiện (q1) được chỉ ra bên trong đầu đọc.
Trong mô hình này, băng trống là tất cả các ô bằng 0. Các ô vuông được tô đậm,
gồm ô đã được quét qua bởi đầu đọc, và các ô vuông được đánh dấu 1, 1, B và biểu
tượng đầu đọc, tạo thành trạng thái của hệ thống.
Một cách rõ ràng hơn, có thể hình dung một máy Turing sẽ bao gồm các
thành phần sau:
• Một băng (TAPE), hay còn gọi là một bộ nhớ vô hạn, dưới dạng một
băng gồm nhiều ô, có thể kéo dài vô hạn về phía phải. Mỗi ô trên băng có
thể chứa một ký hiệu thuộc một bộ chữ, gọi là bộ chữ trên băng (mà một
phần trong đó là bộ chữ vào, dùng cho xâu vào);
• Một đầu đọc (HEAD) di chuyển ở trên băng, ở mỗi thời điểm nhìn
vào một ô trên băng;
• Một tập hữu hạn các trạng thái, trong đó có phân biệt một trạng thái
đầu và một tập hợp các trạng thái đã được thừa nhận;
• Một hàm dịch chuyển chứa một tập hữu hạn chỉ thị cho phép cứ với
mỗi trạng thái của máy và một ký hiệu đọc được trong ô đối diện với đầu
đọc, máy sẽ thực hiện các bước như sau:
o Chuyển trạng thái
o In một ký hiệu trên băng tại ô đang duyệt (nghĩa là
thay ký hiệu đọc được trên băng bằng ký hiệu nào đó)
Máy Turing và tính khả quyết của thuật toán 2

o Dịch chuyển đầu đọc - viết (sang trái (L), sang phải
(R) hoặc đứng yên(∅))

a1 a1 … … a1 B B

Băng
Đầu đọc

q
Trạng thái

Hình 1. Các bộ phận của máy Turing


• Các thao tác có thể của một máy Turing (thường gọi là các thao
tác nguyên tử - Atomic operations)
• Đọc (xác định) ký hiệu hiện tại mà đầu đọc đang trỏ tới
• Viết một ký hiệu lên ô vuông hiện tại mà đầu đọc đang trỏ tới (sau khi
xóa lần đầu tiên ký hiệu vừa được ghi ở đó)
• Di chuyển băng sang trái một ô
• Di chuyển băng sang phải một ô
• Thay đổi trạng thái
• Ngắt
Máy Turing và tính khả quyết của thuật toán 3

• Quá trình thực hiện của máy Turing có thể được mô tả như sau:
• Lúc khởi đầu, xâu vào được đặt trên băng (tận cùng bên trái). Mọi ô
khác trên băng đều chứa một ký hiệu đặc biệt, B (blank), được gọi là ký
hiệu trống. Đầu đọc trỏ vào ô thứ nhất trên băng và máy ở trạng thái đầu.
• Cứ mỗi bước trong quá trình thực hiện (xem hình 2), máy sẽ thực
hiện:
o Đọc ký hiệu đối diện đầu đọc,
o Thay ký hiệu đó bằng ký hiệu tính được từ hàm dịch chuyển,
o Dời đầu đọc một ô sang trái hay sang phải theo hướng chỉ định bởi
hàm dịch chuyển,
o Đổi trạng thái hiện tại thành trạng thái tiếp theo, cho bởi hàm dịch
chuyển.
• Xâu vào là được thừa nhận khi quá trình thực hiện đối với xâu đó đạt
đến một trạng thái thừa nhận.

0 1 0 1 1 B B

0 1 1 1 1 B B

Hình 2. Một bước dịch chuyển


1.2. Định nghĩa hình thức của máy Turing (máy Turing đơn băng –
Single tape Turing machine)
Sự mô tả máy Turing một cách trực quan như ở phần 1 đã giúp chúng ta
bước đầu dễ dàng hình dung ra sự hoạt động của nó. Tuy nhiên, một sự mô tả phi
hình thức như thế là chưa đủ chặt chẽ để có thể tiến hành sự suy diễn toán học,
nhằm đi sâu nghiên cứu về máy Turing được. Bởi vậy, ta cần có một định nghĩa
hình thức về máy Turing.
Theo Hopcroft và Ullman (1979) đã định nghĩa một cách hình thức một máy
Turing như là một bộ 7- M = < Q, Γ , b, ∑ , δ , q , F> trong đó:
0
Máy Turing và tính khả quyết của thuật toán 4

• Q là một tập hữu hạn các trạng thái,


• Γlà bộ chữ trên băng (bộ chữ dùng trên băng),
• b ∈ Γlà ký hiệu trống (ký hiệu duy nhất cho phép xuất hiện một cách
vô hạn trên băng ở bất kỳ bước nào trong quá trình tính toán),

• ∑ ⊆ Γlà bộ chữ vào (bộ chữ dùng cho xâu vào),


• δ : Q x Γ → Q x Γ x {L, R} là một hàm bộ phận, hay còn gọi là
hàm dịch chuyển (là hàm định nghĩa các việc dịch chuyển trạng thái của
máy Turing hoặc máy trạng thái), trong đó L và R được hiểu là trái (Left)
và phải (Right)).
• q0 ∈ Q là trạng thái đầu (trạng thái khởi tạo),
• F ⊆ Q là tập các trạng thái thừa nhận – accepting state (hoặc trạng
thái cuối).
1.4. Ví dụ về máy Turing
Dưới đây là ví dụ về máy Turing ứng đụng trong việc chấp nhận các tập.
Ví dụ 1. Thiết kế máy Turing chấp nhận ngôn ngữ L = { 0n1n | n ≥ 1}
Khởi đầu, máy Turing chứa 0n1n bên trái nhất trên băng sau đó là vô hạn
khoảng trống Blank. Máy Turing lặp lại quá trình sau:
 M thay 0 bên trái nhất bằng X rồi chuyển sang phải tới 1
trái nhất, máy Turing thay 1 này bằng Y rồi dịch chuyển về bên trái cho
tới khi gặp X phải nhất nó chuyển sang phải một ô (tới 0 trái nhất) rồi tiếp
tục lặp một chu trình mới.
 Nếu trong khi dịch chuyển sang phải để tìm 1 mà máy
Turing gặp Blank thì máy Turing dừng và không chấp nhận input. Tương
tự, khi máy Turing đã thay hết 0 bằng X và kiểm tra còn 1 trên băng thì
máy Turing cũng dừng và không chấp nhận input.
 Máy Turing chấp nhận input nếu như cũng không còn
ký hiệu 1 nào nữa trên băng.

Đặt máy Turing M = < Q, Γ , b, ∑ , δ , q , F> với các thành phần :


0

Q = {q0, q1, q2, q3, q4}; ∑= {0, 1}; Γ = {0, 1, X, Y, B} và F = {q4}.


Ta có thể hình dung mỗi trạng thái là một câu lệnh hoặc một nhóm các câu
lệnh trong chương trình. Trạng thái q0 là trạng thái khởi đầu và nó làm cho ký hiệu
0 bên trái nhất thay bằng X. Trạng thái q1 được dùng để tiến sang phải bỏ qua các số
0 và Y để tìm 1 bên trái nhất. Nếu M tìm thấy 1 nó thay 1 bằng Y rồi đi vào trạng
thái q2. Trạng thái q2 đưa M tiến sang trái cho tới X đầu tiên và đi vào trạng thái q0,
dịch chuyển sang phải để tới 0 bên trái nhất và tiếp tục một chu trình mới. Khi M
tiến sang phải trong trạng thái q1, nếu B hoặc X được tìm thấy trước 1 thì input bị
loại bỏ (không chấp nhận) vì có chứa nhiều ký hiệu 0 hơn 1 hoặc input không có
dạng 0*1* .
Máy Turing và tính khả quyết của thuật toán 5

Trạng thái q0 còn có vai trò khác. Nếu trạng thái q2 tìm thấy X bên phải nhất
và ngay sau đó là Y thì các số 0 đã được xét hết, do đó ở trạng thái bắt đầu một chu
trình mới q0 không tìm thấy ký hiệu 0 nào để thay thành X mà chỉ gặp Y thì máy
Turing đi vào trạng thái q3 duyệt qua các Y để kiểm tra có hay không có ký hiệu 1
còn lại. Nếu theo ngay sau các Y là B, nghĩa là trên băng nhập không còn ký hiệu 1
nào nữa thì máy Turing sẽ đi vào q4 (trạng thái kết thúc) để chấp nhận input. Ngược
lại input bị loại bỏ.
Ta có hàm chuyển δ được cho trong bảng sau :

Hình 4. Một máy Turing kiểm nhận {0n1n | n>=1}


Các phép chuyển hình thái của máy Turing M trên input 0011 :
q00011 ⊢ Xq1011 ⊢ X0q111 ⊢ X q20Y1 ⊢ q2X0Y1 ⊢ X q00Y1 ⊢ XXq1Y1
⊢ XXY q11 ⊢ XX q2YY ⊢ X q2XYY ⊢ XX q0YY ⊢ XXYq3Y ⊢
XXYYq3 ⊢ XXYYq4
1.5. Sơ đồ chuyển vị cho máy Turing
Chúng ta có thể biểu diễn các chuyển vị của một máy Turing một cách hình
ảnh. Một sơ đồ chuyển vị (transition diagram) bao gồm một tập các nút tương ứng
với các trạng thái của máy Turing. Một cung từ trạng thái q đến trạng thái p với
nhãn là một hoặc nhiều mục có dạng X/YD, trong đó X và Y là các ký hiệu băng, D
là một hướng (L hoặc R). Điều này có nghĩa là mỗi khi δ (q, Xi) = (p, Y, D), chúng
ta thấy nhãn X/YD trên cung từ q đến p. Tuy nhiên, trong sơ đồ của chúng ta,
hướng D được biểu diễn bằng các mũi tên chỉ sang trái ( ← ) hoặc chỉ sang phải ( →
).
Giống như các loại sơ đồ chuyển vị khác, chúng ta biểu diễn khởi trạng bằng
từ “start” và một mũi tên đi vào trạng thái đó. Kiểm trạng được chi ra bằng vòng
kép. Vì thế thông tin duy nhất của máy Turing không đọc trực tiếp được từ sơ đồ là
ký hiệu được dùng cho ô trống. Chúng ta sẽ xem như đó là B trừ khi được nói rõ.
Ví dụ 1: Hình 5 trình bày sơ đồ chuyển vị cho máy Turing ở ví dụ 1 vừa trình bày ở
trên, với hàm chuyển vị được cho trong hình 4.
Máy Turing và tính khả quyết của thuật toán 6

Hình 5. Sơ đồ chuyển vị cho một máy Turing kiểm nhận các chuỗi có dạng 0n1n
2. Giới thiệu về máy Turing phổ dụng
Máy Turing phổ dụng là một máy Turing có thể bắt chước sự hoạt động
của bất kỳ máy Turing nào. Máy Turing phổ dụng U có thể được hiểu như sau:
Với một cách mã hóa thích hợp, ánh xạ chuyển trạng thái của máy
Turing bất kỳ M và từ ω trên bảng chữ vào. Với từ đã mã hóa này máy
Turing phổ dụng U dừng khi và chỉ khi máy Turing M dừng với từ ω .

Hình 6. Máy Turing phổ dụng


Chúng ta có thể xem máy Turing phổ dụng như là mô hình toán học của máy
tính điện tử ngày hôm nay. Các máy này thực hiện công việc bằng cách mã hóa
chương trình theo ngôn ngữ bên trong được gọi là ngôn ngữ máy.
Tập các kí hiệu có thể ghi lên băng là hữu hạn nên ta có thể ký hiệu chúng
như sau: S0 = B, S1, S2, ..., Sm và có thể mã hóa bằng bộ các chữ số 1. Chẳng hạn:
B – 1, S1 – 11, S2 – 111, ..., Sm – 1m+1.
Tương tự như vậy, tập các trạng thái là hữu hạn và ta cũng có thể mã hóa
chúng như sau:
q0 – 1, q1 – 11, q2 – 111, ..., qn – 1n+1.
Máy Turing và tính khả quyết của thuật toán 7

Cuối cùng hai ký hiệu L và R cũng có thể được mã hóa L – 1 và R – 11.


Bây giờ, để mã hóa ánh xạ chuyển trạng thái của máy Turing, ta sử dụng
bảng biểu diễn ánh xạ này. Trong bảng các cột được ký hiệu bởi các ký hiệu có thể
ghi lên băng vào, các dòng được ký hiệu bởi các trạng thái. Tiếp theo, liệt kê các
phần tử của bảng theo dòng cùng với các chỉ số dòng và cột tương ứng của chúng:
Các phần tử của dòng 1, tiếp đến các phần tử của dòng 2, ... Chẳng hạn, trên một
dòng xuất hiện bộ <qi, Sj, Sk, D, qh> có nghĩa là δ (qi, Sj) = <qh, Sk, D>. Giữa các
dãy mã của các bộ 5 <qi, Sj, Sk, D, qh> có chèn hai ký hiệu 0 và giữa mã các ký hiệu
trong bộ 5 được chèn bởi một ký hiệu 0. Máy Turing M được mã hóa như vậy có ký
hiệu là [M].
Ở đây, chúng ta thừa nhận mà không chứng minh rằng: Với một máy Turing
M bất kỳ tồn tại một máy Turing tương đương chỉ có một trạng thái kết thúc. Vì
vậy, chúng ta có quyền giải thiết q0 là trạng thái đầu và q1 là trạng thái kết thúc duy
nhất của máy Turing M.
Ví dụ 2. Cho máy Turing M với ánh xạ chuyển trạng thái được cho bởi bảng sau:

B S1

q0 <S1, R, q1> <S1, R, q0>

q1 <S1, R, q2>

q2 <S1, R, q2>

Các phần tử của mảng được sắp xếp thành dãy dưới đây :
<q0, B, S1, R, q1> <q0, S1, S1, R, q0>
<q1, S1, S1, R, q2> <q2, S1, S1, R, q2>
Dãy này sẽ được mã hóa dưới dạng dãy số 0, 1.
[M] = 01010110110010110110110100110110110101
1100111011011010111
<q0, B, S1, R, q1> <q0, S1, S1, R, q0> <q1, S1, S1, R, q2> <q2, S1, S1, R, q2>
Nếu trên băng vào có ω = S1S1BS1, thì mã tương ứng của nó sẽ là:
[ ω ] = 1101101011
Với [M] và [ ω ] đã cho ta có thể dịch ra M và từ ω như sau:
M = < {q0, q1, q2}, {S1}, B, {S1, B}, q0, {q1}>
Trong đó:
δ (q0, B) = <S1, R, q1>,
δ (q0, S1) = <S1, R, q0>
δ (q0, S1) = <S1, R, q2>
δ (q0, S1) = <S1, R, q2>
Máy Turing và tính khả quyết của thuật toán 8

và ω =S1S1BS1
Bây giờ giả sử máy Turing M có n trạng thái trong và bảng chữ ghi lên băng
có m ký hiệu, thêm vào đó các ký hiệu, các trạng thái, và ánh xạ chuyển trạng thái
của M được mã hóa như đã nói ở trên. Mô hình hóa hoạt động của máy Turing M
bằng một máy Turing phổ dụng U có thể mô tả khái quát như sau:
Trước hết [M] và [ ω ] cần phải được ghi lên băng của máy Turing phổ
dụng U theo quy cách sau đây: Ký hiệu X được ghi lên băng, chia băng
thành 2 nửa vô hạn. Nửa băng bên phải được dành ra 3 đoạn kề nhau kể
từ vị trí ký hiệu ngay sau X: Đoạn đầu tiên được gọi là Buffer gồm n + m
+ 2 vị trí ký hiệu và tất cả đều được nhận ký hiệu 0; đoạn tiếp theo được
gọi là vùng mã hóa của M, bắt đầu bởi ký hiệu Y, tiếp sau Y là [M] và
được kết thúc bởi 3 chữ số 0 ; đoạn sau cùng được gọi là đoạn mã hóa
của ω , bắt đầu bởi ký hiêu Z và tiếp theo là [ ω ]. Hình ảnh của băng lúc
đầu như sau:

B X 0 . . . Y . . . 0 0 0 Z . . . B B

Buffer Mã hóa M Mã hóa

Hình 7. Hình ảnh của Băng lúc đầu


Buffer phục vụ cho việc ghi nhận nhận cấu hình của M trong từng bước.
Chúng ta có thể sao chép vào vùng này trạng thái bên trong và mã hóa
của ký hiệu đang đọc. Ký hiệu Y thường đứng trước bộ 5 xác định trạng
thái hiện hành của M, ký hiệu hiện hành hành trên băng, hướng chuyển
động của đầu đọc trên băng. Z đánh dấu ký hiệu đang đọc trên băng của
M.
Quá trình tính toán trong U mô phỏng hoạt động của máy Turing M với
xâu vào ω được chia ra các pha thích hợp với việc dịch chuyển các cấu
hình của M.
Một giai đoạn (pha) hoạt động của máy Turing phổ dụng U có thể được tóm
tắt như sau:
Đầu tiên sao chép vào buffer một khối các ký hiệu 1 nằm ngay sau Y (gọi
là khối Y), sau đó ghi vào cuối khối vừa được chép một ký hiệu X, tiếp
theo xóa ký hiệu Y, chạy sang phải tìm ký hiệu Z và sao chép khối ký
hiệu 1 ngay sau Z (gọi là khối Z) vào buffer ngay sau ký hiệu X rồi ghi
lại ký hiệu Y trước [M]. Như vậy, sau giải đoạn này, trong Buffer chứa
mã của trạng thái và ký hiệu hiện hành của máy Turing M. Bước tiếp
theo, máy Turing phổ dụng U so sánh 2 khối ký hiệu 1 liên tiếp nhau sau
Y với nội dung buffer. Nếu trùng nhau thì tìm được bộ 5 cần tìm. Nếu
ngược lại, thì tìm đến mã hóa của bộ 5 tiếp theo sau Y và lại tiếp tục so
sánh. Trong trường hợp giữa các bộ 5 mô tả M không tìm thấy bộ nào
thích hợp thì U dừng. Ngược lại, nếu tìm được bộ 5 cần tìm thì xóa nội
dung buffer rồi chuyển Y đến trước phần tử thứ 3 trong bộ 5 đó. Đổi nội
Máy Turing và tính khả quyết của thuật toán 9

dung của khối sau Z bởi nội dung của khối sau Y và chuyển Y đến trước
phần tử thứ tư của bộ 5. Sau khi đã đọc xong phần tử thứ tư mà nó xác
định hướng chuyển động của đầu đọc/ghi của M và U chuyển ký hiệu Y
đến sau phần tử trước phẩn tử thứ 5. Tùy thuộc vào nội dung của khối thứ
4 (một ký hiệu 1 hay hai ký hiệu 1) mà U sẽ chuyển Z qua phải hay qua
trái một khối. Nếu Z lúc đầu nằm ở tận cùng bên trái của băng ghi và M
cần dịch chuyển sang phải thì U đẩy mã của từ sang phải và ghi mã hóa
của ký hiệu trắng vào sau Z. Nếu Z nằm tận cùng bên phải và cần chuyển
sang phải thì khi đó U ghi mã của ký hiệu trắng vào cuối từ. Khi hoàn
thành các công việc trên khối ký hiệu 1 đứng sau Y ký hiệu trạng thái
hiện hành của M, còn khối sau Z xác định ký hiệu M cần đọc tiếp theo.
Như vậy, giai đoạn tiếp theo của việc mô phỏng bước tiếp theo của M có
thể bắt đầu.
Các giai đoạn hoạt động của máy Turing phổ dụng U mô hình hóa hoạt động
từng bước của máy Turing M như đã chỉ ra ở trên. Ngoài ra, U còn thực hiện công
việc sau đây:
Đầu tiên U thay tất cả các ký hiệu 0 trên 3 đoạn của băng vào bằng các
khoảng trắng, cuối công việc, khi M dừng máy U còn kiểm tra liệu trạng
thái cuối của M có phải là trạng thái kết thúc hay không.
Các pha của một máy Turing phổ dụng U được chia thành 9 phần như sau:
• Phần 1. Thay các ký hiệu 0 bởi ký hiệu B và đầu đọc/ghi chuyển đến
trước Y.
• Phần 2. Sao chép mã của trạng thái hiện hành vào buffer.
• Phần 3. Sao chép mã của ký hiệu cần đọc trên băng của M vào buffer.
• Phần 4. Đặt X và Y vào trước buffer và trước vị trí của [M].
• Phần 5. Tìm bộ 5 có mã của trạng thái và ký hiệu trên băng trùng với
buffer.
• Phần 6. Xóa buffer
• Phần 7. Thay mã ký hiệu đã đọc bằng mã ký hiệu mới của M.
• Phần 8. Đẩy Z sang phải hay sang trái một khối mà mã ký hiệu của
khối đó sẽ được đọc trong pha tiếp theo. Nếu cần thì ghi mã một khoảng
trắng vào phải hoặc trái từ trên băng M.
• Phần 9. Máy Turing phổ dụng U dừng ở trạng thái kết thúc khi và chỉ
khi M dừng ở trạng thái kết thúc. Đồng thời trong vùng mã hóa của từ
trên băng sẽ chứa mã của từ đáng ra còn lại trên băng của M, còn mã của
trạng thái cuối của M có thể thấy trên buffer.
Chúng ta ký hiệu <M ω > là [M] và [ ω ] được ghi trên băng của U và gọi
T(U) là ngôn ngữ được chấp nhận bởi máy Turing phổ dụng U. Chúng ta có thể
nhận thấy rằng <M ω > thuộc T(U) khi và chỉ khi ω được chấp nhận bởi M, có
nghĩa là:
T(U) = {<M ω > : ω ∈ T(M)}
Máy Turing và tính khả quyết của thuật toán 10

3. Máy turing với biểu diễn thuật toán


3.1. Khái niệm thuật toán
Trong vòng 200 năm qua, vẫn chưa một một định nghĩa về thuật toán được
chấp nhận một cách rộng rãi. Tuy nhiên, phần lớn các nhà nghiên cứu trong các lĩnh
vực toán học, tính toán, và các chuyên ngành liên quan đều thống nhất rằng thuật
toán là một quá trình (một tập hữu hạn các lệnh hay phương cách được định nghĩa
rõ ràng) để hoàn thành một số tác vụ nào đó, với một trạng thái ban đầu cho trước,
khi các lệnh này được áp dụng triệt để thì sẽ kết thúc tại một trạng thái kết thúc
được đã được định nghĩa. Nói cách khác, thuật toán là một bộ các qui tắc hay qui
trình cụ thể nhằm giải quyết một vấn đề trong một số bước hữu hạn, hoặc nhằm
cung cấp một kết quả từ một tập hợp của các dữ kiện đưa vào.
Việc nghiên cứu thuật toán là một trong những lĩnh vực nền tảng của khoa
học máy tính. Thông qua việc xây dựng một chương trình máy tính nhằm giải quyết
một bài toán cụ thể, người lập trình đã biểu diễn bằng ngôn ngữ máy tính một thuật
toán giải bài toán, qua đó điều chỉnh thuật toán thành một chương trình máy tính.
Nhiều thuật toán rất hữu dụng trong nhiều ứng dụng máy tính đa dạng.
Những thuật toán cơ sở này được nghiên cứu rộng rãi và được xem là một thành
phần thiết yếu của khoa học máy tính, bao gồm các thuật toán sắp xếp, tìm kiếm, xử
lý chuỗi, đồ thị, thực hiện các phép tính toán toán học phổ biến, …
Ví dụ 3. Thuật toán để giải phương trình bậc nhất P(x): ax + b = c, (a, b, c là các
số thực), trong tập hợp các số thực có thể là một bộ các bước sau đây:
1. Nếu a = 0
o b = c thì P(x) có nghiệm bất kì
o b ≠ c thì P(c) vô nghiệm
2. Nếu a ≠ 0
o P(x) có duy nhất một nghiệm x = (c - b)/a
Knuth (1968, 1973) đã đưa ra một danh sách 5 thuộc tính được thừa nhận
rộng rãi như là các yêu cầu của một thuật toán:
o Tính hữu hạn: “Một thuật toán luôn phải dừng sau một số hữu hạn
bước … một số hữu hạn có thể chấp nhận được”. Các thuật toán cần
được tạo thành từ một tập hữu hạn các thao tác và phải hoàn thành
việc thực hiện trong một thời gian hữu hạn.
o Tính tường minh: “Từng bước của thuật toán phải được định nghĩa
chính xác, các hành động được thực hiện phải chặt chẽ và được xác
định không nhập nhằng cho từng trường hợp”. Cụ thể là bất kỳ những
bước điều kiện nào cũng phải được xử lý một cách có hệ thống theo
từng trường hợp với tiêu chí là từng trường hợp phải rõ ràng (và có
thể tính được). Ngoài ra, vì một thuật toán là một tập các thao
tác/lệnh, chúng ta phải biết trật tự đúng để thực hiện các thao tác.
Nếu trật tự không rõ ràng, chúng ta có thể thực hiện các thao tác sai
hay không chắc chắn thao tác nào sẽ được thực hiện tiếp theo.
Máy Turing và tính khả quyết của thuật toán 11

o Đầu vào: “… định lượng cần được gán lúc ban đầu trước khi thuật
toán bắt đầu. Những đầu vào này được lấy ra từ một tập các đối tượng
xác định”
o Đầu ra: “… định lượng có một quan hệ xác định với đầu ra”. Và các
thuật toán phải đưa ra các kết quả cụ thể, qua đó có thể xác định các
kết quả đó là đúng hay sai.
o Tính hiệu quả: “… tất cả các thao tác cần thực hiện trong thuật toán
phải được đảm bảo về nguyên tắc có thể được thực hiện một cách
chính xác và trong một khoảng thời gian hữu hạn”. Những thao tác
toán học như tìm căn bậc hai của một số âm sẽ là thao tác không hiệu
quả, do đó không thể được sử dụng trong các thuật toán
Thuật toán có thể được biểu diễn bằng nhiều cách, bao gồm ngôn ngữ tự
nhiên, giả mã, ngôn ngữ lưu đồ (sơ đồ khối), ngôn ngữ lập trình. Tuy nhiên, một khi
dùng ngôn ngữ lập trình thì chỉ những lệnh được phép trong ngôn ngữ đó mới có
thể dùng được và điều này thường làm cho sự mô tả các thuật toán trở nên rối rắm
và khó hiểu. Hơn nữa, vì nhiều ngôn ngữ lập trình đều được dùng rộng rãi, nên chọn
một ngôn ngữ đặc biệt nào đó là điều người ta không muốn. Vì vậy ở đây các thuật
toán ngoài việc được trình bày bằng ngôn ngữ tự nhiên cùng với những ký hiệu toán
học quen thuộc còn dùng một dạng giả mã để mô tả thuật toán. Giả mã tạo ra bước
trung gian giữa sự mô tả một thuật toán bằng ngôn ngữ thông thường và sự thực
hiện thuật toán đó trong ngôn ngữ lập trình. Các bước của thuật toán được chỉ rõ
bằng cách dùng các lệnh giống như trong các ngôn ngữ lập trình.
3.2. Biểu diễn thuật toán một cách hình thức bằng máy Turing
Máy Turing là một thành phần rất quan trọng trong nền khoa học của thế kỷ
XX, một phần vì máy Turing đóng vai trò trung tâm trong lý thuyết về tính toán và
khả năng tính toán. Đặc biệt, máy Turing không chỉ được quan tâm như là một bộ
chấp nhận ngôn ngữ mà còn cung cấp một định nghĩa nghiêm ngặt về thuộc tính
hay phương pháp.
Có thể nói các thuật toán rất cần thiết cho máy tính xử lý thông tin, vì một
chương trình máy tính cần là một thuật toán chỉ ra cho máy tính các bước cụ thể nào
cần thực hiện (theo trật tự nào) nhằm thực hiện một tác vụ cụ thể với mục đích
chính của một máy tính là biến đổi input thành output.
Thông thường, khi một thuật toán được kết hợp với thông tin xử lý, dữ liệu
được đọc từ một nguồn hay thiết bị đầu vào, được viết trên một thiết bị đầu ra,
và/hoặc được lưu trữ cho các xử lý tiếp sau. Dữ liệu được lưu trữ được xem là một
phần của trạng thái bên trong của thực thể thực hiện thuật toán. Trên thực tế, trạng
thái được lưu trong một cấu trúc dữ liệu, nhưng một thuật toán chỉ yêu cầu dữ liệu
bên trong cho các tập thao tác xác định gọi là các kiểu dữ liệu trừu tượng. Trong đó,
một kiểu dữ liệu trừu tượng được định nghĩa là đặc tả của một tập dữ liệu và tập
thao tác có thể thực hiện trên dữ liệu. Kiểu dữ liệu này trừu tượng trên khía cạnh
độc lập với các thực thi cụ thể khác nhau.
Trong khi đó, một máy Turing có thể được biểu diễn như một hệ thống thực
hiện chức năng tự động có khả năng ở một số hữu hạn các trạng thái bên trong và
được hỗ trợ bởi một bộ nhớ bên ngoài vô hạn, gọi là băng (nhập/xuất). Trong đó,
Máy Turing và tính khả quyết của thuật toán 12

băng đóng vai trò là phương tiện lưu trữ có mục đích tổng quát của máy Turing:
máy được thiết lập ở trạng thái chuyển động với các đầu vào là nội dung cụ thể thời
điểm khởi đầu băng chứa, đầu ra là nội dung cụ thể thời điểm kết thúc băng chứa,
và băng sẽ là bộ nhớ hoạt động tạm thời để lưu các kết quả của các bước trung gian
trong quá trình tính toán. Chương trình (bảng trạng thái) chỉ đạo quá trình tính cụ
thể mà máy sẽ thực hiện cũng được lưu trữ trên băng. Một chương trình nhỏ, cố
định được tích hợp sẵn trong đầu đọc sẽ hỗ trợ đầu đọc đọc và thực hiện các chỉ dẫn
của chương trình bất kỳ đang ở trên băng.
Trong bối cảnh đó, khái niệm máy Turing có thể được sử dụng để đảm bảo
mô hình hóa ý tưởng tổng quát của một thuật toán được chính xác với một bảng chữ
cái đã cho như sau:
• Input của một sự tính toán là tất cả các kí hiệu không trắng trên băng
tại thời điểm khởi đầu.
• Tại thời điểm kết thúc của sự tính toán, output sẽ là bất kì cái gì có
trên băng.

• Vậy có thể xem một máy Turing M như là một sự hiện thực của một
hàm f được định nghĩa bởi = f(w) trong đó q0w M qf với qf là một
trạng thái kết thúc nào đó.
• Lúc đó, một hàm f với miền xác định D được gọi là khả tính toán-
Turing hay đơn giản là khả tính toán nếu tồn tại một máy Turing nào đó
M = < Q, Γ , b, ∑ , δ , q , F>
0 sao cho q0w M qf f(w), qf ∈F,
∀w ∈ D.
Ví dụ 4. Xét bài toán cộng hai số nguyên viết ở dạng nhị phân f(x, y) = x + y . Thủ
tục thực hiện phép cộng có thể dựa trên phương pháp thông thường là cộng cặp chữ
số nhị phân với nhau (có nhớ) để tính tổng của hai số nguyên.
Để cộng a và b, trước hết cộng hai bit ở phải cùng của chúng, tức là:
a0 + b0 = c0.2 + s0.
Ở đây s0 là bit phải cùng trong khai triển nhị phân của a+b, c 0 là số nhớ, nó
có thể bằng 0 hoặc 1. Sau đó ta cộng hai bit tiếp theo và số nhớ
a1 + b1 + c0 = c1.2 + s1.
Ở đây s1 là bit tiếp theo (tính từ bên phải) trong khai triển nhị phân của a+b
và c1 là số nhớ. Tiếp tục quá trình này bằng cách cộng các bit tương ứng trong hai
khai triển nhị phân và số nhớ để xác định bit tiếp sau tính từ bên phải trong khai
triển nhị phân của tổng a+b. Ở giai đoạn cuối cùng, cộng an-1, bn-1 và cn-2 để nhận
Máy Turing và tính khả quyết của thuật toán 13

được cn-1.2+sn-1. Bit đứng đầu của tổng là sn=cn-1. Kết quả, thủ tục này tạo ra được
khai triển nhị phân của tổng, cụ thể là a+b = (sn sn-1 sn-2 ... s1 s0)2.
Triển khai thuật toán này với máy Turing, chúng ta phải quyết định các số x
và y vào lúc ban đầu được đặt như thế nào trên băng và tổng của chúng xuất hiện
như thế nào lúc kết thúc sự tính toán.
• Chúng ta giả thiết rằng w(x) và w(y) được phân cách bằng một kí hiệu
, với đầu đọc ở trên kí tự phải cùng của w(y).

• Chúng ta vì vậy muốn thiết kế một máy Turing để thực hiện sự tính
toán (trong đó qf là một trạng thái kết thúc)
q0w(x) w(y) M qf w(x + y) ,

Q = {q0, q1, q2, q3,…., q9, qf}, F = {qf}


Với bảng trạng thái được cho bởi đồ thị trạng thái như sau:

• Sau khi tính toán, w(x + y) sẽ ở trên băng và được theo sau bởi một kí
tự , và đầu đọc sẽ được đặt trên kí tự phải cùng của kết quả.

Như trên, chúng ta đã thấy máy Turing có thể thực hiện được các phép toán
cơ bản và quan trọng những cái mà có trong tất cả các máy tính. Vì trong các máy
tính số, các phép toán cơ bản như vậy là các thành phần cơ bản cho các lệnh phức
tạp hơn, sau đây là một ví dụ trình bày khả năng máy Turing kết hợp các phép toán
này lại với nhau.
Giả sử chúng ta thiết kế máy Turing tính toán hàm sau:
Máy Turing và tính khả quyết của thuật toán 14

Ta xây dựng mô hình tính toán như sau:

Vấn đề xây dựng được hàm tính toán được yêu cầu của chúng ta bây giờ sẽ
được chuyển thành xây dựng các bộ so sánh, bộ cộng và bộ xóa. Điều này cũng có
nghĩa rằng bài toán phức tạp của chúng ta đã được chuyển thành kết hợp các phép
toán cơ bản.
Với khá nhiều bằng chứng mạnh mẽ tuy chưa đủ là một chứng minh chặt
chẽ, nhưng chúng ta chấp nhận miêu tả chính xác của ý tưởng tổng quát về thuật
toán trong một bộ chữ cái được thực hiện bởi máy Turing là hoàn toàn đầy đủ. Có
nghĩa rằng, đối với mọi thuật toán trong bảng chữ cái cụ thể, có thể xây dựng một
thuật toán Turing cho cùng các kết quả với cùng dữ liệu ban đầu như thuật toán .
Sự chấp nhận này được gọi là luận đề Turing trong lý thuyết thuật toán, như một
định nghĩa của một “sự tính toán cơ học”. Cụ thể,
• Bất kỳ cái gì có thể được thực hiện trên bất kỳ máy tính số đang tồn
tại nào đều có thể được thực hiện bởi một máy Turing.
• Không ai có thể đưa ra một bài toán, có thể giải quyết được bằng
những gì mà một cách trực quan chúng ta xem là một thuật toán, mà đối
với nó không tồn tại máy Turing nào giải quyết được.
• Các mô hình thay thế khác có thể được đưa ra cho sự tính toán cơ học
nhưng không có cái nào trong số chúng là mạnh hơn mô hình máy
Turing.
Bằng việc chấp nhận luận đề Turing, chúng ta sẵn sàng để định nghĩa chính
xác khái niệm thuật toán, một khái niệm cơ bản trong khoa học máy tính.
Một thuật toán cho một hàm f: D → R là một máy Turing M sao cho cho một
chuỗi nhập w∈D trên băng nhập, cuối cùng M dừng với kết quả f(w) ∈R trên băng.
Một cách cụ thể là:
q0w M qf f(w), qf ∈F, ∀w ∈ D.

Luận đề Turing ngay lập tức được chấp nhận rộng rãi. Thông qua việc thực
hiện các phép tính dựa trên một kế hoạch được chọn trước, các nhà khoa học đã tiến
hành theo một cách tương đương với máy Turing: xem xét một số vị trí trong bài
viết của mình và ở trong một “trạng thái trí tuệ”nhất định, họ tiến hành sửa đổi
Máy Turing và tính khả quyết của thuật toán 15

trong bài viết của mình và được thúc đẩy bởi một “trạng thái trí tuệ” mới, sẽ
chuyển sang suy ngẫm về các phần viết sau.
Tóm lại, một thuật toán có thể được xem là một chuỗi các thao tác có thể
được thực hiện bởi một hệ thống Turing-đầy đủ (Turing complete) (còn được gọi
là Turing-tương đương (Turing equivalent) hay phổ dụng ((computationally)
universal). Trong đó, một máy trừu tượng hay ngôn ngữ lập trình được gọi là
Turing-đầy đủ nếu có khả năng tính toán tương đương một mô hình được đơn giản
hóa của máy tính có khả năng lập trình, đó chính là máy Turing phổ dụng.
“Lý luận không hình thức của Turing trong luận đề của ông đã giải thích cho một
luận đề mạnh hơn: Mọi thuật toán có thể được mô phỏng bởi một máy Turing”
Gurevich (2000)
Còn theo Savage [1987], “Một thuật toán là một quá trình tính được định nghĩa
bởi một máy Turing”
Máy Turing và tính khả quyết của thuật toán 16

CHƯƠNG 2. TÍNH KHẢ QUYẾT CỦA THUẬT TOÁN

1. Tổng quan về tính khả quyết của thuật toán


Trong phần này, chúng ta sẽ tìm hiểu về một trong nền tảng khoa học cơ bản
nhất của khoa học máy tính, đó là tính khả quyết của bài toán. Đó là “Những vấn
đề nào có thể và không thể thực hiện được bởi thuật toán hay máy tính?”
Trong lý thuyết tính toán, một bài toán quyết định là một câu hỏi trong một
số hệ thống hình thức với các câu trả lời có/không. Ví dụ, bài toán “cho 2 số x và y,
x có chia hết y không?”. Câu trả lời sẽ là “có” hay “không”, phụ thuộc vào giá trị
của x và y.
Bên cạnh đó, các bài toán quyết định còn liên hệ mật thiết với các bài toán
hàm (function problem) có thể có các câu trả lời phức tạp hơn so với có/không. Một
bài toán hàm có thể là “cho 2 số x, y, tìm x có thể chia hết bởi y?”. Các bài toán
quyết định còn có thể quan hệ với các bài toán tối ưu, được xét đến với việc tìm lời
giải tối ưu cho một vấn đề cụ thể.
Trong một hướng tiếp cận mới trong vấn đề về tính khả quyết của bài toán,
những nhà khoa học quan tâm đến một họ các bài toán và tìm một thuật toán để
quyết định từng họ bài toán đó. Theo đó, vì các thuật toán là lời giải cho các bài
toán nên các phương pháp được sử dụng để giải các bài toán quyết định được gọi là
thủ tục quyết định hay thuật toán. Từ đó, một bài toán tổng quát khả quyết nếu lời
giải của nó sẽ dừng trong một khoảng thời gian hữu hạn, còn không bài toán bất khả
quyết. Chúng ta cần chú ý rằng vấn đề về tính khả quyết chỉ là một phần của lý
thuyết tính toán không quan tâm đến lượng thời gian mà một lời giải cần mà chỉ cần
khoảng thời gian đó là hữu hạn. Ví dụ, một thuật toán cho bài toán quyết định sẽ
giải thích làm cách nào để xác định x có chia hết cho y không, với x và y cho trước.
Một bài toán quyết định có thể được giải bởi một số thuật toán được gọi là khả
quyết.
Năm 1936, Church đã hình thức hóa một họ các bài toán mà ông có thể
chứng minh rằng không thể quyết định được bởi bất kỳ thuật toán nào. Để phát biểu
này có nghĩa, khái niệm toán học mới của một thuật toán phải được đưa ra. Và
Church đã sử dụng các công cụ từ logic, khái niệm các hàm đệ quy, để hình thức
hóa khái niệm về khả năng giải được về mặt thuật toán.
Trong cùng một năm khi Church công bố công trình của mình, Turing cũng
đã đưa ra khái niệm về máy Turing. Và ngày nay, chúng ta gọi những bài toán có
khả năng tính được về mặt thuật toán (algorithmic solvability) nếu chúng có thể
được tính bởi máy Turing. Tuy nhiên, các nhà khoa học đã thống nhất rằng lớp các
hàm có thể tính được bằng thuật toán trùng với lớp các hàm có thể tính được bằng
máy Turing. Nhiều mô hình tính toán khác đã được đề xuất (một số mô hình tương
đối khác với máy Turing) nhưng chúng ta vẫn chưa tìm được một mô hình máy có
thể giải quyết được nhiều vấn đề tính toán hơn máy Turing. Trong phần sau đây,
chúng ta sẽ khảo sát về luận đề Church-Turing, một luận đề nền tảng trong lý thuyết
về tính khả quyết của bài toán
Máy Turing và tính khả quyết của thuật toán 17

2. Luận đề Church-Turing
Luận đề Church-Turing đề cập đến khái niệm của một thuật toán hiệu quả
trong logic và toán học. Một thuật toán, hay thủ tục, M, cho việc thu được các kết
quả mong muốn được gọi là “hiệu quả” trong trường hợp:
• M được thiết lập với hình thức một số hữu hạn các lệnh chính xác
(từng lệnh được biểu diễn dưới dạng một số hữu hạn các ký hiệu)
• Nếu được thực hiện không lỗi, M sẽ đưa ra các kết quả mong muốn
trong một số hữu hạn bước.
Khái niệm về một thuật toán hiệu quả là một khái niệm không hình thức, và
các nỗ lực để xác định tính hiệu quả cho yêu cầu quan trọng mà thuật toán đòi hỏi
vẫn được được phát triển. Một trong những thành tựu hàng đầu của Turing – và là
bước phát triển lớn đầu tiên trong quá trình phát triển của lý thuyết tính toán – là đề
xuất một biểu thức được định nghĩa một cách nghiêm ngặt, qua đó phát biểu không
chính quy “bằng một thuật toán hiệu quả” có thể được thay “bằng một máy
Turing”. Tầm quan trọng của đề xuất Turing là ở chỗ: nếu đề xuất là chính xác, thì
việc nói về sự tồn tại và không tồn tại các thuật toán hiệu quả có thể được thay thế,
cả trong toán học và logic, bằng cách nói về sự tồn tại hay không tồn tại của các
chương trình máy Turing. Ví dụ, một người có thể thiết lập rằng không có thuật
toán hiệu quả để thực hiện một vấn đề nào đó bằng cách chứng minh rằng không có
máy Turing nào có thể thực hiện được cùng vấn đề đó.
Khái niệm hình thức được đề xuất bởi Turing là khái niệm về tính khả quyết
của máy Turing. Ông cho rằng mỗi khi có một thuật toán hiệu quả có thể thu được
các giá trị của một hàm toán học, hàm đó cũng có thể được tính bởi máy Turing.
Chúng ta cần chú ý rằng phần đảo của luận đề - bất kỳ thuật toán giải quyết vấn đề
nào có thể thực hiện bởi máy Turing đều hiệu quả - là đúng. Đó là do chương trình
máy Turing tự mình là một đặc tả của thuật toán hiệu quả, nên một người có thể, về
mặt lý thuyết, làm việc với bất kỳ một chương trình máy Turing nào, theo các lệnh
đã được định nghĩa trước và thực hiện các thao tác được yêu cầu.
Trước đó, Church cũng đã độc lập đề xuất một cách khác để thay thế cách
nói về các thuật toán hiệu quả với ngôn ngữ chính xác một cách chính quy, sử dụng
khái niệm khả năng định nghĩa-lambda (lambda-definability) thay vì “khả năng
tính được của máy Turing”. Trong đó, một hàm các số nguyên dương được gọi là
có khả năng định nghĩa-lambda nếu giá trị của hàm có thể được tính bằng một quá
trình các phép thế được lặp lại. Và ông đã sử dụng biểu diễn (phi hình thức) “có thể
tính được hiệu quả” để chỉ ra rằng có một thuật toán hiệu quả để tính các giá trị
của hàm qua đề xuất:
“Xác định khái niệm của một hàm có thể tính được hiệu quả các số nguyên
dương bằng cách xác định khái niệm đó bằng khái niệm của hàm đệ quy của các số
nguyên dương (hay với khái niệm hàm có khả năng định nghĩa-lambda các số
nguyên dương”.
Trong thực tế, Church đã đề xuất “Một hàm các số nguyên dương có khả
năng tính được hiệu quả chỉ khi là hàm đệ quy”
Máy Turing và tính khả quyết của thuật toán 18

Sự đảo lại, rằng mọi hàm đệ quy của các số nguyên dương là có khả năng
tính được hiệu quả, thường được xem là định lý đảo của luận đề Church.
Sau khi tìm hiểu đề xuất của Church, Turing nhanh chóng chứng minh được
rằng cấu trúc của khái niệm khả năng định nghĩa-lambda của Church và cấu trúc
khái niệm về khả năng tính được của ông là tương đương. Do đó, trong đề xuất của
Church, các từ “hàm đệ quy của các số nguyên dương” có thể được thay thế bởi các
từ “hàm các số nguyên dương có thể tính được bởi máy Turing”.
Và với quan điểm của các kết quả được tìm hiểu trên đây, nếu chỉ giới hạn
trong các hàm các số nguyên dương, thì luận đề của Church và của Turing đề xuất,
tuy có vẻ rất khác nhau, nhưng lại trở thành tương đương nhau, theo nghĩa là mỗi
hướng đề đưa ra chung một tập các hàm toán học. Luận đề Church-Turing là sự
khẳng định rằng tập này bao gồm mọi hàm có giá trị có thể thu được bằng một thuật
toán thỏa mãn các điều kiện trên đây cho tính hiệu quả. Tuy nhiên, cả Turing và
Church đề nhận ra rằng cách triển khai của Turing là “có sức thuyết phục hơn”
[turing] và “có ưu điểm trong việc đưa ra khả năng nhận dạng với tính hiệu quả…
hiển nhiên ngay lập tức” [Church].
Tóm lại, luận đề Church-Turing, mà nay đã trở thành chuẩn, được đề xuất
bởi Kleene như sau:
“Các luận đề của Turing và Church là tương đương nhau. Chúng ta có thể
xem các luận đề này vừa là luận đề Church, hay liên hệ với một trong các phiên bản
… của nó có quan hệ với máy Turing như Luận đề Church-Turing”.
3. Các chương trình như các bộ nhận dạng ngôn ngữ
Như trên tiểu luận đã trình bày, ưu điểm nổi bật của máy Turing là tính đơn
giản, và cần chú ý rằng chỉ một sự thay đổi đơn giản máy automat hữu hạn (thêm bộ
nhớ đọc/viết) đã mang lại cho chúng ta khả năng tính toán phổ dụng. Tuy nhiên,
việc máy Turing thuộc loại “bậc thấp” đã dẫn đến các hạn chế trong một số tình
huống như sau: Xây dựng một máy Turing chỉ để thực hiện một công việc đơn giản
như kiểm tra một số nguyên có phải là một số nguyên tố hay không cũng đã là một
công việc rắc rối và mất thời gian.
Chính vì lý do đó, trong tiểu luận này, chúng ta sẽ tiến hành theo một cách
tương đối phi truyền thống. Chúng ta sẽ sử dụng chính các chương trình để
nghiên cứu khả năng tính toán thuần túy như một khái niệm, định lý … trong phần
dưới đây sẽ đảm bảo cho chúng ta rằng việc chúng ta có sử dụng các máy Turing
hay các chương trình như cách hình thức hóa “chính thức” không phải là vấn đề
quan trọng.
Đầu tiên, chúng ta cần xác định một chương trình chấp nhận một ngôn ngữ
có ý nghĩa như thế nào. Để cụ thể, chúng ta xét lại một số quy ước về chương trình
(mà ở đây là chương trình C):
• Một file văn bản được mô hình hóa như một chuỗi các ký tự (được kết
thúc bằng một dấu hiệu đánh dấu). Trong thuật ngữ ngôn ngữ hình thức
chuẩn, một file văn bản đơn giản là một từ trên bảng ký tự ASCII.
• Một chương trình p có thể lấy đầu vào từ file đầu vào chuẩn, và có thể
xuất các kết quả đầu ra vào một file đầu ra chuẩn
Máy Turing và tính khả quyết của thuật toán 19

• Khi một chương tình dừng, nó sẽ trả về một điều kiện thoát cho hệ
điều hành bằng cách gọi hàm exit(status). Trạng thái 0 được sử dụng để
thông báo sự thực hiện thành công mà ở đây chúng ta ký hiệu là exit(0).
Chúng ta cũng ký hiệu một trạng thái thoát khác của 1 là exit(1) minh họa
các điều kiện khác được sử dụng để báo hiệu sự không thành công.
• Và chương trình tự bản thân cũng chỉ là một file văn bản
Vì vậy, cho p là chương trình, x là file văn bản, và giả sử rằng p được thực
hiện với x là đầu vào. Hãy tạm bỏ qua đầu ra và chỉ chú trọng vào cách kết thúc của
p. Có 3 khả năng sau đây:
• p dừng với exit(0), hay
• p dừng với điều kiện dừng khác, hay
• p không thể dừng lại, có nghĩa là quá trình tính toán sẽ được thực hiện
mãi mãi (chú ý rằng trong mô hình tính toán của chúng ta, chúng ta
không cho phép hệ điều hành có thể dừng chương trình vì tràn stack hay
các ràng buộc khác)
Theo cách này, chúng ta có thể xét một chương trình p để định nghĩa một tập
các từ trên bảng chữ cái ASCII: những từ này sẽ làm cho chương trình thực hiện
lệnh exit(0). Nghĩa là, bất kỳ chương trình nào cũng định nghĩa (đoán nhận) một
ngôn ngữ trên ASCII. Qua đây, chúng ta có thể thấy được mối liên quan khăng
khít và tự nhiên giữa lý thuyết tính toán và lý thuyết ngôn ngữ. Tóm lại:
Định nghĩa 1. Cho bảng ký tự ASCII được ký hiệu bằng Σ A. Giả sử p là chương
trình, và x là từ trên Σ A. Xét kết quả của việc thực hiện chương trình p khi đầu vào
chuẩn là một file với nội dung x. Nếu p dừng với exit(0) (tức thành công), chúng ta
sẽ phát biểu P chấp nhận x.
Tập ngôn ngữ được chấp nhận bởi p là tập tất cả các từ được chấp nhận bởi p
và được ký hiệu là L(p):
L(p) {x∈ | p dừng với điều kiện thoát exit(0) trên đầu vào x}
Với là tập tất cả các từ có thể được thành lập từ Σ A.
Ví dụ 5. Cho p là chương trình có giả mã như sau:
//Chấp nhận anbncn
Đọc đầu vào vào một mảng;
oksofar = true;
duyệt mảng, đếm số a, lưu kết quả đếm vào n1;
duyệt mảng, đếm số b, lưu kết quả đếm vào n2;
nếu thấy một a, exit(1);
duyệt mảng, đếm số c, lưu kết quả đếm vào n3;
nếu thấy a hay b, exit(1);
nếu không eof, exit(1);
nếu n1 == n2 == n3 exit(0) còn không thì exit(1)
Máy Turing và tính khả quyết của thuật toán 20

Lúc này L(p) là {anbncn | n ≥ 0}


Thực tế, có thể rút ra được nhiều điều từ việc chương trình p chấp nhận ngôn
ngữ {a b c | n ≥ 0}. Vì p luôn dừng, chúng ta có thể xét exit(0) như “đúng vậy, từ
n n n

đầu vào có vẻ như là anbncn với một số n”, và chúng ta có thể xét exit(1) như
“không, từ đầu vào không có vẻ là anbncn với bất kỳ n nào”. Có nghĩa là, chúng ta có
thể xét một cách tự nhiên rằng p như một thủ tục quyết định để kiểm tra các phần tử
của ngôn ngữ {anbncn | n ≥ 0}.
Định nghĩa 2. Cho p là một chương trình. Ta nói p là một bộ quyết định nếu với
mọi đầu vào x, hoặc p sẽ dừng với exit(0), hoặc p sẽ dừng với exit(1). Đôi khi một
bộ quyết định còn được gọi là một chương trình toàn thể (total program)
Điểm cần chú ý ở đây là p sẽ không bao giờ thực hiện mãi mãi trên bất kỳ
một đầu vào nào, cũng như không dừng với trạng thái thoát nào ngoài exit(0) hay
exit(1). Chúng ta có thể thấy p là một bộ quyết định.
Sự phân biệt trên đây là rất quan trọng [], và là nguyên tắc trung tâm mà lý
thuyết về tính khả quyết sử dụng làm nền tảng. Chúng ta sẽ xét điểm này chi tiết
trong những phần sau.
3.1. Các chương trình và máy Turing
Với nền tảng lý thuyết ở phần trên (khả năng biểu diễn thuật toán một cách
hình thức của máy Turing + khả năng nhận dạng ngôn ngữ của máy Turing), chúng
ta có thể suy ra những kết quả cơ bản sau:
Định lý 1. Cho một chương trình p, có một máy Turing M mô phỏng p cho mọi từ x
với nghĩa sau:
• Nếu p dừng với exit(0) trên đầu vào x thì M chấp nhận x và dừng,
• Nếu p dừng với một số điều kiện thoát khác trên đầu vào x thì M dừng
trên x mà không chấp nhận x, và
• Nếu p không dừng trên đầu vào x thì M không thể dừng trên đầu vào
x.
Hơn nữa, cho một máy Turing M, có một chương trình p mô phỏng M theo
cùng một cách như trên.
Chú ý rằng, những quan sát trên đây mang lại cho chúng ta những khái niệm
đáng chú ý về quá trình tính toán bằng các chương trình. Đó chính là khái niệm
mạnh (robust) không phân biêt theo những ngôn ngữ lập trình khác nhau. Và một
lần nữa chúng ta có thể thấy rằng khái niệm máy Turing, dù đơn giản hơn rất nhiều
so với các ngôn ngữ lập trình hiện đại, vẫn sẵn sàng thực hiện tất cả các thao tác
phức tạp có thể có trong quá trình tính toán.
3.2. Các hàm tính toán
Trên đây chúng ta đã xét các chương trình đơn giản như là các bộ chấp nhận
từ, nghĩa là định nghĩa ngôn ngữ. Dĩ nhiên, các chương trình thường cũng cho ra
các đầu ra cũng như các đầu vào, và do đó các chương trình tính các hàm.
Máy Turing và tính khả quyết của thuật toán 21

Trong phần trên, chúng ta đã xét một định nghĩa hình thức của một thuật
toán tổng quát với máy Turing. Phần này, chúng ta sẽ xét một số định nghĩa thuật
ngữ về các hàm trên khía cạnh nhận dạng ngôn ngữ.
Định nghĩa 3. Một hàm một phần từ Σ * vào Σ * là một hàm f từ D và Σ *, trong đó
D là tập con của Σ *.
Chú ý rằng, nếu f là hàm một phần trên các từ vựng, hoàn toàn có thể xảy ra
trường hợp miền D của f là tất cả Σ *, lúc này ta gọi f là hàm toàn phần từ Σ * vào
Σ *.
Định nghĩa 4. Cho p là chương trình, và w là từ. Xét kết quả của chương trình thực
thi p khi đầu vào chuẩn là một file với nội dung là w. Nếu p dừng với exit(0), và nội
dung của file đầu ra chuẩn là từ x, chúng ta sẽ nói rằng quá trình tính toán của p trên
w sẽ trả về x.
Hàm một phần được tính bởi p là hàm một phần từ các từ vựng vào các từ
vựng được miêu tả ở phần trên. Và chúng ta cũng cần chú ý rằng miền của hàm
được tính bởi p chính xác là L(p).
Dĩ nhiên, chúng ta cũng có những mối quan hệ chung giữa các máy Turing và
các chương trình trong bối cảnh các hàm chúng ta cho nhận dạng ngôn ngữ như sau:
Định lý 2. Cho một chương trình p, có một máy Turing M sao cho M tính cùng một
hàm một phần trên các từ vựng mà p đã thực hiện.
Cho máy Turing M có một chương trình p sao cho p tính cùng một hàm một
phần trên các từ vựng mà M đã thực hiện.
Lúc này,
• Một hàm một phần f từ Σ * vào Σ * được gọi là hàm một phần T-tính
được nếu tồn tại một máy Turing sao cho:
o Với một xâu đầu vào w thuộc miền xác định của f, thì máy Turing sẽ
dừng ở một hình trạng mà f(w) đang ở trên băng,
o Với xâu đầu vào w không thuộc miền xác định của f, thì máy Turing
sẽ chạy không dừng hoặc sẽ dừng và thông báo, nhờ một giá trị quy
ước trên băng rằng hàm là không xác định
• Một hàm toàn phần f từ Σ * vào Σ * được gọi là hàm T-tính được nếu
tồn tại một máy Turing sao cho với mọi đầu vào w, máy sẽ dừng ở một
hình trạng mà f(w) đang ở trên băng.
Trong tiểu luận này, chúng ta xét một bài toán quyết định là mọi câu hỏi
có/không bất kỳ trên một tập các đầu vào vô hạn. Do đó, chúng ta có thể định nghĩa
bài toán quyết định dưới hình thức tập các đầu vào mà bài toán sẽ trả về kết quả có.
Với nghĩa này, một bài toán quyết định tương đương với bài toán quyết định một
chuỗi đã cho có thuộc về tập các chuỗi hay không, với tập các chuỗi này được gọi là
một ngôn ngữ hình thức, trong đó một chuỗi đầu vào thuộc tập này sẽ trả về CÓ.
Hay phát biểu một cách hình thức hơn, một thuật toán khả quyết sẽ dừng với
một câu trả lời CÓ hay KHÔNG trên mỗi chuỗi đầu vào đối với một ngôn ngữ L đã
cho. Đối với một vấn đề cụ thể, nếu một thuật toán có thể quyết định chính xác một
Máy Turing và tính khả quyết của thuật toán 22

chuỗi có thuộc một ngôn ngữ không thì bài toán sẽ khả quyết. Do đó, tính khả quyết
của nhiều ngôn ngữ có thể được xác định theo thuật toán. Và cũng theo đó, việc chỉ
ra rằng một ngôn ngữ là khả quyết cũng sẽ tương đương với việc chỉ ra rằng một bài
toán là khả quyết.
Trong đó, một bài toán khả quyết là T-quyết định được nếu tồn tại một máy
Turing quyết định ngôn ngữ liên kết với bài toán đó (có nghĩa ngôn ngữ liên kết
với nó là đệ quy). Còn một bài toán khả quyết là T-nửa quyết định được nếu tồn
tại một máy Turing thừa nhận ngôn ngữ liên kết với bài toán đó (có nghĩa ngôn
ngữ liên kết với nó là đệ quy kể được). Trong những phần sau, chúng ta sẽ xét các
khái niệm đệ quy và đệ quy kể được một cách cụ thể hơn.
4. Máy Turing và vấn đề khả quyết
4.1. Các tập đệ quy kể được và khả quyết
4.1.1. Một số định nghĩa
Định nghĩa 5. Cho p là một chương trình. Người ta nói rằng p là một bộ quyết định
(decider) nếu với mỗi đầu vào x, hoặc p ngắt với EXIT_SUCCESS hoặc p ngắt với
EXIT_FAILURE.
Điểm mấu chốt ở đây là p sẽ không bao giờ chạy mãi trên bất kỳ đầu vào
nào, cũng không ngắt với một trạng thái kết thúc nào ngoài EXIT_SUCCESS hoặc
EXIT_FAILURE.

Định nghĩa 6. Cho A là một tập con của ∑ *


.

• A là nửa khả quyết (semi-decidability), hoặc là đệ quy kể được (RE) nếu nó


là ngôn ngữ L(p) cho một chương trình p nào đó.
• A là khả quyết nếu nó là ngôn ngữ L(p) cho một bộ quyết định p nào đó.

Định đề 1. Cho A là một tập con của ∑ *


. Thì :

• A là RE nếu và chỉ nếu có một máy Turing M sao cho A = L(M)


• A là khả quyết nếu và chỉ nếu có một máy Turing M mà nó ngắt trên mỗi
đầu vào sao cho A = L(M).
4.1.2. So sánh RE và tính khả quyết
Điểm khác nhau giữa RE và khả quyết là gì? Một điều chắc chắn rằng, nếu
một tập A là khả quyết thì A là RE.
Điều này được suy ra trực tiếp từ các định nghĩa: Nếu A là khả quyết thì
nó là L(p) cho một bộ quyết định p nào đó, và do đó nó cũng là L(p) cho
một chương trình p nào đó, suy ra nó là RE.
Vậy, điều ngược lại sẽ như thế nào? Đó là, nếu A là RE, thì liệu rằng A có
khả quyết không? Trong một số tài liệu đã chỉ ra rằng điều ngược lại này là không
đúng vì có các tập RE nhưng chúng lại không khả quyết.
Tóm lại: Nếu chúng ta nói rằng “A là RE” thì điều này có nghĩa là “A là nửa
khả quyết, nó cũng có thể hoặc không thể là khả quyết”.
Máy Turing và tính khả quyết của thuật toán 23

4.1.3. Tính kể được


Thuật ngữ “đệ quy kể được” được nêu ra trong các định nghĩa ở trên dường
như là một nghịch lý, bởi có thể thấy rằng hầu như không có cái gì liên quan đến
“đếm được” cả.
Chúng ta cùng nhau xem định nghĩa dưới đây:
Định nghĩa 7. Một chương trình E kể được một tập A nếu, khi được xử lý với một
file đầu vào rỗng, nó tạo ra một chuỗi các từ bao gồm các thành phần của A.
Nó không được yêu cầu rằng một bộ kể được (enumerator) tạo ra các từ của
A trong bất kỳ thứ tự cụ thể nào. Nó cũng không được yêu cầu rằng một bộ kể được
tạo ra các từ chỉ một lần. Nghĩa là một bộ kể được E cho một tập A sẽ tạo ra cùng
một x từ A sau nhiều lần thực hiện. Nó chỉ được yêu cầu rằng mỗi thành phần của A
xuất hiện ít nhất một lần trong đầu ra của E.
Nói cách khác, bạn có thể chỉ ra rằng nếu A là RE thì có một bộ kể được nào
đó cho A mà nó có thể in mỗi thành phần của A đúng một lần.
Chú ý rằng một bộ kể được sẽ không bao giờ ngắt. Nếu nó ngắt nghĩa là nó
sẽ đếm một tập hữu hạn. Ngay cả khi nó không ngắt nó cũng có thể chỉ đếm một tập
hữu hạn. Tuy nhiên, nó cũng hoàn toàn có thể đếm một tập vô hạn, bởi vì một bộ kể
được không được yêu cầu ngắt.
Định lý chính của phần này đó là: Một tập là đệ quy kể được nếu và chỉ nếu
nó có thể kể được bởi một chương trình nào đó. Đến đây, có thể thấy rằng cái tên
“đệ quy kể được” không còn ẩn đi như lúc trước nữa.
Chiều “nếu” của chứng minh có thể được kiểm chứng một cách dễ dàng.
Chiều còn lại thì có vẻ hơi phức tạp. Giả sử A là RE, một chương trình p với L(p) =
A. Ở đây, chúng ta phải đi tìm một chương trình E để tạo ra một danh sách của
thành phần của A. Ý tưởng dưới đây hoàn toàn có thể thực hiện được: bằng việc
đếm tất cả các từ x0, x1, x2, … xem mỗi xi lần lượt là đầu vào của p. Bất kể khi nào p
chấp nhận xi, thì thêm xi vào đầu ra của E.
Một rắc rối xảy ra với ý tưởng này đó là nếu chúng ta không cẩn thận, chúng
ta sẽ rơi vào một vòng lặp vô hạn để cố gắng quyết định phải chăng p chấp nhận
một xi cụ thể nào đó và chưa bao giờ có cơ hội để xem xét xi+1, xi+2, … Một thủ thuật
ở đây là chạy một cách có hiệu quả tất cả các kiểm tra trên tất cả các giá trị x i một
cách đồng thời. Đoạn mã được cho bên dưới (trong chứng minh của nửa thứ hai của
mệnh đề nếu và chỉ nếu) đưa ra một kỹ thuật thực sự.

Định lý 3. Một tập A ⊆ ∑ *


là RE nếu và chỉ nếu có một chương trình máy tính
mà nó đếm được A.
Chứng minh.
Giả sử có một chương trình E. Ở đây, ta có một chương trình p sao cho L(p)
= E.
Trên đầu vào x;
Bắt đầu chương trình E và xem đầu ra;
Nếu và khi x xuất hiện trên đầu ra của E, thì exit(0).
Máy Turing và tính khả quyết của thuật toán 24

Ngược lại, giả sử rằng A là RE. Ở đây, ta có một chương trình E mà nó kể


được A.
int k = 0;
while true do
For each xi with 0 ≤ i ≤ k
Chạy p trên xi trong k bước;
Bất kể khi nào xi được chấp nhận bởi p thì print(xi);
k = k+1;
Chú ý rằng, với việc kể được của chương trình E mà chúng ta đã xây dựng
trong phần 2, mỗi x trong A hoàn toàn được in bởi E nhiều lần một cách vô hạn.
4.2. Các ngôn ngữ đệ quy liệt kê
4.2.1. Ngôn ngữ đệ quy
Ngôn ngữ đệ quy là tập tất cả các ngôn ngữ mà chúng được quyết định bởi
một máy Turing nào đó.
LREC = {L : Tồn tại một máy Turing M, sao cho M quyết định L}
4.2.2. Ngôn ngữ đệ quy liệt kê
Ngôn ngữ đệ quy liệt kê là tập tất cả các ngôn ngữ mà chúng được quyết
định một nửa (semi-decided) bởi một máy Turing nào đó
LR.E = {L : Tồn tại một máy Turing, sao cho M quyết định một nửa L }
4.3. Các bài toán khả quyết
Có một quan hệ gần gũi giữa các câu hỏi về mối quan hệ giữa các ngôn ngữ
và loại câu hỏi “yes/no” mà chúng ta thường muốn giải quyết trong thế giới thực,
chẳng hạn như kiểm tra tính nguyên thủy (primality) của các số nguyên, kiểm tra
các đồ thị có là đồ thị phẳng hay không, hay kiểm tra tính đúng đắn của các chương
trình.

Mối quan hệ này chỉ đơn giản như sau: mỗi khi chúng ta đặt một ký tự ∑
lên những gì mà chúng ta sẽ biểu diễn các trường hợp của một bài toán, các trường
hợp mà nó cho ra câu trả lời ứng với câu hỏi của chúng ta là “đúng” thì nó sẽ định
nghĩa một ngôn ngữ trên ∑ , đó là tập con của ∑ *
. Với cách này, có thể hiểu
rằng bài toán của chúng ta là khả quyết hoặc RE. Sự liên hệ này rất đáng để chú ý:
Chúng ta xác định một vấn đề đã cho với một ngôn ngữ chứa tất cả các đầu
vào lấy từ một câu trả lời “đúng” cho vấn đề đó.
Chẳng hạn, như đã định nghĩa ở trên, ngôn ngữ sau đây:
{w ∈ [0, 1] * | w mã hóa một số nguyên tố}
có thể được xác định với bài toán:
Đầu vào: Một số nguyên n ở dạng nhị phân
Câu hỏi: n có phải là số nguyên tố hay không?
Máy Turing và tính khả quyết của thuật toán 25

Như vậy, chúng ta nói rằng một bài toán là RE hoặc khả quyết khi ngôn ngữ
kết hợp là RE hoặc khả quyết, nghĩa là khi ngôn ngữ kết hợp có một chương trình
nhận ra nó hoặc thậm chí là quyết định nó.
Ví dụ 7. Bài toán dưới đây là khả quyết
Đầu vào: Một số nguyên n ở dạng nhị phân
Câu hỏi: Có phải n là số nguyên tố không?
Những gì mà chúng tôi muốn nói ở đây, đó là: các số nguyên được mã hóa
dưới dạng các từ trên tập {0, 1} sử dụng cơ số 2. Tập các từ để mã hóa một số
nguyên tố là một ngôn ngữ. Và chúng ta khai báo rằng ngôn ngữ này là ngôn ngữ
khả quyết. Để định nghĩa khai báo này, chúng ta sẽ trình bày một chương trình mà
nó như là một bộ quyết định hoặc ngắt với exit(0) trên đầu vào w nếu và chỉ nếu w
mã hóa một số nguyên tố.
Rõ ràng rằng chương trình có thể làm được điều này, chẳng hạn một tìm
kiếm hoàn thiện của tất cả các ước số có thể có.
Ví dụ 8. Bài toán dưới đây là nửa khả quyết.
Đầu vào: Một chương trình viết bằng Java P
Câu hỏi: Với đầu vào là 17, p có dừng một cách thông thường hay không?
Xem các chương trình như là các từ trên S. Tập S của các từ mà chúng mã
hóa các chương trình hợp lệ để chương trình dừng một cách thông thường với đầu
vào là 17 là một ngôn ngữ. Để nói rằng tập này là RE hoặc bài toán này là nửa khả
quyết, thì cần chỉ ra rằng: Có thể viết một chương mà nó dừng với điều kiện ngắt
thành công trên đầu vào w nếu và chỉ nếu w mã hóa được một chương trình như
thế.
Cách mà chúng ta nhìn thấy ở đây là có thể viết một chương trình TermTst
mà nó căn cứ vào đầu vào p, biên dịch p thành mã máy trừu tượng Java _ JAM
(Java Abstract Machine codee) (nếu p không phải là một chương trình hợp lệ thì
loại bỏ p) và sau đó mô phỏng mã JAM này trên đầu vào 17. Nếu và khi việc mô
phòng dừng, thì chương trình TermTst sẽ quan sát sự kiện này và ngắt với exit(0).
Nếu việc mô phỏng ngắt không bình thường (chẳng hạn bị ngắt bằng lỗi division by
0), thì chương trình TermTst của chúng ta ngắt với exit(1).
Thảo luận trên chỉ ra rằng tập S là một tập nửa khả quyết hoặc RE. Tuy
nhiên, ở ví dụ trên có một điểm rất nguy hiểm, đó là bạn sẽ rất dễ nhầm lẫn TermTst
với các chương trình Java đang được kiểm tra. Đừng nhầm lẫn! TermTst là một
chương trình để kiểm tra chương trình; nó có thể xử lý bất kỳ chương trình java nào
mà bạn chuyển cho nó.
Hãy chắc rằng bạn chỉ chứng minh S là nửa khả quyết, chứ không phải là
khả quyết, bởi vì chương trình TermTst không được đảm bảo là có thể ngắt trên tất
cả các đầu vào. Tóm lại là chúng ta biết chắc chắn một điều rằng TermTst sẽ bị lỗi
khi ngắt trên một số đầu vào nào đó, bởi vì đơn giản rằng một số chương trình Java
sẽ lặp vô hạn khi lấy 17 như một đầu vào, và TermTst, là một chương trình khá đơn
giản, chỉ chuyển dịch sang phải. Với quan điểm này, hy vọng rằng sẽ có thể viết ra
một chương trình SuperTermTst thông minh hơn mà nó sẽ có thể xoay xở để phân
tích các chương trình Java một cách thông minh, và có thể dự đoán được phải chăng
Máy Turing và tính khả quyết của thuật toán 26

chương trình p sẽ dừng một cách bình thường mà không phải mô phỏng p một cách
mù quáng. Nếu chúng ta có thể xây dựng một chương trình SuperTermTst như thế,
chúng ta có thể chứng minh S là khả quyết. Tuy nhiên, chúng ta không thể thực hiện
được điều này, như chúng ta sẽ thấy …nhiều ứng dụng phải chờ cho đến khi chúng
ta tiến hành xong một nghiên cứu nào đó nữa dựa trên các kiến thức cơ sở.
5. Một số vấn đề máy Turing không giải được
5.1. Bài toán in (printing problem) và bài toán dừng(halting problem)
Turing đã miêu tả một số các bài toán toán học không thể giải được bởi máy
Turing, trong đó có bài toán in. Một số chương trình in “0” ở một số bước trong quá
trình tính toán của mình; còn tất cả các chương trình còn lại thì không bao giờ in
“0”. Bài toán in là bài toán quyết định, với một chương trình bất kỳ đã cho, là
chương trình đó thuộc loại nào trong hai loại trên đây. Turing đã chỉ ra rằng bài toán
này là không thể giải được bởi máy Turing phổ dụng.
Bài toán dừng là một ví dụ khác của các bài toán không thể giải được bằng
máy Turing phổ dụng. Đây là bài toán xác định, với một máy Turing bất kỳ đã cho,
máy cuối cùng có dừng hay không khi bắt đầu trên một băng trống. Trong một số
trường hợp, chúng ta không thể xác định rõ ràng từ một bảng của máy rằng máy có
dừng hay không. Trong trường hợp một máy vẫn hoạt động và chưa dừng lại, không
có cách thức hiệu quả nào để quyết định máy Turing sẽ dừng hay không.
5.2. Hàm dừng
Một hàm là một ánh xạ từ “các đối số” (đầu vào) vào “các giá trị” (đầu ra).
Ví dụ, phép + là một hàm ánh xác các cặp số vào những số duy nhất. Một hàm được
gọi là có thể tính được bởi máy Turing nếu một số máy Turing sẽ dùng các đối số
của hàm (hay các cặp đối số…) và, sau khi thực hiện một số hữu hạn các thao tác cơ
bản, đưa ra giá trị tương ứng – và, hơn nữa sẽ thực hiện đối số bất kỳ của hàm đã
được trình bày. Ví dụ, phép cộng trên các số nguyên là có thể tính được bởi máy
Turing, vì máy Turing có thể được thiết lập sao cho mỗi khi 2 số nguyên được đưa
vào băng (nhị phân), máy sẽ đưa ra kết quả phép cộng của hai số đó.
Hàm dừng được miêu tả như sau: Giả sử các máy Turing được sắp xếp theo
một trật tự nào đó, sao cho chúng ta có thể nói đến máy Turing đầu tiên trong danh
sách, máy thứ hai, … Các đối số của hàm dừng đơn giản là 1, 2, 3, … Giá trị của
hàm dừng cho đối số n bất kỳ là 1 nếu máy Turing thứ n trong trật tự sắp xếp cuối
cùng sẽ dừng khi bắt đầu trên một băng trống, và là 0 nếu máy thứ n chạy mãi mãi
(ví dụ như một máy Turing được lập trính để đưa ra liên tiếp các con trong biểu
diễn thập phân của π).
Định lý về máy Turing phổ dụng không thể giải bài toán dừng thường được
biểu diễn dưới dạng hàm dừng.
5.3. Entscheidungsproblem
Entscheidungsproblem, hay bài toán quyết định, là động lực chính của
Turing trong công trình “Về các số tính được”. Vào đầu thế kỷ 20, nhà toán học D.
Hilbert đã tự hỏi liệu có thể tìm ra một thuật toán xác định được tính đúng sai cho
mọi mệnh đề toán học hay không và ông cùng W.Ackermann đã đưa ra định nghĩa
về Entscheidungsproblem như sau:
Máy Turing và tính khả quyết của thuật toán 27

“Entscheidungsproblem được giải quyết khi chúng ta biết một thủ tục qua đó
có thể quyết định trong một số hữu hạn các thao tác một biểu thức logic đã cho có
đúng hay có thể được thỏa mãn không. Lời giải của Entscheidungsproblem đóng vai
trò quan trọng nền tảng cho lý thuyết của tất cả mọi lĩnh vực, và cho các định lý có
khả năng phát triển logic từ các tiên đề hữu hạn” []. Trong đó, Hilbert và các cộng
sự đã đề xuất các nhà toán học nên biểu diễn toán theo một dạng hệ thống hình thức
hoàn chỉnh, nhất quán, khả quyết – một hệ thống biểu diễn “toàn bộ nội dung ý
tưởng của toán học theo một cách thống nhất” []. Một hệ thống nhất quán có nghĩa
là không chứa mâu thuẫn, một hệ thống đầy đủ trong đó mọi phát biểu toán học
đúng đều có thể được chứng minh. “Khả quyết” hàm ý rằng có một phương pháp
hiệu quả để có thể cho biết, với từng phát biểu toán học, phát biểu đó có thể được
chứng minh trong hệ thống hay không, và qua đó chỉ ra phát biểu đó là đúng hay
sai.
Tuy nhiên, năm 1931, nhà toán học người Uc Kurt Gödel đã chứng minh
rằng ý tưởng của Hilbert là không thể thỏa mãn. Đây được xem như Định lý về tính
không đầy đủ đầu tiên của Gödel, trong đó có thể thấy được có những câu hỏi toán
học được hình thức hóa hoàn hảo nhưng lại không đầy đủ và bất khả quyết. Gödel
đã chỉ ra rằng dù các nhà toán học có xây dựng hệ thống hình thức theo tư tưởng
của Hilbert hoàn thiện đến mức nào đi nữa thì kết quả, dù có nhất quán, cũng không
thể đầy đủ. Gödel sau này đã tổng quát hóa kết quả này, chỉ ra rằng “với nền tảng là
các công trình của Turing, bây giờ ta có thể đưa ra một định nghĩa chính xác và
không thể bàn cãi về khái niệm tổng quát của một hệ thống hình thức”, với hệ quả
rằng sự không đầy đủ “có thể được chứng minh một cách nghiêm ngặt cho mọi hệ
thống hình thức thống nhất có chứa một lý thuyết số hữu hạn nhất định”[].
Tuy nhiên, định lý của Gödel đã không đề cập đến tính khả quyết. Khía cạnh
này được Turing và Church [] đề cập đến, một cách độc lập, rằng không có hệ thống
hình thức nhất quán của số học nào là khả quyết. Họ trình bày điều này bằng cách
chứng minh rằng ngay cả hệ thống logic thuần nhất được giả sử trước bởi một hệ
thống hình thức số học bất kỳ và được gọi là phép tính vị từ bậc nhất (first-order
predicate calculus) là khả quyết. Ông chỉ ra một cách hình thức rằng không có máy
Turing nào có thể xác định, trong một số hữu hạn bước, một công thức đã cho bất
kỳ của phép tính vị từ có phải là định lý (theorem) của phép tính không.
Hướng tiếp cận của Turing trong việc chứng minh các phép tính vị từ bậc
nhất là bất khả quyết liên quan đến bài toán in. Ông đã chỉ ra rằng nếu một máy
Turing có thể, với bất kỳ phát biểu nào, xác định phát biểu đó là có thể chứng minh
được bằng phép tính vị từ bậc nhất, thì một máy Turing có thể, với mọi máy Turing
đã cho, xác định nó có in “0” hay không. Vì, như Turing đã thiết lập, không có máy
Turing nào có thể giải bài toán in, do đó không có máy Turing nào có thể giải bài
toán Entscheidungsproblem . Và bước cuối cùng là áp dụng luận đề Turing: nếu
không tồn tại máy Turing có thể thực hiện tác vụ được hỏi, thì sẽ không có thuật
toán hiệu quả nào để thực hiện tác vụ đó. Do đó, theo luận đề Turing, sẽ không thể
tìm được thuật toán nào thỏa yêu cầu.
Máy Turing và tính khả quyết của thuật toán 28

TÀI LIỆU THAM KHẢO


1. Dan Dougherty. Notes on Decidability. Worcester Polytechnic Institute, 2007.
2. Jack Copeland. Computation.
www.blackwellpublishing.com/pci/downloads/SampleChapter.pdf
3. Jack Copeland. The Church-Turing Thesis. Stanford Encyclopedia of Philosophy,
2002.
4. Lê Mạnh Thạnh. Nhập môn Ngôn ngữ hình thức và Ôtômat hữu hạn. NXB Giáo
dục, Đà Nẵng, 1998.
5. Nguyễn Gia Định. Giáo trình Lý thuyết Ngôn ngữ hình thức và Ôtômat. Huế, 2004.
6. Nguyễn Văn Ba. Lý thuyết Ngôn ngữ và Tính toán. NXB Đại học Quốc gia Hà Nội,
Hà Nội, 2006.
7. Peter Gács and László Lovász. Algorithmic decidability. Lecture Notes, Yale
University, 1999.
8. Wikipedia, http://en.wikipedia.org/wiki/Wiki

You might also like