You are on page 1of 108

ĐẠI HỌC ĐÀ NẴNG

TRƯỜNG ĐẠI HỌC BÁCH KHOA


KHOA CÔNG NGHỆ THÔNG TIN

GIÁO TRÌNH
LÝ THUYẾT
TÍNH TOÁN

PGS.TS. PHAN HUY KHÁNH


ĐÀ NẴNG 1999
MỤC LỤC

CHƯƠNG 1 NHẬP MÔN LÝ THUYẾT TÍNH TOÁN ........................................... 1


I. CÁC ĐỐI TƯỢNG ĐƯỢC XỬ LÝ TRONG TIN HỌC .............................................................1
II. CÁC MÁY (MACHINES).......................................................................................................................2
II.1. Khía cạnh chức năng (functional look)........................................................ 2
II.2. Khía cạnh cấu trúc (structural look)............................................................ 3
III. MÔ HÌNH TÍNH TOÁN .........................................................................................................................4
IV. ĐỊNH NGHĨA BÀI TOÁN .....................................................................................................................5

CHƯƠNG 2 MÔ HÌNH CÁC MÁY RAM ............................................................... 9


I. CÁC MÁY RAM .....................................................................................................................................9
II. MÔ PHỎNG MỘT MÁY BỞI MỘT MÁY KHÁC .........................................................16
III. MỘT MÔ HÌNH THÔ SƠ KIỂU RAM..................................................................................19
III.1. Mô phỏng các phép toán trên chuỗi ký tự
bởi các phép toán trên các số nguyên ........................................................ 19
III.2. Thu gọn tập hợp các lệnh ngắt................................................................... 20
III.3. Thu gọn tập hợp các lệnh số học................................................................ 20
IV. MÁY RAM VẠN NĂNG....................................................................................................................22

CHƯƠNG 3 MÔ HÌNH CÁC MÁY TURING ....................................................... 25


I. MÔ TẢ VÀ HOẠT ĐỘNG CỦA MÁY TURING.......................................................................25
I.1. Mô tả máy Turing....................................................................................... 25
I.2. Hoạt động của máy Turing ........................................................................ 26
I.3. Cấu hình xuất phát của máy Turing........................................................... 29
I.4. Máy Turing đơn định.................................................................................. 29
II. CAC HÀM T-TÍNH ĐƯỢC ...............................................................................................................30
III. LỚP CÁC HÀM T-TÍNH ĐƯỢC .....................................................................................................32
III.1. Một số hàm sơ cấp ..................................................................................... 32
III.1.1. Các hàm hằng (constant functions)............................................................ 32
III.1.2. Các hàm chiếu (projection functions) ........................................................ 33
III.2. Các hàm kế tiếp (successor functions) ....................................................... 33
III.3. Các hàm kế trước (predecessor functions).......................................................... 34
III.4. Sự hợp thành (composition) ....................................................................... 34
III.3.1. Các máy được tiêu chuẩn hóa .................................................................... 35
III.3.2. Các máy Turing được chuẩn hóa ............................................................... 36
III.3.3. Tổ hợp các máy Turing.............................................................................. 36
III.5. Lập trình trên ngôn ngữ bậc cao máy Turing ............................................ 37
III.4.1. Cấu trúc if then else và cấu trúc rẽ nhiều nhánh ........................................ 37
III.4.2. Cấu trúc while ............................................................................................ 38
III.6. Quản lý bộ nhớ ........................................................................................... 39
III.5.1. Máy Turing chuyển một ô qua phải........................................................... 39

PGS.TS. PHAN HUY KHÁNH biên soạn 1


2 Lý thuyết tính toán
III.5.2. Máy Turing chỉ sử dụng phần băng bên phải
kể từ vị trí đầu tiên của đầu đọc-ghi...........................................................39
III.7. Một số máy Turing thông dụng ..................................................................40
III.6.1. Sao chép .....................................................................................................40
III.6.2. Kiểm tra bằng nhau ....................................................................................41
III.6.3. Liệt kê các câu, các cặp câu và dãy các câu ...............................................41
III.6.4. Các hàm chiếu ngược (antiprojection function).........................................42
III.6.5. Các hàm giao hoán .....................................................................................42
III.7. Các hàm T-tính được phức tạp hơn............................................................42
III.8. Nhận xét......................................................................................................43
IV. CÁC BIẾN THẾ KHÁC CỦA MÔ HÌNH MÁY TURING ........................................................ 46
IV.1. Mô phỏng một máy Turing bởi một máy khác............................................46
IV.2. Các biến thể của máy Turing .....................................................................48
IV.2.1. Máy Turing có k băng ................................................................................48
IV.2.2. Các máy off−line và các máy có băng ra ...................................................49
IV.2.3. Các máy Turing không đơn định................................................................49
IV.2.4. Thu gọn một bảng chữ còn ba ký tự...........................................................50
IV.2.5. Rút gọn một bảng chữ còn hai ký tự ..........................................................52
IV.3. Các máy Turing có băng vô hạn một phía .................................................52
V. MÁY TURING VẠN NĂNG .............................................................................................................. 53


VI. TỒN TẠI CÁC HÀM KHÔNG LÀ T TÍNH ĐƯỢC ............................................................ 55

CHƯƠNG 4 LUẬN ĐỀ CHURCH ........................................................................59


I. TƯƠNG ĐƯƠNG GIỮA CÁC MÔ HÌNH MÁY TURING VÀ MÁY RAM ......................... 59
I.1. Mọi hàm T-tính được cũng là R−tính được................................................59
I.2. Mọi hàm R−tính được cũng là T−tính được ...............................................60
I.2.1. Tăng nội dung thanh ghi n lên 1.................................................................60
I.2.2. Giảm 1 nội dung thanh ghi n ......................................................................60
I.2.3. Đưa nội dung thanh ghi n về 0 ...................................................................60
I.2.4. Nhảy theo nội dung thanh ghi n .................................................................61
I.2.5. Hoán vị nội dung hai thanh ghi n và m ......................................................61
I.3. Sự khác nhau giữa máy Turing và máy RAM.............................................61
II. MÔ HÌNH CÁC HÀM ĐỆ QUY ....................................................................................................... 62
II.1. Các hàm đệ quy nguyên thủy (primitive recursive functions)....................62
II.1.1. Xây dựng các hàm sơ cấp...........................................................................62
II.1.2. Sơ đồ hợp thành tổng quát..........................................................................62
II.1.3. Sơ đồ đệ quy đơn (simple recurrence) .......................................................63
II.1.4. Sơ đồ đệ quy đồng thời ..............................................................................63
II.1.5. Các hàm được định nghĩa bởi case.............................................................65
II.2. Các hàm đệ quy ..........................................................................................67
II.2.1. Sơ đồ tối thiểu ............................................................................................67
II.2.2. Các hàm đệ quy trừu tượng (abstract recursive functions) ........................68
II.2.3. Một số ví dụ................................................................................................68
II.3. Các hàm đệ quy đều T−tính được...............................................................70
II.3.1. Sơ đồ hợp thành tổng quát..........................................................................70
II.3.2. Sơ đồ đệ quy đơn........................................................................................70
II.3.3. Sơ đồ tối thiểu ............................................................................................71
Nhập môn lý thuyết tính toán 3

II.4. Mọi hàm T−tính được là đệ quy bộ phận ................................................... 71


III. LUẬN ĐỀ CHURCH ............................................................................................................................73

CHƯƠNG 5 CÁC BÀI TOÁN KHÔNG QUYẾT ĐỊNH ĐƯỢC .......................... 77


I. CÁC NGÔN NGỮ LIỆT KÊ ĐỆ QUY VÀ CÁC NGÔN NGỮ ĐỆ QUY .......................................77
II. CÁC BÀI TOÁN KHÔNG QUYẾT ĐịNH ĐƯỢC ................................................................................82
III. THUẬT TOÁN RÚT GỌN MỘT BÀI TOÁN VỀ BÀI TOÁN KHÁC .............................................83

CHƯƠNG 6 ĐỘ PHỨC TẠP TÍNH TOÁN ......................................................... 93


I. ĐỘ PHỨC TẠP VỀ THỜI GIAN VÀ VỀ BỘ NHỚ ...............................................................84
II. CÁC LỚP CỦA ĐỘ PHỨC TẠP ....................................................................................................84
II.1. Hiện tượng nén........................................................................................... 84
II.2. Các họ P, NP và P−bộ nhớ (P−space)..................................................... 84
III. RÚT GỌN ĐA THỨC VÀ CÁC BÀI TOÁN NP−ĐẦY ĐỦ .........................................................84
III.1. Khái niệm ................................................................................................... 84
III.2. Các bài toán cổ điển .................................................................................. 84
III.3. Ví dụ về rút gọn kiểu đa thức ..................................................................... 84
CHƯƠNG 1

Nhập môn lý thuyết tính toán


(Introduction to the theory of computation)
It’s not bad being the small fish.

I. Các đối tượng được xử lý trong Tin học


Trong Tin học, các đối tượng (objects) được xử lý thông thường là những
phần tử thuộc vào những tập hợp vô hạn đếm được. Những phần tử này luôn luôn
được biểu diễn (represented) dưới một dạng nào đó.
Chẳng hạn trong ngôn ngữ tự nhiên, số nguyên 1999 được biểu diễn trong hệ
đếm cơ số 10 (hệ thập phân) gồm một dãy bốn chữ số thập phân thuộc bảng chữ
số {0, 1, ..., 9}. Việc xử lý (thực hiện các phép toán số học thông thường) đối với
các số nguyên được tiến hành trên cách biểu diễn cơ số 10 này.
Ví dụ : Phép cộng hai số 1999 + 1 = 2000.
Người ta giả thiết rằng các đối tượng được xử lý là những câu (word, hay
sentence) được xây dựng trên một bảng chữ (alphabet) hữu hạn, được xem như là
sự biểu diễn của đối tượng trong một bản chất khác.
Định nghĩa 1.1 :
Một bảng chữ S là một tập hợp hữu hạn các chữ (letters), hay là các ký tự
(symbols, hay characters).
Số lượng các ký tự, còn gọi là bản số (cardinality) hay lực lượng của S, được
ký hiệu ||S||, hay |S|, nếu không sợ nhầm lẫn.
Một câu, hay một từ, trên bảng chữ S đã cho là một dãy hữu hạn các ký tự của
bảng chữ S được viết liên tiếp nhau.
Độ dài (length) của một câu (trên bảng chữ S đã cho) là số lượng các ký tự có
mặt trong câu. Câu rỗng (empty word), được ký hiệu là e (ω hoặc e, hoặc l), là
câu có độ dài không, tức không chứa ký tự nào.
Ghép (concatenation) của hai câu là đặt kế tiếp hai câu đã cho (trên cùng
dòng) để nhận được một câu mới. Bằng cách ghép liên tục như vậy cho mọi ký
tự, mọi câu của S, ta nhận được một tập hợp chứa mọi câu có thể trên S, ký hiệu
S*. Người ta nói S*là một cấu trúc đồng đẳng (nonoide), mà phần tử trung hòa
(neutral element) chính là câu rỗng.
Cho trước một bảng chữ S, người ta định nghĩa một quan hệ có thứ tự toàn
phần (total order) trên S* như sau : cho một thứ tự tùy ý trên các ký tự của S,

PGS.TS. PHAN HUY KHÁNH biên soạn 1


2 Lý thuyết tính toán

người ta sắp xếp các câu theo một thứ tự phân cấp (hierechical order), đầu tiên là
theo độ dài câu, sau đó theo thứ tự từ vựng (lexicography), hay thứ tự ABC.
Ví dụ :
Cho S = {a, b, c}, với giả thiết thứ tự phân cấp của các ký tự là a < b < c, ta
có thể đánh số các câu của S* (kể cả câu rỗng e) bắt đầu từ 1 trở đi như sau :
e1

a2 b3 c4

aa 5 ab 6 ac 7 ba 8 bb 9 bc 10 ca 11 cb 12 cc 13

aaa 14 aab 15 aac 16 . . .

Hình 1.1. Thứ tự phân cấp trong S*

II. Các máy (machines)


II.1. Khía cạnh chức năng (functional look)
Một máy (machine) được biểu diễn một cách hệ thống như sau :

Dữ liệu vào Dữ liệu ra


Máy

Hình 1.2. Khía cạnh chức năng của một máy


Ở lối vào, người ta cung cấp một hoặc nhiều dữ liệu (data) cho máy, thì lối ra,
người ta nhận được kết quả (result).
Giả thiết rằng các dữ liệu vào có dạng là dãy các ký tự, là một câu trên một
bảng chữ nào đó đã cho (vào từ bàn phím chẳng hạn). Kết quả là một phần tử của
một tập hợp xác định trước (predefini). Người ta phân biệt các kiểu máy
(machine type) tùy theo bản chất của tập hợp kết quả này như sau :
1. Nếu tập hợp chỉ có hai phần tử { không, có } hay {0, 1}, máy sẽ chia dữ
liệu vào thành ba phần tùy theo kết quả :
Tập hợp các câu trên bảng chữ vào sau khi được xử lý sẽ cho ra một kết
quả là có (đúng, true), hoặc không (sai, false).
Tập hợp các câu mà máy đưa ra một kết quả khác.
Tập hợp các câu trên bảng chữ vào mà máy không cho kết quả nào.
Nhập môn lý thuyết tính toán 3

Các tập hợp này tạo thành các ngôn ngữ (language). Hai tập hợp đầu là bù
nhau nếu với mọi dữ liệu vào, máy đều cho một kết quả. Người ta gọi đó là
máy đoán nhận (recognition machine) câu.
2. Nếu kết quả là một dãy hữu hạn các ký tự, ta nhận được một câu trên một
bảng chữ G nào đó.
Cho S là bảng chữ vào, máy xác định một hàm f từ S* vào G*, ta viết :
f : S* → G *
nghĩa là với một câu vào w ∈ S*, f(w) ∈ G*. Người ta nói máy thực hiện
hàm f. Nếu với mọi câu vào w ∈ S*, máy đều cho một kết quả f(w) ∈ G*,
thì f được gọi là hàm toàn phần (partial function). Người ta gọi đó là máy
tính toán (computation machine) hay máy tính.
Chú ý rằng kiểu máy thứ nhất (máy đoán nhận) mà chúng ta vừa phân biệt
thực ra chỉ là một trường hợp đặc biệt của kiểu máy thứ hai (máy tính).
3. Nếu kết quả là một dãy vô hạn các ký tự và bảng chữ đang sử dụng chỉ có
tối thiểu hai ký tự, trong đó có một dấu phân cách (separator) #, thì người ta
nhận được kết quả là một dãy liên tiếp các câu phân cách nhau bởi dấu #,
tạo thành một ngôn ngữ. Người ta gọi ngôn ngữ này là liệt kê được
(enumerated) bởi máy.

II.2. Khía cạnh cấu trúc (structural look)


Ở đây, ta chỉ quan tâm đến các máy được mô tả đầy đủ về chức năng hoạt
động của chúng. Những máy này có thê :
Thực hiện các phép toán sơ cấp (elementary operation) trong một khoảng
thời gian hữu hạn. Mỗi phép toán, giả thiết không chia cắt nhỏ hơn được,
được chọn trong một tập hợp hữu hạn các phép toán là một phần mô tả cấu
trúc máy.
Lần lượt thực hiện các phép toán sơ cấp theo một thứ tự xác định trước, tạo
thành một chương trình (program), là một phần mô tả cấu trúc máy.
Một dãy các phép toán sơ cấp được máy thực hiện liên tiếp được gọi là một
tính toán (computation) của máy.
4 Lý thuyết tính toán

III. Mô hình tính toán


Thay vì phải thay đổi lại máy tính mỗi lần thay đổi bài toán cần giải, người ta
định nghĩa các lớp máy có cùng nguyên lý hoạt động và chúng chỉ khác nhau ở
chương trình.
Người ta gọi mô hình tính toán (model), ký hiệu T, là sự mô tả tất cả các phép
toán sơ cấp có thể được thực hiện trên những đối tượng nào, cách tác động lên
mỗi một trong chúng như thế nào, và mô tả cách thức chương trình được thực
hiện (execution) trên máy.
Một trường hợp riêng (instance) của mô hình là một máy biệt lập nào đó, gọi
tắt là máy, hoạt động theo cách mô hình tính toán đã chỉ ra. Máy này được định
nghĩa bởi dữ liệu vào của chương trình :
Mô hình + Chương trình = Máy
Một khi một mô hình tính toán T được định nghĩa, được gọi là một T−máy,
vấn đề đặt ra là làm sao để có thể biết :
− lớp ngôn ngữ đoán nhận được (recognized), được gọi là T−nhận biết được,
hoặc
− lớp các hàm tính được (computable), được gọi là T−tính được, hoặc
− lớp các ngôn ngữ liệt kê được (enumerable) được gọi là T −liệt kê được,
bởi một máy nào đó của mô hình này ?
Hai mô hình tính toán được đưa ra so sánh với nhau : một mô hình T1 được
nói là mạnh hơn so với một mô hình T2 nếu :
− mọi ngôn ngữ T2−nhận biết được cũng là T1−nhận biết được, hoặc
− mọi hàm T2-tính được cũng là T1−tính được, hoặc
− mọi ngôn ngữ T2-liệt kê được cũng là T1-liệt kê được.
Hai mô hình được gọi là tương đương (equivalent) nếu mỗi mô hình mạnh
hơn mô hình kia và ngược lại.
Hai mô hình là không thể so sánh với nhau được nếu không tồn tại mô hình
nào ít ra đủ mạnh hơn mô hình kia.
Nhập môn lý thuyết tính toán 5

IV. Định nghĩa bài toán


Trong Tin học lý thuyết, định nghĩa về bài toán (problem) có vai trò đặc biệt
quan trọng, khác với khái niệm thông thường về bài toán được dùng trong lĩnh
vực Toán học hoặc hiểu theo nghĩa thông dụng.
Định nghĩa 1.2 :
Một bài toán là :
− Sự mô tả cách biểu diễn (hữu hạn) các phần tử của một tập hợp hữu hạn
hay vô hạn đếm được.
− Một phát biểu liên quan đến các phần tử của tập hợp này, có thể là đúng,
hoặc có thể là sai tùy theo phần tử được chọn.
Sau đây là một số ví dụ :
Bài toán 1 :
Dữ liệu: Một số nguyên viết trong hệ 10.
Câu hỏi : Số nguyên đã cho có là số nguyên tố hay không ?
Bài toán 2 :
Dữ liệu : Một số nguyên viết trong hệ 10.
Câu hỏi : Có phải số nguyên này được viết dưới dạng tổng của 4 số bình phương
?
Bài toán 3 :
Dữ liệu : Một số nguyên viết dưới dạng tích của các số hạng trong hệ 10.
Câu hỏi : Số nguyên đã cho có là số nguyên tố hay không ?
Bài toán 4 :
Dữ liệu : Một đồ thị hữu hạn được biểu diễn bởi một danh sách gồm các đỉnh
và các cung, trong đó mỗi đỉnh được biểu diễn bởi một số nguyên
trong hệ 10.
Câu hỏi : Có tồn tại một đường đi Hamilton (đi qua hết tất cả các đỉnh của
đồ thị, mỗi đỉnh đi qua đúng một lần) trong đồ thị đã cho không ?
Bài toán 5 :
Dữ liệu : Một biểu thức chính quy (regular expression) được xây dựng trên
một bảng chữ S (là một biểu thức nhận được từ các câu w∈S* bởi
các phép hoặc, phép ghép tiếp, phép * và lấy bù).
Câu hỏi : Có phải biểu thức đã cho biểu diễn (hay chỉ định) một ngôn ngữ
trống (empty language) hay không ?
Bài toán 6 :
Dữ liệu : Một dãy hữu hạn các cặp câu (u1, v1), (u2, v2)..., (uk, vk).
Câu hỏi : Tồn tại hay không một dãy chỉ số i1 , i2 ,...in sao cho thoả mãn
ui1 ui2... uin = vi1 vi2... vin ?
6 Lý thuyết tính toán

Việc biểu diễn tường minh các dữ liệu là một thành phần của bài toán. Điều
này đóng vai trò đặc biệt quan trọng khi người ta quan tâm đến độ phức tạp
(complexity) của một bài toán. Mỗi dữ liệu sẽ tạo thành một trường hợp cá biệt
của bài toán, được biểu diễn bởi một câu trên một bảng chữ hữu hạn đã cho.
Với mỗi bài toán P được hợp thành từ một biểu diễn các phần tử của một tập
hợp và từ một phát biểu liên quan đến các phần tử này, người ta thường kết hợp
bài toán P với một ngôn ngữ, gọi là ngôn ngữ đặc trưng (characteristic language)
của bài toán, được hợp thành từ tập hợp các câu biểu diễn một phần tử của tập
hợp để từ đó, kết quả của bài toán là câu trả lời đúng. Người ta ký hiệu LP là
ngôn ngữ đặc trưng của bài toán P.
Cho trước một bài toán P, bài toán ngược lại CP là bài toán nhận được từ P
bằng cách giữ nguyên cách biểu diễn các dữ liệu nhưng riêng câu hỏi thì đặt
ngược lại. Ví dụ, bài toán ngược với bài toán 1 sẽ là :
Bài toán 1’ :
Dữ liệu : Cho một số nguyên viết trong hệ 10.
Câu hỏi : Số nguyên này không phải là một số nguyên tố ?
Từ đó, lời giải một bài toán đưa đến sự nhận biết của một ngôn ngữ : ngôn
ngữ kết hợp với bài toán này. Người ta đưa ra định nghĩa hình thức sau đây :
Định nghĩa 1.2 :
Một máy giải (solve) một bài toán P nếu và chỉ nếu với mọi câu f biểu diễn
một phần tử của tập hợp liên quan đến bài toán này, máy cho phép xác định,
trong một khoảng thời gian hữu hạn, nếu câu này thuộc về LP hay LCP.
Người ta phân lớp các bài toán tùy theo độ khó (difficulty) để đưa ra câu trả
lời từ dữ liệu vào đã cho.
Một bài toán là tầm thường (trivial) nếu LP = ∅ hoặc nếu LCP = ∅.
Thật vậy, trong trường hợp này, không cần thiết biết dữ liệu đưa vào để đưa ra
câu trả lời. Chú ý rằng, những gì là tầm thường, đó là việc đưa ra câu trả lời,
nhưng có thể rất khó để chứng minh rằng bài toán là tầm thường theo nghĩa này.
Ví dụ, bài toán 2 là tầm thường.
Các bài toán 1 và 3 có cùng câu hỏi, nhưng bài toán 3 giải quyết rất dễ dàng :
chỉ cần đọc qua dữ liệu vào, người ta có thể đưa ra kết quả, tuy nhiên trong bài
toán 1 thì cần phải xử lý dữ liệu vào. Bài toán 4 phức tạp hơn : người ta chưa biết
phương pháp nào hoạt động một cách đơn định (deterministic) tiêu tốn một lượng
thời gian đa thức (polynomial times) để giải quyết vấn đề đặt ra.
Đối với bài toán 5 thì tính phức tạp còn lớn hơn nữa : người ta biết rằng mọi
phương pháp đều hoạt động theo thời gian tối thiểu là lũy thừa. Cuối cùng bài
toán 6 không thể giải được theo nghĩa đã đưa ra. Bài toán này được gọi là bài
toán tương ứng Post (Post’s correspondence problem).
Nhập môn lý thuyết tính toán 7

Bài tập
1) Chứng minh rằng một tập hợp E là hữu hạn hay vô hạn đếm được nếu tồn tại
một đơn ánh từ E vào N. Tương tự, nếu tồn tại một toàn ánh (surjection) từ Ν
vào E.
2) Chứng minh rằng tích Đê-cac của hai tập hợp vô hạn đếm được cũng là một
tập hợp vô hạn đếm được.
3) Chứng minh các tập hợp sau đây là vô hạn đếm được : N×N, Q, tập hợp Ν*
gồm các dãy số nguyên, S*, S*×G*, S*×N, tập hợp (S*)* gồm các dãy các
câu. Thể hiện các song ánh (bijection) giữa N và mỗi một tập hợp vừa nêu.
4) Cho S là một bảng chữ kích thước (bản số) n. Với mọi câu w∈S*, ký hiệu |w|
là độ dài của w và m(w) là số thứ tự của w trong thứ tự phân cấp đã cho. Hãy
tìm cách tính m(w) khi biết w.
5) Chứng minh rằng NN không phải là vô hạn đếm được. Tập hợp các chương
trình Pascal có phải là vô hạn đếm được hay không ? Tập hợp các hàm f: N →
N tính được nhờ một chương trình Psacal có là vô hạn đếm được hay không ?
Từ đó suy ra rằng tồn tại các hàm từ N vào N không là vô hạn đếm được nhờ
một chương trình Pascal.
6) Viết một chương trình để liệt kê :
− các cặp số nguyên
− các dãy hữu hạn các số nguyên
− các câu trên một bảng chữ hữu hạn (chẳng hạn S={a, b, c})
− các cặp câu
− các dãy hữu hạn các câu.
CHƯƠNG 2

Mô hình các máy RAM


« I like the dreams of the future better than
the history of the past »
Jefferson

I. Các máy RAM


Máy RAM là một mô hình tính toán rất gần với máy tính điện tử và ngôn ngữ
assembler. Máy RAM có các thành phần đặc trưng chung như sau :
Một băng vào, hay dải vào (input tape) được chia thành nhiều ô (square hay
pigeonhole) liên tiếp nhau, mỗi ô chứa một số nguyên hoặc một ký tự. Một
đầu đọc (read head) đọc lần lượt nội dung từng ô trên băng vào, đọc từ trái
qua phải.
Một băng ra (output tape) cũng chia ra thành nhiều ô liên tiếp nhau và một
đầu ghi (write head) có thể ghi mỗi lần lên một ô và tiến từ trái qua phải.
Người ta nói rằng đầu đọc (hoặc ghi) được đặt trên (tại) một ô và di chuyển
qua phải mỗi lần một ô. Trước tiên, ta xem rằng mỗi ô chứa một số nguyên có thể
lớn tuỳ ý. Băng vào và băng ra của máy RAM được gọi là các cơ quan vào/ra.
Máy RAM còn có các thành phần bên trong như sau :
Các thanh ghi (registers) là các phần tử nhớ được đánh số thứ tự, số lượng
các thanh ghi có thể lớn tuỳ ý. Mỗi thanh ghi có thể lưu giữ một số nguyên.
Các thanh ghi lần lượt được đặt tên là R0, R1, R2, ... , Rn...
Chỉ số i, i = 0, 1, 2, ..., được gọi là địa chỉ (address) của mỗi thanh ghi (hay
của bộ nhớ). Riêng R0 là một thanh ghi đặc biệt, được gọi là thanh tổng (ACC −
accumulator) hay thanh tích luỹ.
Một tập hợp các đơn vị nhớ được đánh số chứa chương trình của máy RAM
dưới dạng một dãy các lệnh sơ cấp (primary instructions) không bị thay đổi
trong quá trình chạy (thực hiện). Mỗi lệnh được lưu trữ trong một đơn vị
nhớ, được đánh số tương ứng với số thứ tự hay nhãn của lệnh (label).
Một đơn vị nhớ chứa số thứ tự của lệnh đang được thực hiện, được gọi là
thanh đếm lệnh (OC − Ordinal Counter). Lúc đầu nội dung là của OC là 1.
Trong kiểu máy này, người ta truy cập trực tiếp đến mỗi thanh ghi bởi địa chỉ
của thanh ghi đó. Chính lý do này mà kiểu máy này được đặt tên là Random
Access Memory (viết tắt RAM).

PGS.TS. PHAN HUY KHÁNH biên soạn 9


10 Lý thuyết tính toán

x1 x2 ... xn Băng vào

1 R0 Thanh tổng
Chương trình
2 R1
... ... ... ... Các thanh ghi
j Ri
... ... ... ...
p Rn
i
Thanh
đếm lệnh

y1 y2 y3 ... Băng ra

Hình 2.1 Sơ đồ một máy RAM


Mỗi chương trình của máy RAM gồm một dãy lệnh sơ cấp, mỗi lệnh được tạo
thành từ 2 thành phần : mã lệnh (operation code) và toán hạng (operand) :
Mã lệnh Toán hạng
Các lệnh được phân thành nhóm theo chức năng của phần mã lệnh như sau :
Nhóm lệnh gán :
LOAD Operand
STORE Operand
Nhóm lệnh số học :
INCR Operand
DECR Operand
AD Operand
SUB Operand
MULT Operand
DIV Operand
Nhóm lệnh nhảy (hay lệnh ngắt, cũng còn gọi là lệnh chuyển điều khiển) :
JUMP Label
JGTZ Label
JZERO Label
HALT
Nhóm lệnh vào − ra :
READ Operand
WRITE Operand
Mô hình các máy RAM 11

Theo nguyên tắc địa chỉ, phần toán hạng là địa chỉ (address) của toán hạng
tham gia phép toán chỉ định bởi phần mã lệnh. Toán hạng có thể là một trong ba
kiểu sau :
Kiểu địa chỉ Ý nghĩa
Số nguyên n Chỉ nội dung của thanh ghi thứ n (Rn).
A: n (A = Absolute) toán hạng chính là số nguyên n đó.
I: n (I = Indirection) toán hạng là nội dung của thanh ghi có số thứ
tự là nội dung của thanh ghi Rn. Đây là kiểu lệnh gián tiếp.
Nếu lệnh là một lệnh nhảy thì địa chỉ chính là số thứ tự của lệnh trong chương
trình. Các lệnh trên đây của máy RAM điển hình cho các lệnh của ngôn ngữ
assembler. Tuy nhiên ở đây vắng mặt các lệnh xử lý ký tự và các lệnh logic nhằm
đơn giản cách trình bày.
Thứ tự thực hiện các lệnh của chương trình là tuần tự (on sequence), bắt đầu
từ lệnh đầu tiên (có nhãn 1). Ngoại lệ duy nhất là khi gặp lệnh nhảy (hay chuyển
điều khiển) thì lệnh tiếp theo được thực hiện có nhãn chỉ định bởi lệnh nhảy này.
Nguyên tắc thực hiện như sau : OC luôn luôn chứa nhãn của lệnh sẽ được
thực hiện, lúc đầu nội dung OC là 1. Sau khi thực hiện lệnh, nội dung OC được
tự động tăng thêm 1 (increment) nếu như lệnh vừa thực hiện không là lệnh nhảy.
Nếu như lệnh vừa thực hiện là lệnh nhảy thì nội dung của OC lấy nhãn là phần
địa chỉ của lệnh nhảy này.
Sau đây sử dụng một số quy ước để giải thích cách thực hiện lệnh.
← dấu gán ; quy ước số nguyên i nằm bên trái dấu gán chỉ thanh ghi
thứ i là Ri, số nguyên i nằm bên phải dấu gán chỉ giá trị chính là số
nguyên i đó.
<i> Chỉ nội dung của thanh ghi Ri.
<<i>> Chỉ nội dung của thanh ghi có số thứ tự được chứa trong thanh ghi
Ri đối với kiểu lệnh gián tiếp.
ACC Chỉ thanh ghi R0.
CO Chỉ thanh đếm lệnh.
<CO> Nội dung của CO.
Sau đây là bảng các lệnh RAM và ý nghĩa sử dụng của chúng.
12 Lý thuyết tính toán

Lệnh Ý nghĩa
LOAD
 n ACC ← <n>
LOAD
 A: n ACC ← giá trị n
LOAD
 I: n ACC ← <<n>>
STORE
 n n ← <ACC>
STORE
 I: n <n> ← <ACC>
INCR
 n n ← <n> + 1
DECR
 n n ← <n> - 1
ADD
 n ACC ← <ACC> + <n>
SUB
 n ACC ← <ACC> − <n>
MULT
 n ACC ← <ACC> × <n>
DIV
 n ACC ← <ACC> / <n>
JUMP
 n CO ← n
JGTZ
 n CO ← n nếu <ACC> ≥ 0
JZERO
 n CO ← n nếu <ACC> = 0
Cả hai trường hợp trên, nếu không thỏa mãn, CO ← <CO> + 1

HALT
 Dừng máy
READ n
 n ← số nguyên trong ô dưới đầu đọc của băng,
đầu đọc dịch một ô qua phải
WRITE n
 Nội dung <n> được ghi vào ô dưới đầu ghi,
đầu ghi dịch qua phải một ô.
Ví dụ 2.1 : Chương trình RAM sau đây đánh giá trị n!
READ 0 đọc một giá nguyên n vào ACC
JZERO 10 nếu n = 0, nhảy đến nhãn 10,
nếu không, thực hiện lệnh tiếp theo
STORE 1 R1 ← <ACC>
4: STORE 2 R2 ← <ACC>
DECR 1 R1 ← < R1> − 1
LOAD 1 ACC ← <R1>
JZERO 12 nếu <ACC> = 0 nhảy đến 12
MULT 2 ACC ← <ACC> * <R2>
JUMP 4 CO ← 4
10: LOAD A: 1 ACC ← 1
STORE 2 R2 ← <ACC>
12 : WRITE 2 ghi ra <R2>
HALT Dừng máy
Mô hình các máy RAM 13

Ví dụ 2.2 : Chương trình RAM tính nn


READ 1 R1 ← số nguyên trên ô của băng vào
LOAD 1 ACC ← <R1>
JGTZ 6 nếu <ACC> ≥ 0, nhảy đều 6
WRITE A:0 in ra 0
JUMP 22 về lệnh dừng
6 : LOAD 1 ACC ← <R1>
STORE 2 R2 ← <ACC>
LOAD 1 ACC ← <R1>
DECR 0 ACC ← <ACC> − 1
STORE 3 R3 ← <ACC>
11 : LOAD 3 ACC ← <R3>
JGTZ 14 nếu <ACC> ≥ 0, nhảy đến 14
JUMP 21 nhảy đến 21 nếu <ACC> < 0
14: LOAD 2 ACC ← <R2>
MULT 1 ACC ← <ACC> * <R1>
STORE 2 R2 ← <ACC>
LOAD 3 ACC ← <>
DECR 0 ACC ← <ACC> − 1
STORE 3 R3 ← <ACC>
JUMP 11 nhảy đến 11
21: WRITE 2 in ra nội dung <R2>
22: HALT dừng
Ta có thể viết đoạn trình Pascal minh họa trình RAM như sau :
begin
read (R1)
if R1 < 0 then write (R0)
else begin
R2:= R1 ; R3:= R1 − 1 ;
while R3 > 0 do begin R2:= R2*R1 ; R3:= R3–1 end ;
write (R2)
end
end ;
Ta thấy một trình RAM xác định một ánh xạ từ tập các băng vào lên tập các
băng ra. Đây là ánh xạ bộ phận (partial map) vì một số ánh xạ có thể không xác
định trên một số băng vào, nghĩa là chương trình ứng với băng vào đó không
dừng.
Ta có thể giải thích ánh xạ này ở dưới hai dạng : dạng hàm và dạng ngôn ngữ.
14 Lý thuyết tính toán

Dạng hàm f : S* → S*
Giả sử chương trình P luôn đọc được từ băng vào n số nguyên x1, x2, ..., xn và
ghi lên băng ra không quá một số nguyên y ở ô đầu tiên, khi đó ta nói P tính hàm
f (x1, x2, ..., xn) = y.
Dạng ngôn ngữ L ⊆ S*
Giả sử trên băng vào có câu w = a1a2 ... an với ai ở ô thứ i, i = 1.. n, còn ô thứ
n+1 chứa # là ký tự kết thúc dãy. Ta nói w được thừa nhận bởi chương trình
RAM nếu nó đọc được hết w, kể cả ký tự #, sau đó viết lên ô đầu tiên của băng ra
một ký tự kết quả và dừng.
Ta nói máy RAM thừa nhận một ngôn ngữ L đã cho nếu thừa nhận mọi câu
w∈L. Nếu w∉L thì máy RAM có thể không đọc hết w, ghi ký tự kết thúc lên
băng ra, hoặc bị hóc (crash), hoặc không bao giờ dừng.
Sự khác nhau cơ bản giữa mô hình máy RAM vừa mô tả ở trên và các máy
tinh điện tử hiện nay là ở chỗ :
1) Ta đã giả thiết có thể sử dụng một số lớn tùy ý các thanh ghi, tuy nhiên
trong thực tế điều này rất khó thực hiện. Tương tự, ta đã giả thiết có thể đặt
một số nguyên lớn tùy ý vào một thanh ghi nào đó, hoặc vào một ô nào đó
trên băng vào, hoặc trên băng ra. Nhưng điều này cũng rất khó thực hiện
trong thực tiễn.
2) Ta đã giả thiết rằng chương trình có sẵn trong bộ nhớ RAM chỉ có thể đọc
(không thể bị thay đổi khi chạy chương trình), khác với các bộ nhớ kiểu
thanh ghi. Điều này cũng không xảy ra với các máy tính thông dụng.
Sự khác nhau chi tiết như sau :
3) Các lệnh sơ cấp được chọn hạn chế hơn so với các ngôn ngữ assembler
Tuy nhiên, người ta có thể nói rằng vẫn không làm mất tính tổng quát nếu
giảm đáng kể tập hợp các lệnh sơ cấp.
4) Các dữ liệu đưa vào không phải dưới dạng các số nguyên được đọc toàn bộ
một lần trong một ô, mà dưới dạng một dãy ký tự (một dãy các chữ số),
tương tự như vậy đối với các kết quả ra.
Ta hãy xem làm cách nào để giải quyết vấn đề do 4) đặt ra : Trong các máy
tính, các số nguyên thường được biểu diễn theo hai cách phân biệt là biểu diễn
thập phân, hoặc biểu diễn nhị phân. Cách biểu diễn nhị phân có lợi thế hơn vì chỉ
sử dụng hai chữ số. Máy tính sẽ chuyển đổi chuỗi ký tự biểu diễn số nguyên
thành biểu diễn nhị phân để đặt trong các thanh ghi, sau đó chuyển đổi kết quả
đang ở dạng biểu diễn nhị phân của số nguyên thành chuỗi ký tự trên băng ra.
Điểm 1) trên đây có nghĩa : trong mọi trường hợp, kích thước của bài toán cần
giải là đủ bé để bộ nhớ máy tính có thể chứa hết ở dạng nhị phân trong các đơn vị
nhớ, hay từ nhớ (memory word). Chú ý rằng nếu chỉ làm việc với cách biểu diễn
số nguyên bởi chuỗi các chữ số thì không còn giả thiết số lớn tùy ý nữa.
Mô hình các máy RAM 15

Cuối cùng, sự khác nhau ở điếm (2) đưa đến việc xây dựng một mô hình
tương tự mô hình RAM, nhưng chương trình được đặt trong các thanh ghi (và do
vậy có thể bị thay đổi), được gọi là mô hình các máy RASP (Random Access
with Stored Program). Sự khác nhau cơ bản với các máy RAM là vùng nhớ lưu
giữ chương trình của RASP hoàn toàn không khác gì so với các vùng nhớ khác.
Máy RASP
Để thuận tiện cách trình bày, ta quy ước rằng mỗi lệnh RASP chiếm chỗ hai
thanh ghi liên tiếp nhau : thanh ghi đầu chứa trường toán hạng, thanh ghi thứ hai
chứa trường địa chỉ của lệnh.

x1 x2 ... xn Băng vào

R0 Thanh tổng
R1
R2
Chương trình
Rp
i
Thanh đếm lệnh
... Các thanh ghi khác

y1 y2 y3 ... Băng ra

Hình 2.2 Sơ đồ một máy RASP


Trong máy RASP, thanh tổng luôn luôn là R0, thanh ghi R1 dùng để lưu giữ
trung gian nội dung của thanh tổng.
Các thanh ghi từ 2..p (với p là một số nguyên lẻ) chứa chương trình của máy
RASP, và các thanh ghi tiếp theo, từ p + 1 trở đi, là các thanh ghi còn trống.
Sự khác nhau cớ bản với mô hình máy RAM là có thể thay đổi một thanh ghi
chứa chương trình, và do vậy, có thể thay đổi chương trình.
16 Lý thuyết tính toán

II. Mô phỏng một máy bởi một máy khác


Từ đây trở đi, người ta thường phải mô phỏng một máy bởi một máy khác :
máy mô phỏng sẽ bắt chước hay nhại lại (mime) mỗi một lệnh của máy được mô
phỏng, bằng cách thực hiện nhiều lệnh (nói chung) để đi đến cùng một kết quả.
Khi có một máy RAM M có chương trình P chạy và sử dụng đến thanh ghi 0
và các thanh ghi từ 1 đến p (giá trị của p thay đổi tùy theo dữ liệu), người ta nói
rằng một máy RAM M’ có chương trình P’ mô phỏng chức năng của máy RAM
M nếu :
Tồn tại một ánh xạ I từ N vào N mà biến 0 thành 0.
Mỗi lệnh của P được thay thế bởi một lệnh của P’ sao cho, mỗi lần thực
hiện chương trình P (nghĩa là với mọi dữ liệu), nội dung mỗi thanh ghi I (r)
của M’ sau khi thực hiện dãy các lệnh của P’ là giống như nội dung của
thanh ghi R của M sau khi thực hiện các lệnh tương ứng của P.
Ví dụ 2.3 : Dịch chuyển các địa chỉ thanh ghi.
Xuất phát từ một máy RAM có chương trình P khi chạy sử dụng thanh ghi 0
và các thanh ghi từ 1 đến p, ta có thể xây dựng một máy RAM khác có chương
trình Pk mô phỏng trình P với ánh xạ I xác định bởi :
I (0) = 0
I (r) = k + r với r > 0.
Việc mô phỏng máy RAM sẽ trở nên tầm thường nếu không xử lý các lệnh
gián tiếp. Đối với kiểu lệnh này, vấn đề là thay đổi địa chỉ các thanh ghi sử dụng
đến, bằng cách thêm giá trị k (nhờ lệnh ADD A:k) vào nội dung của thanh ghi
liên quan (đặt sau I) để thực hiện kiểu gián tiếp.
Các máy RASP cũng có thể được mô phỏng và có thể xử lý kiểu lệnh gián
tiếp.
Dịch chuyển các địa chỉ thanh ghi của RASP
Những gì mà một máy RAM làm được thì một máy RASP cũng có thể được
làm được. Thật vậy, nếu chương trình của RASP được lưu giữ trong các thanh
ghi từ 2 đến p, chỉ cần thực hiện một sự biến đổi của p lên tất cả các số của thanh
ghi sử dụng bởi máy RAM tương ứng.
Tuy nhiên trong mô hình của RASP, kiểu lệnh gián tiếp được xử lý như sau :
Giả sử một chương trình P của máy RASP được lưu giữ từ thanh ghi số 2 đến
p và khi chạy sử dụng đến các thanh ghi từ p + 1 đến q. Ta sẽ xây dựng một
chương trình mới mô phỏng P được lưu giữ trong các thanh ghi từ 2 đến p’.
Khi chạy, chương trình sử dụng đến các thanh ghi từ p’ + 1 đến q + p’ − p,
bằng cách thay thế mỗi lệnh kiểu gián tiếp bởi 6 lệnh không là kiểu gián tiếp, sao
cho kết quả của 6 lệnh này là tương tự trên mỗi thanh ghi số p’ + i với kết quả
của lệnh được mô phỏng trên mỗi thanh ghi số p + i.
Mô hình các máy RAM 17

Một cách cụ thể hơn, p’ − p có giá trị 2 × (6 − 1) × s = 10s với s là tổng số


lệnh kiểu gián tiếp của chương trình.
Giả sử ta cần mô phỏng một trong các lệnh MULT I: n của chương trình
RASP cần mô phỏng, được lưu giữ trên các thanh ghi 30 và 31 của máy xuất
phát. Để mô phỏng, ta cần tạo ra nhóm 6 lệnh chiếm 12 liên tiếp, giả sử từ thanh
ghi số 50 đến 61, với giả thiết chương trình có trên hai lệnh kiểu gián tiếp. Lệnh
đầu tiên của nhóm 6 lệnh này là lưu giữ nội dung của thanh tổng vào thanh ghi
R1 :
50 STORE
51 1 R1 ← <ACC>
Lệnh thứ hai nạp vào thanh tổng nội dung của thanh ghi n + p’ − p (tương ứng
với thanh ghi n trong chương trình xuất phát) :
52 LOAD
53 n + p’- p ACC ← <Rn> + (p’ − p)
Lệnh thứ ba tăng nội dung của thanh tổng lên p’ − p để lúc này thanh tổng
chứa địa chỉ của thanh ghi chứa giá trị cần nhân :
54 ADD A:
55 p’- p ACC ← <ACC> + (p’ − p)
Lệnh thứ tư gán trực tiếp lệnh thứ sáu bằng cách thay đổi trường địa chỉ của
lệnh này (việc thực hiện chương trình làm thay đổi bản thân chương trình đó) :
56 STORE
57 61 R61 ← <ACC>
Lệnh thứ năm khôi phục nội dung lúc đầu của thanh tổng :
58 LOAD
59 1 ACC ← <R1>
Cuối cùng, thực hiện phép nhân :
60 MULT
61 x ACC ← <ACC> * <Rx>
Ở đây, lúc bắt đầu thực hiện chương trình, x là một giá trị nào đó, và mỗi lần
thực hiện, nếu thanh ghi n của máy xuất phát chứa số nguyên a, thì x sẽ có giá trị
là a + p’ - p tại thời điểm thực hiện lệnh đặt trong các thanh ghi 60 và 61. Như
vậy, khi mô phỏng trình P thành P’ đặt trong các thanh ghi RASP, P’ đã bị thay
đổi khi thực hiện nó.
18 Lý thuyết tính toán

Ví dụ 2.4 : Dịch chuyển một trình RASP có một lệnh dạng gián tiếp :
⎧⎪1 + a nãúu a ≤ b
Tính in ⎨
⎪⎩1 + b nãúu a > b
Chương trình RASP xuất phát P : sau khi dịch chuyển thành P’ :
2 READ R27 ← a READ
3 27 37
4 READ R27 ← b READ
5 28 38
6 LOAD A: ACC ← <R27> LOAD A:
7 27 37
8 STORE R26 ← <ACC> STORE
9 26 36 Phần này là
10 LOAD ACC ← <R28> LOAD dịch chuyển của P
11 28 38 với ánh xạ :
12 SUB I(r) = r+p’-p = r+10
ACC ← <ACC> - <R27> SUB
13 27 37
14 JGTZ JGTZ
OC ← 18, if <ACC> > 0
15 18 18
16 INCR R26 ← < R26> + 1 INCR
17 26 36
18 LOAD A: LOAD A:
ACC ← 1
19 1 1
20 ADD I: ACC ← <ACC> + <<R26>> STORE R1 ← <ACC>
21 26 1
22 WRITE LOAD ACC ← <R36>
In ra <ACC>
23 0 36
24 HALT ADD A: ACC ← <ACC> +
Dừng
p 25 0 10 10
P+1 26 27 / 28 Nội dung 27, hoặc 28 STORE R31 ← <ACC> : số
27 a Chứa giá trị a 31 x
q 28 b Chứa giá trị b LOAD ACC ← <R1>
29 1
30 ADD ACC←<ACC> +
Nội dung thay đổi : số x <Rx>
31 0

32 WRITE
33 0
34 HALT
P’ 35 0
P’+1 36 37 / 38 Nội dung 37, hoặc 38
37 a Chứa giá trị a
q +P’-p 38 b Chứa giá trị b
Hình 2.3. Trình P’ bị thay đổi khi thực hiện
Mô hình các máy RAM 19

III. Một mô hình thô sơ kiểu RAM


Trong phần này, ta sẽ chỉ ra rằng có thể thu gọn về một tập hợp lệnh sơ cấp rất
nhỏ. Đặc biệt, ta sẽ chỉ ra rằng có thể xử lý ký tự và xử lý các số nguyên.
Trước hết, ta quay lại cách biểu diễn các số nguyên. Trong máy tính, có hai
cách biểu diễn : biểu diễn nhị phân cho phép lưu trữ một số nguyên trong một
thanh ghi làm tiết kiệm chỗ và tính toán nhanh chóng nhưng có nhược điểm là độ
lớn của số nguyên phụ thuộc vào kích thước thực tế của thanh ghi (hữu hạn).
Cách biểu diễn thứ hai là sử dụng một dãy chữ số trên bảng chữ {0.. 9}. Thực
tế, ngay cả khi người ta có thể biểu diễn trong một thanh ghi nhiều ký tự (thường
không quá 4), thì để biểu diễn một số nguyên cũng đòi hỏi có nhiều thanh ghi.
Mặc dù dải số nguyên có thể biểu diễn được là khá lớn, nhưng do số lượng các
thanh ghi trong máy tính hiện nay bị hạn chế nên cách biểu diễn này cũng chưa
phải tối ưu.

III.1. Mô phỏng các phép toán trên chuỗi ký tự bởi các


phép toán trên các số nguyên
Mỗi ký tự được mã hóa bởi một dãy các chữ số nhị phân {0, 1} (chẳng hạn 8
chữ số cho một ký tự). Một chuỗi bit như vậy có thể dùng để biểu diễn các số
nguyên nhờ thực hiện các phép toán trên các số nguyên.
Chẳng hạn, ghép 198 và 7, dẫn đến phép nhân số nguyên biểu diễn chuỗi 198
với 28 rồi cộng thêm số nguyên biểu diễn chuỗi 7 vào tích số nhận được :

198 7 ~ 198 × 28 + 7

Hình 2.4 Ghép hai số nguyên


Ngược lại, các phép toán số học có thể được thực hiện trên biểu diễn các số
nguyên bởi các chuỗi ký tự, đó là các phép tính sơ cấp.
Chú ý rằng khi người ta tiến hành các phép toán trên các số nguyên theo cách
biểu diễn nhị phân, người ta đã xử lý trên các câu của bảng chữ {0, 1}, và phép
toán được thực thi trên các ký tự.
20 Lý thuyết tính toán

III.2. Thu gọn tập hợp các lệnh ngắt


Ta có thể chuyển đổi các lệnh ngắt JUMP n về hai kiểu lệnh là nhảy nếu gặp 0
(zero) JZERO và lệnh dừng máy HALP.
Lệnh JUMP n sẽ sử dụng thanh ghi R1 làm trung gian để lưu giữ nội dung của
thanh tổng, bằng cách thêm vào trước mỗi lệnh đã gắn nhãn các lệnh sau :
STORE 1 R1 ← <ACC>
LOAD 1 <ACC> ← R1
sau đó thay thế lệnh nhảy bởi :
STORE 1 R1 ← <ACC>
LOAD A: 0 <ACC> ← 0
JZERO n’ goto n’, if <ACC> = 0
Trong đó n’ là nhãn của lệnh STORE 1 đặt trước ngay lệnh có nhãn n trong
máy xuất phát.
Bài tập : Một cách tương tự, xây dựng lại lệnh JGTZ (nhảy nếu kết quả dương).

III.3. Thu gọn tập hợp các lệnh số học


Có thể chuyển đổi các lệnh số học (cộng, trừ, nhân, chia) về hai kiểu lệnh là
INCR (tăng 1) và DECR (giảm 1).
Chẳng hạn, lệnh nhân MULT n sẽ được chuyển đổi bằng cách thêm <n> lần
nội dung của thanh tổng. Sử dụng các thanh ghi từ 1 đến 3 làm trung gian, ta có
thể thay lệnh nhân bởi các lệnh sau :
STORE 1
LOAD n
STORE 2
LOAD A: 0
STORE 3
return: LOAD 2
JZERO lab
DECR 2
LOAD 1
ADD 1
STORE 3
JUMP return
lab: LOAD 3
Một cách tương tự, lệnh ADD n tăng thêm 1 (INCR) đúng <n> lần nội dung
của thanh tổng nhờ các lệnh STORE, LOAD, JGTZ, DECR ...
Mô hình các máy RAM 21

Từ đó, người ta có thể thu hẹp về một mô hình tính toán, gọi là mô hình RAM
thô sơ, chỉ có tập hợp các lệnh tối thiểu sau :
Lệnh Ý nghĩa
I <n> Tăng thêm 1 nội dung của thanh ghi n
D <n> Giảm bớt 1 nội dung của thanh ghi n
Z <n> Đặt nội dung của thanh ghi n về 0
S <n, m> Hoán đổi nội dung các thanh ghi n và m
J <n> (i, j) Nếu nội dung của thanh ghi n là 0, nhảy đến lệnh có nhãn i,
nếu không nhảy đến lệnh có nhãn j
HALT Dừng máy
Với tập hợp các lệnh trên, chương trình cũng là một dãy lệnh có mang nhãn.
Nếu <n> chỉ định nội dung của thanh ghi n, thì <<n>> chỉ định nội dung của
thanh ghi có số thứ tự là <n>.
Ví dụ 2.5 :
1: J <2> (5, 2)
2: I <1>
3: D <2>
4: J <3> (1, 1)
5: HALT
Nếu các thanh ghi 1 và 2 chứa lần lượt các số nguyên n và p, thì máy dừng lại
khi hai thanh ghi này chứa lần lượt n + p và 0.
22 Lý thuyết tính toán

IV. Máy RAM vạn năng


Trong phần này, chúng ta sẽ chỉ ra cách xây dựng một máy kiểu RAM có thể
mô phỏng bất kỳ máy RASP nào không sử dụng kiểu gián tiếp. Nguyên lý mô
phỏng như sau : lúc đầu, người ta đọc chương trình của máy RASP, chương trình
này được lưu giữ trong các thanh ghi từ 4 đến p của máy RAM. Thanh ghi R1
dùng làm địa chỉ gián tiếp ; thanh ghi R2 dùng để mô phỏng thanh đếm lệnh của
RASP. Thanh ghi R3 dùng để mô phỏng thanh tổng của RASP. Sau đó, thực hiện
một vòng lặp trên các phép toán được mô tả dưới đây, mỗi lần lặp là một lần mô
phỏng một lệnh của RASP.
Giả thiết rằng thanh ghi R2 chứa địa chỉ của thanh ghi đầu tiên trong hai thanh
ghi chứa lệnh cần mô phỏng (bắt đầu từ 4). Vòng lặp như sau :
Loop:
− Nội dung của thanh ghi của R2 được gán cho thanh tổng :
LOAD I: 2
− Phân tích mã phép toán của lệnh này và tùy theo mã đã phân tích mà nhảy
đến dãy lệnh tương ứng với nó. Ví dụ, nếu x là mã của phép chia DIV và y
là nhãn của dãy phép toán mô phỏng DIV, nếu z là mã của phép nhảy
dương JGTZ và t là nhãn của dãy phép toán mô phỏng JGTZ :
...
SUB A: x
JZERO y
ADD A: x
SUB A: z
JZERO t
ADD A: z
...
Sau đó, từ nhãn y, thực hiện mô phỏng phép toán chia DIV :
− Tăng nội dung R2 lên 1 để R2 chứa địa chỉ của thanh ghi chứa toán hạng :
INCR 2
− Gán địa chỉ này cho thanh ghi R1 :
LOAD I: 2
STORE 1
− Mô phỏng phép toán giữa nội dung thanh tổng của RASP và toán hạng này bởi
:
LOAD 3
DIV I: 1
STORE 3
Mô hình các máy RAM 23

− Tăng nội dung thanh ghi R2 lên 1 để R2 chứa địa chỉ của thanh ghi đầu tiên
trong hai thanh ghi chứa lệnh tiếp theo cần mô phỏng :
INCR 2
− Quay lại từ đầu vòng lặp bởi lệnh nhảy :
JUMP loop
Tương tự, từ nhãn t, thực hiện mô phỏng phép toán nhảy dương JGTZ :
− Kiểm tra nội dung thanh tổng của RASP, nếu dương thì nhảy :
LOAD 3
JGTZ lab
− Nếu kết quả âm, tăng nội dung của R2 lên 2 để R2 chứa địa chỉ của thanh
ghi đầu tiên trong hai thanh ghi chứa lệnh tiếp theo cần mô phỏng và quay
lại đầu vòng lặp :
INCR 2
INCR 2
JUMPloop
− Nếu kết quả dương, từ nhãn lab, tăng nội dung thanh ghi R2 lên 1 để R2
chứa địa chỉ của thanh ghi chứa toán hạng :
lab: INCR 2
− Gán địa chỉ này cho thanh ghi R1 :
LOAD I: 2
STORE 1
− Lấy địa chỉ của lệnh nhảy điều kiện :
LOAD I: 1
− Thay đổi sao cho thanh ghi R2 mô phỏng thanh đếm lệnh OC của RASP,
và quay lại đầu vòng lặp :
STORE 2
JUMPloop
Như vậy mỗi phép toán sơ cấp của RASP được mô phỏng bởi một dãy các lệnh
lặp của máy RAM. Máy RAM vừa mô phỏng có dữ liệu là chương trình P của một
máy RASP bất kỳ, theo sau là một dữ liệu D cho chương trình P. Máy RAM có kết
quả là kết quả của P trên dữ liệu D. Máy RAM mô phỏng hoạt động của mọi máy
RASP.
Một cách tương tự, người ta có thể xây dựng một máy RAM mô phỏng hoạt
động của tất cả máy RAM. Một máy RAM dựa trên mô hình tính toán mô phỏng
hoạt động của tất cả các phần tử của mô hình như vừa xét được gọi là một máy
RAM vạn năng (universal).
24 Lý thuyết tính toán

Bài tập
1. Viết chương trình của một máy RAM tính nn với số nguyên n cho trước.
2. Viết chương trình của một máy RASP tính giá trị bình quân nguyên của dãy n
số nguyên cho trước, với n lẻ.
3. Viết chương trình của một máy RASP không sử dụng kiểu gián tiếp để tính
giống bài 2.
4. Viết chương trình của một máy RAM thô sơ tính :
a. Phần dư của phép chia m cho n, với m và n cho trước.
b. Số nguyên tố thứ n, với n cho trước
5. Chứng tỏ rằng có thể rút lệnh hoán đổi : S <n, m> trong máy RAM thô sơ.
6. Hãy tìm cách mô phỏng các phép toán logic sơ cấp trong một máy RAM,
trong một máy RASP và trong một máy RAM thô sơ.
7. Hãy cho biết tập hợp các phép toán sơ cấp để xử lý ký tự. Hãy tìm cách mô
phỏng chúng trong một máy RAM, trong một máy RASP và trong một máy
RAM thô sơ.
8. Viết chương trình của một máy RAM vạn năng.
CHƯƠNG 3

Mô hình các máy Turing


« If the human brain was so simple
that we could understand it,
then we would be so simple that we could not »
(L. Watson)

Mô hình các máy Turing (Turing machines model) là một trong trong những
mô hình được sử dụng rất rộng rãi trong lý thuyết tính toán. Trong chương này,
chúng ta sẽ tập trung mô tả hình thức các máy Turing, chức năng đoán nhận ngôn
ngữ và tính hàm của chúng. Từ đó chúng ta sẽ nghiên cứu các tính chất của lớp
các hàm T−tính được. Phần cuối chương trình bày các biến thể khác của mô hình
các máy Turing và các máy Turing không đơn định.

I. Mô tả và hoạt động của máy Turing


I.1. Mô tả máy Turing
Một máy Turing gồm :
Một băng vô hạn cả hai phía trái và phải được chia thành các ô liên tiếp
nhau. Mỗi ô chứa một thông tin hữu hạn (finite information) nào đó được
biểu diễn bởi một chữ cái (letter) hay ký tự. Tập hợp các chữ cái (hay ký tự)
này tạo ra bảng chữ của máy Turing, đưọc định nghĩa đồng thời với máy
Turing.
Một đầu đọc−ghi để đọc hay ghi (làm thay đổi) nội dung từng ô của băng,
và mỗi lần chỉ di chuyển, qua phải hoặc qua trái, một vị trí tương ứng với
một ô. Như vậy, tại mỗi thời điểm, chỉ duy nhất một ô được đọc, hoặc được
ghi mà thôi.
Một bộ nhớ phụ hữu hạn có thể tiếp cận tại mọi thời điểm, có thể biết được
nội dung và thay đổi được. Tất cả các nội dung có thể của bộ nhớ phụ này
được liệt kê hết lúc định nghĩa máy Turing, được chỉ định bởi một số thứ
tự, gọi là trạng thái của máy Turing.
Một chương trình là một tập hợp hữu hạn các quy tắc chỉ ra sự thay đổi các
thông tin trên băng và nội dung của bộ nhớ phụ.
Một cách hình thức, máy Turing được định nghĩa từ các thành phần sau đây :

PGS. TS. PHAN HUY KHÁNH biên soạn 25


26 Lý thuyết tính toán

Một bảng chữ S có tối thiểu hai ký tự, một trong chúng là một ký tự trắng,
ký hiệu # (hoặc B). Trên băng của máy Turing, mỗi ô chứa một ký tự của
bảng chữ này.
Một tập hợp hữu hạn các trạng thái Q. Mỗi trạng thái là một tên chỉ định
thông tin của bộ nhớ phụ hữu hạn.
Một chương trình P là một tập hợp con của Q×S´S´M´Q, trong đó,
M = {L, R} là tập hợp các chuyển động có thể của đầu đọc−ghi, tương ứng
với việc chuyển đầu đọc qua trái (Left) một ô, hoặc qua phải (Right) một ô.
Mỗi phần tử (q, x, y, m, p) của P là một quy tắc, được viết như sau :
q, x → y, m, p
với x và y ∈ S, q và p ∈ Q, m ∈ M, trong đó :
Cặp (q, x) là vế trái của quy tắc, cho biết điều kiện để áp dụng quy tắc.
Bộ ba (y, m, p) là vế phải của quy tắc, cho biết các thay đổi khác nhau khi
áp dụng quy tắc, theo một thể thức sẽ trình bày dưới đây.
Người ta thường biểu diễn một quy tắc của P dưới dạng sơ đồ như sau :
x | y, m
q p

Hình 3.1. Biểu diễn dạng sơ đồ một quy tắc của máy Turing

Như vậy, một máy Turing là một bộ ba T = <S, Q, P> được đặc tả một cách
hữu hạn. Trước khi giải thích họat động của một máy Turing, ta có nhận xét rằng
tồn tại nhiều cách định nghĩa máy Turing. Mặc dù những định nghĩa này không
làm ảnh hưởng đến hiệu lực của mô hình, nhưng đều có các nhược điểm.
Mô hình được chọn định nghĩa ở đây cũng có những điều bất tiện. Đó là cách
mô tả các ô của băng vô hạn. Ở đây ta đã quy ước rằng các máy Turing luôn luôn
có vô hạn các ô chứa ký tự trắng # về phía bên trái và về phía bên phải, chỉ có
một phần của băng gồm một số hữu hạn ô (nhưng không bị giới hạn) là hữu ích,
gọi là phần hữu ích (usable part).
Dãy ký tự chứa trong phần hữu ích này là một câu f trên bảng chữ S, nằm giữa
hai ký tự #. Người ta viết f#f.
Chú ý rằng một số tài liệu xem ký tự trắng không thuộc bảng chữ S, # ∉ S.

I.2. Hoạt động của máy Turing


Người ta gọi c là cấu hình (configuration) của một máy Turing T =<S, Q, P>
là một bộ ba :
c = (f, q, xg) ∈ S* ´ Q ´ SS*
sao cho câu fxg tạo thành phần hữu ích của băng vô hạn. Trạng thái q chỉ định nội
dung của bộ nhớ phụ. Đầu đọc−ghi được đặt trên ô chứa ký tự x.
Mô hình các máy RAM 27

Một máy Turing và một cấu hình của máy cho phép mô tả đầy đủ hệ thống.
Cho máy Turing T = <S, Q, P>, và c = (f, q, xg) là một cấu hình nào đó, ta nói
rằng tồn tại một chuyển tiếp (transition) hay dịch chuyển từ cấu hình c thành cấu
hình c’ = (f’, q’, g’), ký hiệu :
c Ã− c’
nếu và chỉ nếu :
− (q, x) là vế trái của quy tắc (q, x → y, m, q’) của P và :
− nếu m = R thì f’ = fy và g’ = g
− nếu m = L thì f = f’z và g’ = zyg, với z là ký tự trên băng.
Trong cả hai trường hợp, chuyển tiếp làm thay đổi nội dung của ô nằm dưới
đầu đọc−ghi, và dịch đầu đọc−ghi qua trái hoặc qua phải tuỳ theo giá trị chỉ
hướng của m (L hoặc R). Cuối cùng chuyển tiếp làm thay đổi nội dung của bộ
nhớ phụ, chuyển từ trạng thái q thành trạng thái q’.

←−− Phần hữu ích −−→

...### f x g ###...

Hình 3.2. Máy Turing trong cấu hình c = (f, q, xg)


Cho máy Turing T = <S, Q, P>, và c là một cấu hình, ta nói rằng tồn tại một
phép tính hợp lệ (valid computation) có độ dài n ≥ 0 dẫn từ cấu hình c đến cấu
hình c’, ký hiệu c Ã−n c’, nếu và chỉ nếu :
− tồn tại một dãy các cấu hình c0, c1, ..., cn sao cho c = c0, c’ = cn
− với mỗi i ∈ {0 .. n-1}, tồn tại một chuyển tiếp giữa ci và ci+1 : ci Ã− ci+1
Ta ký hiệu cÃ−* c’ là phép tính hợp lệ dẫn từ cấu hình c đến cấu hình c’ có độ
dài không biết chắc chắn (quan hệ Ã−* là đóng đối với các phép phản xạ và bắc
cầu của quan hệ Ã−).
Chú ý rằng người ta không xét các phép tính không hợp lệ.
Ví dụ 3.1 :
Cho máy Turing T =<S, Q, P> với S = {1, #}, Q = {q1, q2, q3, q4} và
P = { q1, 1 → 1, R, q2,
q2, 1 → 1, R, q1,
q1, # → #, L, q3,
28 Lý thuyết tính toán

q3, 1 → 1, L, q3,
q3, 1 → 1, R, q3,
q3, 1 → #, R, q1 }
Xét cấu hình c = (e, q1, 111), ta có thể có các chuyển tiếp sau :
c = (e, q1, 111) Ã− (11, q1, 1) Ã- (111, q2, #)
Từ cấu hình cuối cùng, không tồn tại quy tắc nào trong P có vế trái là (q2, #)
nên không thể tiếp tục được nữa.
Bây giờ xét cấu hình c’ = (e, q1, 1111), ta có các chuyển tiếp sau :
c’ = (e, q1, 1111) Ã− (e, q1, 111)
Ã− (11, q1, 11)
Ã− (111, q2, 1)
Ã− (1111, q1, #)
Ã− (111, q3, 1)
Ã− (11, q3, 1)
Ã− (11, q3, 11)
Ã− (1, q3, 111)
Ã− (e, q3, 1111) = (#, q3, 1111)
Ã− (e, q3, # 1111)
Ã− (#, q1, 1111) = (e, q1, 1111)
Cấu hình cuối cùng nhận được chính là cấu hình xuất phát c’. Như vậy quá
trình tính toán có thể lặp lại vô hạn.
Chú ý rằng phép tính trên không là phép tính duy nhất có thể, từ cấu hình
(111, q3, 1) chẳng hạn, người ta có thể thực hiện chuyển tiếp :
(111, q3, 1) Ã− (1111, q3, #)
Chúng ta sẽ quay lại xét hiện tượng này.
Như vậy, trong một số cấu hình, khi không còn tồn tại một chuyển tiếp nào có
thể, người ta nói rằng máy Turing dừng (halt) tại những cấu hình đó.
Một phép tính hợp lệ dẫn đến một cấu hình như vậy sẽ không thể kéo dài.
Người ta có thể nói về phép tính hợp lệ tối đa trong trường hợp này. Ký hiệu :
c Ã− c’
T
là sự kiện tồn tại một phép tính hợp lệ giữa các cấu hình c và c’ và không một
chuyển tiếp nào có thể kể từ cấu hình c’.
Ngược lại, xuất phát từ một số cấu hình, tồn tại các phép tính hợp lệ không
bao giờ dừng. Từ đó người ta có thể chia tập hợp các câu f ∈ S* thành hai phần :
Mô hình các máy RAM 29

Tập hợp các câu f sao cho xuất phát từ cấu hình (e, q1, f), máy Turing có ít
nhất một phép tính hợp lệ dừng, gọi là L(T).
Tập hợp các câu f sao cho từ cấu hình (e, q1, f), máy Turing không có một
phép tính hợp lệ nào dừng.

I.3. Cấu hình xuất phát của máy Turing


Bây giờ, ta cần xem xét những yếu tố bất tiện của mô hình máy Turing. Ta dễ
nhận thấy rằng không thể biết đâu là điểm bắt đầu và đâu là điểm kết thúc của dữ
liệu trên băng. Bởi vì phần hữu ích không phân biệt được với phần còn lại trên
băng. Để khắc phục điều bất tiện này, người ta đưa vào các quy ước đối với các
cấu hình xuất phát như sau :
Lúc đầu, phần hữu ích phải khác rỗng để loại trừ các khả năng liệt của các
máy Turing.
Lúc đầu, phần hữu ích không chứa hai ký tự # liên tiếp nhau và dễ dàng xác
định được vị trí bắt đầu và vị trí kết thúc để phân biệt với phần còn lại trên
băng.
Lúc đầu, đầu đọc−ghi được đặt trong phần hữu ích để chỉ định phần này.
Mặt khác, người ta cũng quy ước thêm như sau :
Trạng thái xuất phát phải luôn luôn là q1, gọi là trạng thái đầu (initial).
Đầu đọc−ghi đặt tại ký tự khác # và sát bên trái nhất của phần hữu ích.
Một câu f ∈ S* được gọi là được thừa nhận (accepted) bởi máy Turing nếu,
xuất phát từ cấu hình ban đầu (e, q1, f), máy Turing đã thực hiện một phép tính
hợp lệ và dừng. Ngôn ngữ L(T) gồm tập hợp các câu được thừa nhận, được gọi là
ngôn ngữ được thừa nhận (accepted language) bởi máy Turing.
Trong ví dụ trên, ngôn ngữ được thừa nhận là các câu chứa một số lẻ số 1 :
L(T) = { f ∈ S * | f gồm một số lẻ chữ số 1 }.

I.4. Máy Turing đơn định


Điểm bất tiện thứ hai trong mô hình máy Turing là có thể thực hiện nhiều
phép tính khác nhau tại mỗi thời điểm. Nếu với mọi cặp (q, x) ∈ Q ´ S, tồn tại
nhiều nhất một quy tắc của máy Turing có (q, x) là phần bên trái, khi đó từ một
cấu hình đã cho c, tồn tại duy nhất một phép tính hợp lệ có thể. Người ta gọi máy
Turing như vậy là đơn định (deterministic).
Ta dễ nhận thấy tính đơn giản của các máy Turing đơn định với quan niệm
như sau : một câu f ∈ S* không được thừa nhận ngay khi phép tính hợp lệ xuất
phát từ (e, q1, f) không dừng. Trong trường hợp này, chương trình P của máy
Turing :
P⊆Q´S´S´M´Q
30 Lý thuyết tính toán

là một hàm bộ phận (partial function) của Q ´ S vào S ´ M ´ Q, dễ dàng được


phân tách thành ba hàm bộ phận khác nhau có cùng miền xác định (domain)
trong Q ´ S :
hàm ký tự mới nc : Q ´ S → S
hàm dịch chuyển đầu đọc−ghi mh : Q ´ S → M
hàm trạng thái mới ns : Q ´ S → Q
Ba hàm này được định nghĩa như sau :
nc (q, x) = y
mh (q, x) = m
ns (q, x) = q’
nếu và chỉ nếu (q, x, y, m, q’) là một quy tắc của P.
Các máy Turing được sử dụng theo nhiều cách khác nhau. Ví dụ vừa được
trình bày trên đây mô tả cách thức máy Turing nhận biết các ngôn ngữ. Dưới đây,
ta sẽ tiếp tục trình bày cách máy Turing tính toán các hàm.

II. Các hàm T−tính được


Giả sử ta chỉ xét các máy Turing đơn định.
Cho T =<S, Q, P> là một máy Turing. Ta nói T xác định một hàm bộ phận fT
từ S* → S* như sau : miền xác định của hàm fT là ngôn ngữ được thừa nhận bởi
T, và với mỗi câu f ∈ S*, ta có một phép tính hợp lệ tối đa :
(e, q1, f) Ã− c’ = (g, q, h)
T
với fT được xác định bởi :
fT(f) = gh
gh được gọi là kết quả của phép tính của T đối với câu vào f.
Người ta cũng nói náy Turing T thực hiện (tính) hàm fT.
Ví dụ 3.2 :
Cho T1 = <S, Q, P> với S = {0, 1, #}, Q = {q1, q2, q3} và
P = { q1, 1 → 1, R, q1,
q2, 0 → 1, L, q3,
q1, 0 → 0, R, q1,
q2, 1 → 0 L, q2,
q1, # → #, L, q2,
q2, # → 1, L, q3 }
Mô hình các máy RAM 31

Bây giờ xét các cấu hình c1 = (e, q1, 10100) và c2 = (e, q1, 100111). Tồn tại
phép tính tối đa dẫn c1 và c2 đến các cấu hình (1010, q3, 1) và (10, q3, 1000)
tương ứng như sau :
c1 = { e, q1, 10100} Ã− (1010, q3, 1)
T
c2 = { e, q1, 100111} Ã− (10, q3, 1000)
T
Dễ dàng nhận thấy rằng, xuất phát từ một cấu hình c = (e, q1, f), tồn tại một
phép tính tối đa dẫn c đến cấu hình (g, q3, h) sao cho, nếu f là biểu diễn nhị phân
của số nguyên n, thì câu gh là biểu diễn nhị phân của số nguyên n + 1.
Người ta nói máy Turing T1 đã thực hiện hàm tính số nguyên kế tiếp
(successor) trên một biểu diễn nhị phân của số nguyên.

Ví dụ 3.3 :
Cho T2 = < S, Q, P> với S = {1, #}, Q = {q1, q2, q3, q4} và
P = { q1, 1 → #, R, q2,
q2, 1 → # R, q3,
q3, 1 → 1, R, q3,
q3, # → 1, L, q4 }
Nếu qui ước biểu diễn đơn nguyên (unary) của một số nguyên bởi viết liên
tiếp n+1 chữ số 1 (số nguyên 0 được biểu diễn bởi một chữ số 1) và các cặp số
nguyên biểu diễn theo quy ước này được đặt cách nhau một ký tự trắng #, khi đó,
dễ dàng nhận thấy rằng máy Turing T2 thực hiện hàm tính tổng hai số nguyên
cho kết quả là một biểu diễn đơn nguyên. Chẳng hạn :
(ε, q1, 11 # 111) Ã− (##1111, q4, 111)
T
Định nghĩa 3.1 :
Một hàm bộ phận φ từ S* → S* được gọi là tính được bởi máy Turing (Turing
−computable), viết tắt T−tính được, nếu tồn tại một máy Turing đơn định tính
được hàm này.
Rõ ràng, với mỗi hàm T−tính được, sẽ có vô số các máy Turing tính nó.
Chú ý rằng quan điểm tính được trong lý thuyết tính toán được nêu ra ở đây
liên quan chặt chẽ đến sự nhận biết (cognition) :
Một mặt, với mọi ngôn ngữ L ⊂ S*, sẽ có một hàm đặc trưng
(characteristic function) δL tương ứng được định nghĩa bởi :
δL(f) = 1 nếu f ∈ L
δL (f) = 0 nếu không (f ∉ L)
32 Lý thuyết tính toán

Người ta cũng kết hợp L với một hàm đặc trưng cục bộ (partial characteristic
function) δ‘L được định nghĩa bởi :
δ‘L(f) = 1 nếu f ∈ L
δ‘L(f) không xác định nếu không (f ∉ L)
Mặt khác, với mọi hàm φ : S* → S*, φ được kết hợp với một ngôn ngữ Gφ ,
trên S ∪ {#} chẳng hạn, gọi là đồ thị của hàm, được xác định bởi :
Gφ = { f # φ(f) | f ∈ Dom(φ) }
Sau đây ta sẽ chỉ ra rằng, lớp các hàm T−tính được là rất lớn, trước khi chỉ ra
rằng tồn tại các hàm không là T−tính được.

III. Lớp các hàm T−tính được


Trong mục này, ta sẽ xét một số hàm T-tính được rất sơ cấp (elementary
functions), để từ đó, ta xây dựng các hàm phức tạp hơn nhờ phép hợp thành. Ta
cũng tìm cách mở rộng khả năng hoạt động của các máy Turing.

III.1. Một số hàm sơ cấp


Ta xây dựng máy Turing để tính toán một số hàm rất sơ cấp từ G* vào G*,
n
hay (G*) vào G*, trong đó, G là một bảng chữ không chứa ký tự trắng #, và các
bộ−n (n−tuple) gồm các phần tử được ngăn cách nhau bởi một ký tự trắng #. Đó
là các hàm hằng, hàm chiếu, hàm kế tiếp và hàm kế trước.

III.1.1. Các hàm hằng (constant functions)


Xét hàm hằng :
n
Bin_FivnG : (G*) → G*
sao cho mọi dữ liệu vào là một bộ−n câu của G*, dạng f1#f2# ... #fn, hàm hằng
luôn trả về một câu nào đó của G*.
Ví dụ 3.4 :
Giả sử G = {0, 1} và n = 2, với mọi dữ liệu vào là một cặp câu dạng f#g,
Bin_Fiv2G luôn trả về một câu, chẳng hạn 101∈G* (101 là biểu diễn nhị phân
của số 5).
Xây dựng máy Turing thực hiện hàm hằng Bin_Fiv2G như sau :
T =<S, Q, P> với S = G ∪ {#}, Q = {q1, q2, q3, q4, q5} và
P = { q1, 1 → $, R, q1,
q1, # → #, R, q2,
q1, 0 → #, R, q1,
Mô hình các máy RAM 33

q2, 0 → #, R, q2,
q2, 1 → #, R, q2,
q2, # → 1, L, q3,
q3, # → 0, L, q4,
q4, # → 1, L, q5 }
Ta có : c = (e, q1, #01 #10) Ã−* ( #, q5, # 101 #).
T
Hàm hằng rất dễ triển khai và có thể xây dựng bất kỳ hàm hằng nào.

III.1.2. Các hàm chiếu (projection functions)


Xét hàm chiếu :
n
Projn, iG : (G*) → G*
sao cho với mọi bộ−n các câu của G*, hàm chiếu trả về câu thứ i của dãy này.
Ví dụ 3.5 :
Giả sử G = {0, 1}, n = 4 và i = 2, xây dựng máy Turing thực hiện hàm chiếu
Proj4, 2G để trả về kết quả là câu thứ hai trong dữ liệu vào là dãy bốn câu như sau :
T =< S, Q, P> với S = G ∪ {#}, Q = q1, q2, q3, q4, q5} và
P = { q1, 1 → #, R, q1,
q1, 0 → # R, q1,
q1, # → #, R, q2,
q2, 1 → 1, R, q2,
q2, 0 → 0, R, q2,
q2, # → #, R, q3,
q3, 1 → #, R, q3,
q3, 0 → #, R, q3,
q3, # → #, R, q4,
q4, 1 → #, R, q4,
q4, 0 → #, R, q4
q4, # → #, L, q5 }
Ta có c = (e, q1, 10#01#100#101#) Ã−* (#, q5, #10#)
T
Ta nhận thấy rằng hàm chiếu cũng rất dễ triển khai như hàm hằng và có thể
xây dựng bất kỳ kiểu hàm chiếu nào.

III.2. Các hàm kế tiếp (successor functions)


Xét hàm kế tiếp :
34 Lý thuyết tính toán

SuccG : G* → G*
sao cho với mọi câu f∈G*, hàm SuccG trả về câu kế tiếp của f theo thứ tự đã cho.
Ví dụ 3.6 :
Giả sử G = {0, 1, 2} với thứ tự 0<1<2, xây dựng máy Turing thực hàm kế tiếp
như sau :
T =< S, Q, P > với S = G ∪ {#}, Q = { q1, q2, q3} và
P = { q1, 0 → 0, R, q1,
q1, 1 → 1, R, q1,
q1, 2 → 2, R, q1
q1, # → #, L, q2,
q2, 0 → 1, R, q3,
q2, 1 → 2, R, q3,
q2, 2 → 0, L, q2,
q2, # → 1, R, q3 }
Ta có c = (e, q1, # 22 #)Ã−* (#1, q3, 00#)
T
Ta nhận thấy rằng có thể dễ dàng xây dựng các kiểu hàm kế tiếp cho mọi bảng
chữ và cho mọi kiểu thứ tự của các ký tự trong bảng chữ.

III.3. Các hàm kế trước (predecessor functions)


Tương tự hàm kế tiếp, ta có thể dễ dàng xây dựng hàm kế trước :
PredG : G* → G*
sao cho với mọi câu f∈G*, hàm PredG trả về câu kế trước của f trong thứ tự đã
cho của bảng chữ S. Để hàm PredG là toàn phần, ta cần quy ước rằng câu đứng
trước câu rỗng cũng chính là câu rỗng.
Bài tập : Xây dựng một máy Turing thực hiện hàm kế trước.

III.4. Sự hợp thành (composition)


Nhiều hàm được định nghĩa từ nhiều hàm khác hợp thành. Ta sẽ nghiên cứu
các kỹ thuật cho phép xây dựng lớp các hàm T−tính được nhờ phép hợp thành.
Mô hình các máy RAM 35

III.4.1. Các máy được tiêu chuẩn hóa


Một máy Turing được gọi là đã tiêu chuẩn hóa (standadized) nếu, khi tính
toán xong, đầu đọc-ghi được đặt tại vị trí khác ký tự trắng # cận trái nhất của
phần hữu ích trên băng.
←−− Phần hữu ích −−→

...### a ###...

Hình 3.3 Máy Turing được tiêu chuẩn hóa


Mệnh đề 3.1 :
Nếu T là một máy Turing, thì có thể xây dựng từ T một máy turing T’ khác
được tiêu chuẩn hóa cùng thực hiện một chức năng (tính hàm) như T.

Bài tập : Chứng minh mệnh đề 3.1

Mệnh đề 3.2 :
Có thể luôn luôn giả thiết được rằng trạng thái đầu (trạng thái xuất phát)
không nằm trong bất kỳ một vế phải nào của quy tắc.
Chứng minh :
Thật vậy, nếu q1 là trạng thái đầu, ta thêm vào Q một trạng thái mới q’1 và
thêm vào P mọi quy tắc dạng :
q’1, x → y, m, qi
sao cho quy tắc :
q1, x → y, m, qi
là một quy tắc của máy Turing đang xét. Vậy người ta chọn lại q’1 là trạng thái
đầu. Như vậy, máy Turing vừa thêm q’1 thực hiện cùng một chức năng với máy
Turing cũ và thỏa mãn điều kiện của giả thiết.
Lúc này, người ta có thể biểu diễn máy Turing có trạng thái đầu thỏa mãn
mệnh đề 3.2 bởi sơ đồ sau đây :

q1 T

Hình 3.4. Máy Turing T có trạng thái đầu


36 Lý thuyết tính toán

III.4.2. Các máy Turing được chuẩn hóa


Cho máy Turing T =<S, Q, P> có một tập hợp con A các trạng thái thõa mãn :
1. Không một trạng thái nào của A nằm trong vế trái của quy tắc
2. Với mọi trạng thái q∈Q\A và mọi ký tự x∈S, tồn tại một quy tắc của P có
(q, x) là vế trái.
Một máy Turing như vậy được gọi là đã được chuẩn hóa (normalized).
Nói cách khác, máy Turing là được chuẩn hóa nếu với một tập hợp trạng thái
A, một phép tính dừng nếu và chỉ nếu máy Turing rơi vào một trạng thái của A.
Một trạng thái của A được gọi là một trạng thái dừng (halt state)

Mệnh đề 3.3 :
Nếu T là một máy Turing, có thể xây dựng từ T một máy Turing T’ chuẩn hóa
thực hiện cùng chức năng với T.
(Tự chứng minh)
Chú ý rằng người ta có thể xem rằng máy Turing chỉ có một trạng thái dừng,
lúc đó, máy Turing có thể được biểu diễn bởi sơ đồ :

q1 T qh

Hình 3.5. Máy Turing T được chuẩn hóa


Nếu tiến hành đồng thời cả hai cách xây dựng vừa nêu, chúng ta sẽ nhận được
một máy Turing vừa được tiêu chuẩn hóa, vừa được chuẩn hóa.

III.4.3. Tổ hợp các máy Turing


Cho T là một máy Turing chuẩn hóa có một trạng thái dừng duy nhất qh, và T’
là một máy Turing bất kỳ nào đó. Ta định nghĩa máy Turing tổ hợp từ T và T’, ký
hiệu T next T’, bằng cách đánh số lại các trạng thái của T’ để nhận được các
trạng thái tách rời (disjoint) với các trạng thái của T và lấy trạng thái dừng của T
làm trạng thái đầu của T’ :
qh
q1 T T’
= q’1

Hình 3.6. Máy Turing T next T’


Chú ý rằng nếu T’ được tiêu chuẩn hóa (một cách tương ứng, được chuẩn hóa)
thì máy Turing T next T’ cũng được tiêu chuẩn hóa (được chuẩn hóa).
Rõ ràng rằng, nếu T được tiêu chuẩn hóa và thực hiện hàm f và nếu T’ thực
hiện hàm f’, thì máy Turing T next T’ thực hiện hàm ghép f’°f.
Mô hình các máy RAM 37

III.5. Lập trình trên ngôn ngữ bậc cao máy Turing
Để mở rộng phạm vi các lệnh thông dụng và sử dụng chúng như là các lệnh vĩ
mô (macro instruction), người ta định nghĩa các máy Turing tiện ích như sau :
Ví dụ 3.7 :
Xây dựng máy Turing T =< S, P, Q > cho phép dời đầu đọc−ghi qua phải đến
vị trí ký tự thứ n trong tập ký tự G là một tập hợp con của S. Giả sử lấy n = 2, ta
có tập hợp P gồm các lệnh như sau :
P = { q1, x → x, R, q1, với ∀x ∉ G
q1, y → y, R, q2, với ∀y ∈ G
q2, x → x, R, q2, với ∀x ∉ G
q2, y → y, R, q3, với ∀y ∈ G
q3, x → x, L, q4 } với ∀x ∈ S
Một cách tương tự, ta có thể xây dựng máy Turing cho phép dời đầu đọc−ghi
qua phải (hay qua trái) đến vị trí (ngay trước, hoặc ngay sau) ký tự thứ n trong G
là một tập hợp con của S.
Ta cũng có thể xây dựng một số máy Turing tiện ích khác để thực hiện các
chức năng như : chuyển thành hằng, phép chiếu, kế tiếp, kế trước, và các hàm
mới như sao chép, hoán vị.
Sau đây, ta sẽ mở rộng phương tiện thể hiện các máy Turing bằng cách đưa
vào các cấu trúc điều khiển và chỉ ra cách hoạt động của chúng.

III.5.1. Cấu trúc if then else và cấu trúc rẽ nhiều nhánh


Cho T là một máy Turing chuẩn hóa dừng ở các trạng thái qh , qh , ..., qh và
1 2 k
T1, T2, ..., Tk là những máy Turing bất kỳ, người ta định nghĩa phép tổ hợp tổng
quát (generalized combinator) từ phép tổ hợp next bởi :
T next if h1 : T1, if h2 : T2, ..., if hk : Tk
là máy Turing nhận được bằng cách đánh số lại các trạng thái của Ti để nhận
được các trạng thái tách rời nhau giữa chúng và tách rời các trạng thái của T,
bằng cách lấy trạng thái dừng qh của T làm trạng thái đầu của T1, lấy trạng thái
1
dừng qh của T làm trạng thái đầu của T2, ..., lấy trạng thái dừng qh của T làm
2 k
trạng thái đầu của Tk.
Nếu máy Turing T dừng với mọi dữ liệu vào, T sẽ thực hiện phép rẽ nhánh
theo các trường hợp khác nhau (với if then else là một trường hợp đặc biệt).
38 Lý thuyết tính toán

Chẳng hạn với k = 2, máy Turing T thực hiện lệnh if then else :

qh T1
1

q1 T
qh T2
2

Hình 3.7. Máy Turing T next if h1 : T1, if h2 : T2

III.5.2. Cấu trúc while


Cho T là máy Turing chuẩn hóa có hai trạng thái dừng qh và qh , và T’ là
1 2
một máy Turing chuẩn hóa có duy nhất một trạng thái dừng q’h. Giả thiết rằng T
và T’ có các trạng thái rời nhau. Người ta định nghĩa while T do qh : T’ là máy
Turing nhận được từ T và T’ bằng cách lấy trạng thái dừng qh của T làm trạng
2
thái đầu của T’ và lấy trạng thái dừng của T’ làm trạng thái đầu q1 của T.
Máy Turing while T do qh : T’ được vẽ như sau :

qh
1
q1 T
qh T’
2

Hình 3.8. Máy Turing while T do h2 : T’


Người ta nhận thấy rằng, các trạng thái của một máy Turing có thể được xem
như là các nhãn (label) của chương trình của chính máy này. Do vậy, các quy tắc
trong P dạng q, x → y, m, p có thể được viết dưới dạng :
q : if x then y, m next goto p
và bằng cách nhóm tất cả các quy tắc có cùng trạng thái q là vế trái, lúc này chỉ
cần viết q ở quy tắc đầu tiên liên quan.
Chương trình tìm phần tử kế tiếp ở ví dụ 3.7 bây giờ được viết lại như sau :
q1 : if 0 then 0, R next goto q1
if 1 then 1, R next goto q1
if 2 then 2, R next goto q1
if # then #, L next goto q2
q2 : if 0 then 1, R next goto q3
Mô hình các máy RAM 39

if 1 then 2, R next goto q3


if 2 then 0, L next goto q2
if # then #, R next goto q3
q3 : halt

III.6. Quản lý bộ nhớ


Khi xây dựng các máy Turing thực hiện các hàm phức tạp, người ta gặp phải
vấn đề quản lý bộ nhớ, nghĩa là khả năng tổ chức lại nội dung các ô ở trên băng.
Ta đưa vào các khả năng quản lý bộ nhớ cho máy Turing như sau :

III.6.1. Máy Turing chuyển một ô qua phải


Việc chuyển một ký tự sang bên phải được thực hiện đối với một bảng chữ có
ba ký tự là S = {#, 0, 1} nhờ máy Turing có tập hợp P gồm các quy tắc như sau :
P = { q1, 0 → #, R, q(0),
q1, 1 → #, R, q(1),
q(0), 0 → 0, R, q(0),
q(0), 1 → 0, R, q(1),
q(1), 0 → 1, R, q(0),
q(1), 1 → 1, R, q(1),
q(0), # → 0, R, q(#),
q(1), # → 1, R, q(#),
q(#), 0 → #, R, q(0),
q(#), 1 → #, R, q(1) }
Máy Turing này dừng lại khi gặp hai ký tự # liên tiếp. Từ cách xây dựng này,
dễ dàng xây dựng được các máy Turing chuyển k ô qua phải (hoặc qua trái).

III.6.2. Máy Turing chỉ sử dụng phần băng bên phải kể


từ vị trí đầu tiên của đầu đọc-ghi
Nếu T =< S, Q, P > là một máy Turing thực hiện hàm f, có thể xây dựng một
máy Turing khác mô phỏng T sao cho đầu đọc−ghi không bao giờ vượt qua bên
trái vị trí ban đầu.
Giả sử T1 là máy Turing đặt một dấu h ở vị trí đầu tiên của đầu đọc−ghi và di
chuyển nội dung câu vào một ô qua bên phải. Giả sử T2 là máy Turing cho phép
di chuyển nội dung một ô qua bên phải xuất phát từ vị trí đầu tiên của đầu
đọc−ghi (và đặt một ô ký tự trắng # tại vị trí ô đầu tiên đã di chuyển).
Như vậy, có bao nhiêu trạng thái trong máy T thì có bấy nhiêu máy sao chép
của T2 và giả thiết chúng đều đã được tiêu chuẩn hóa và chuẩn hóa. Ký hiệu T2i
40 Lý thuyết tính toán

là bản sao tương ứng với trạng thái qi, còn pi là trạng thái đầu và pi là trạng thái
1 h
cuối của T2i.
Xây dựng từ máy T một máy mới T3 có tất cả các quy tắc của T và các quy tắc
của tất cả các máy T2 , ngoài ra, P3 còn có thêm các quy tắc sau :
i
P3 = { qi, h → h, R, pi
1
pi , x → x, L, qi } với x ∈ S là ký tự bất kỳ.
h
Với các điều kiện trên, T1 next T3 là máy thỏa mãn yêu cầu đặt ra.

III.7. Một số máy Turing thông dụng


Sau đây ta sẽ xét một số máy Turing thực hiện các chức năng phức tạp hơn.

III.7.1. Sao chép


Xây dựng hàm :
CopyG : G* → (G*)2
sao cho ∀ câu f ∈ G*, với G = {0, 1}, hàm CopyG trả về câu f #f ∈ (G*)2.
Giả sử T1 là máy Turing đọc một ký tự và thay thế ký tự đó bởi ký tự đánh
dấu a, sau đó di chuyển qua phải để viết lại ký tự này tại vị trí của ký tự trắng #
đầu tiên gặp phải, sau đó quay trở lại ký tự đánh dấu a để thay thế nó bởi ký tự
ban đầu. Máy T1 dừng ngay lập tức ở bên phải vị trí này.
Cho T1 = < S, Q, P> với S = G ∪ {a, b, #}, Q = {q1, q2, q3, q4, q5, q6} và
P = { q1, 1 → a, R, q2,
q1, 0 → a, R, q4,
q2, 0 → 0, R, q2,
q2, 1 → 1, R, q2,
q4, 0 → 0, R, q4,
q4, 1 → 1, R, q4,
q2, b → b, R, q2,
q4, b → b, R, q4,
q2, # → 1, L, q3,
q4, # → 0, L, q5
q3, 0 → 0, L, q3,
q3, 1 → 1, L, q3,
q5, 0 → 0, L, q5,
Mô hình các máy RAM 41

q5, 1 → 1, L, q5,
q3, b, → b, L, q3,
q5, b → b, L, q5,
q3, a → 1, R, q6,
q5, a, → 0, R, q6 }
Xây dựng T2 là máy Turing :
while < tại trạng thái q1 không đọc ký tự b > : T1
Xuất phát từ câu vào fb#, T2 cho kết quả là fbf#. Vậy T2 là máy sao chép cần
xây dựng.

III.7.2. Kiểm tra bằng nhau


Cần xây dựng máy Turing so sánh hai câu cho trước có bằng nhau không.
Muốn vậy, ta xây dựng máy Turing có hai trạng thái dừng qYes và qNo sao cho
khi cho câu vào f#g, máy dừng ở trạng thái qYes nếu f = g và máy dừng ở trạng
thái qNo nếu f ≠ g.
Máy hoạt động như sau : thay đổi câu vào f#g thành fagb với a và b là hai ký
tự đánh dấu. Sau đó, trong khi f và g còn khác rỗng, thay thế các ký tự cuối của f
và g bởi a và b tương ứng rồi ghi nhớ chúng. Nếu sau khi thay thế, chúng khác
nhau, máy dừng ở trạng thái qNo. Nếu không, tiếp tục quá trình. Cho tới khi đồng
thời cả f và g đều rỗng thì máy dừng ở trạng thái thái qYes, nếu không phải, máy
dừng ở trạng thái qNo.

III.7.3. Liệt kê các câu, các cặp câu và dãy các câu
Việc liệt kê các câu của S* rất đơn giản : người ta liệt kê câu đầu tiên của S*
(là một hằng), sau đó lần lượt liệt kê câu kế tiếp của câu trước đó đã liệt kê.
Việc liệt kê các cặp câu được tiến hành như sau : giả sử máy Turing T1 đã có
trên băng vào một cặp câu, giả sử f#g, T1 thực hiện việc chép kế tiếp một cặp câu,
gồm câu đầu tiên của S*, là f, và câu kế tiếp của câu kia, là succ(g). Sau đó T1 lặp
đi lặp lại việc chép cặp câu tiếp theo bằng cách lấy câu kế tiếp của thành phần thứ
nhất, là succ(f), và câu kế trước của thành phần thứ hai, là pred(succ(g)), khi mà
thành phần này không phải là câu đầu tiên của S*.
Giả sử máy Turing T2 có cặp câu vào x#y trên băng, T2 thực hiện chép một
cặp câu, gồm câu kế tiếp của câu đầu tiên, là succ(x), và câu còn lại, là y. Sau đó,
T2 thực hiện lặp đi lặp lại việc chép cặp câu tiếp theo bằng cách lấy câu kế trước
42 Lý thuyết tính toán

của thành phần thứ nhất, là pred(succ(x)), khi mà thành phần này không phải là
câu đầu tiên của S*, và lấy câu kế tiếp của thành phần thứ hai, là succ(y).
Máy Turing cần tìm thực hiện chép một cặp câu gồm hai câu đầu tiên của S*,
sau đó lặp đi lặp lại thực hiện T1 next T2.
Bài tập : Mô tả máy Turing liệt kê dãy các câu trên S*.

III.7.4. Các hàm chiếu ngược (antiprojection function)


Xét hàm chiếu ngược :
n n-1
Antiprojn, iG : (G*) → (G*)
sao cho biến mỗi bộ−n là dãy n câu của G* thành bộ−(n−1) câu, bằng cách lấy đi
câu thứ i của dãy n câu.
Máy Turing thực hiện hàm chiếu ngược được mô tả như sau : sau khi đặt đầu
đọc−ghi ngay trước câu thứ i (tại ký tự # thứ i của dữ liệu vào), máy Turing đánh
dấu a tại vị trí này và xóa (thay thế bởi #) câu thứ i cho đến khi gặp ký tự # đặt
trước câu thứ i+1. Sau đó, máy thực hiện lặp đi lặp lại phép dời qua trái một ô
cho phần các câu còn lại (từ i + 1 đến n) cho đến khi gặp ký tự đánh dấu a. Máy
dừng lại sau khi đã xóa ký tự đánh dấu a.

III.7.5. Các hàm giao hoán


Hàm giao hoán (permutation function) :
n n
Permi, j : (G*) → (G*)
cho phép giao hoán câu thứ i và câu thứ j của dãy n câu :
n
(w1, ..., wi, ...,wj, ..., wn) ∈ (G*)
thành :
(w1, ...,wi-1, wj , wi+1 , ..., wj-1 , wi , wj+1 , ..., wn)
nghĩa là câu thứ i đổi chỗ cho câu thứ j và ngược lại.
Máy Turing thực hiện hàm giao hoán được xây dựng bằng cách tổ hợp cách
máy sao chép và máy chiếu ngược.

III.8. Các hàm T-tính được phức tạp hơn


Bây giờ ta sẽ xây dựng các máy Turing thực hiện các phép tính số học dựa
trên các công cụ đã có.
Phép cộng : Ta cần thực hiện phép cộng hai số nguyên hệ 2 : Giả sử m và n là
hai số nguyên được biểu diễn bởi hai câu u và v trên bảng chữ {0, 1}. Gọi dữ liệu
là u#v và ta cần chuyển nó thành uabv, với a và b là hai ký tự đánh dấu.
Mô hình các máy RAM 43

Đặt đầu đọc−ghi tại ký tự cuối cùng của v, tiếp theo, trong khi ký tự đọc được
(dưới đầu đọc−ghi) chưa là b thì ghi nhớ bằng cách xóa ký tự đọc được (0 hay 1)
và đi đến ngay trước ký tự a. Ở đây, tùy theo ký tự đã đọc (0 hay 1 hoặc ký tự
trắng # được xử lý hoàn toàn tương tự 0), tùy theo ký tự đã ghi nhớ, và theo một
số nguyên 0 hay 1 cũng đã ghi nhớ (phần nhớ do 1 + 1), lúc đó đã được khởi
động giá trị 0, viết ký tự a theo sau 0 hoặc 1 tùy theo kết quả (nghĩa là sự đối
chiếu của tổng 3 chữ số này), và ghi nhớ phần nhớ 0 hoặc 1 (tùy theo có hay
không ít ra là hai chữ số 1 trong 3 chữ số này). Tiếp tục quay lại ngay trước ký tự
trắng # đầu tiên bên phải, rồi lại quay đến ngay trước chữ a và trong khi phần
nhớ là 1, thay đổi ký tự đọc được và dời một ô qua bên trái : 1 được thay thế bởi
0, với phần nhớ vẫn giữ, và 0 được thay thế bởi 1, với phần nhớ thay đổi thành 0.
Từ đó nhận được câu fagb với fg là biểu diễn nhị phân của m + n.
Máy Turing xây dựng theo cách trên có thể thực hiện được phép cộng các số
nguyên biểu diễn trong một hệ đếm bất kỳ.
Bài tập : Xây dựng máy Turing thực hiện phép trừ, phép nhân và phép chia của
hai số nguyên biểu diễn trong hệ 2, hệ 10 hoặc trong một hệ đếm bất kỳ.

III.9. Nhận xét


Như đã trình bày, nhờ các máy Turing, ta có thể thực hiện được một lớp rộng
các hàm xử lý các phép tính số học. Tuy nhiên, như ta sẽ thấy về sau, lớp các
hàm T−tính được không chứa tất cả mọi hàm. Như vậy, ta không thể xây dựng
bất cứ mọi hàm nhờ các máy Turing. Vì vậy, trong những phần sau, ta cần
khoanh vùng chính xác các hàm T−tính được.
Bây giờ ta xét một hàm f từ Ν → Ν và bốn cách biểu diễn các số nguyên r1,
r2, r3 và r4 (chẳng hạn đơn phân, nhị phân, thập phân và thập lục phân). Giả sử f1
là hàm nhận đối số là một số nguyên n có dạng biểu diễn r1 để cho kết quả f (n)
có dạng biểu diễn r2. Giả sử f2 là hàm nhận đối số là một số nguyên n có dạng
biểu diễn r3 để cho kết quả f (n) có dạng biểu diễn r4. Khi đó, f1 là T−tính được
khi và chỉ khi f2 là T−tính được.
Theo cách xây dựng hàm f, ta thấy rằng có thể xây dựng được máy Turing TC
có dữ liệu vào là một số nguyên n dưới dạng biểu diễn r1 để có kết quả dưới dạng
biểu diễn r3. Tương tự, ta có thể xây dựng máy TD có dữ liệu vào là một số
nguyên m dưới dạng biểu diễn r4 để cho kết quả dưới dạng biểu diễn r2.
Nếu T’ là máy Turing thực hiện hàm f2, thì T =TC next T’ next TD là một máy
Turing thực hiện hàm f1.
Như vậy một hàm T−tính được phải không phụ thuộc vào cách biểu diễn lựa
chọn, miễn rằng cách biểu diễn này vẫn còn hợp lý. Nghĩa là người ta có thể
chuyển từ cách biểu diễn này qua cách biểu diễn khác nhờ một máy Turing.
44 Lý thuyết tính toán

Chính vì vậy mà người ta thường nói theo cách lạm dụng (excessively) về hàm
mà không chỉ rõ cách biểu diễn lựa chọn.
Chẳng hạn, tồn tại T−tính được phép cộng các số nguyên biểu diễn trong một
hệ đếm nào đó thì người ta nói rằng phép cộng các số nguyên là T−tính được.
Mối quan hệ hẹp giữa các ngôn ngữ và các hàm được chỉ rõ qua các mệnh đề sau.
Mệnh đề 3.4 :
Ngôn ngữ L là được nhận biết bởi một máy Turing khi hàm cục bộ đặc trưng
của L, viết d’L, là T−tính được.
Chứng minh :
Nếu ngôn ngữ L nhận biết bởi một máy Turing T, ta có thể giả thiết T được
chuẩn hóa và tiêu chuẩn hóa. Nếu T là một máy Turing viết ra hằng 1, thì máy
T next T1 là một máy Turing thực hiện hàm d’L. Nếu T’ là một máy Turing thực
hiện d’L, T’ nhận biết L.
Mệnh đề 3.5 :
Hàm f là T−tính được khi và chỉ khi đồ thị Gf của nó là được nhận biết bởi
một máy Turing.
Chứng minh :
«Chỉ khi» : Cho T là máy Turing thực hiện hàm f, ta cần chứng minh rằng đồ
thị Gf của nó được nhận biết bởi một máy Turing nào đó.
Nếu T là máy Turing thực hiện hàm f : f → f( f) = g, có thể giả thiết rằng T
được chuẩn hóa và tiêu chuẩn hóa, đầu đọc−ghi của T sẽ không bao giờ vượt qua
bên trái vị trí xuất phát.
Để xây dựng máy Turing nhận biết Gf, ta xây dựng hai máy Turing bổ trợ :
− T1 hoán vị hai câu vào (f#g trở thành g#f) và dời đầu đọc-ghi về vị trí
bắt đầu của câu thứ hai (câu mới),
− T2 so sánh hai câu vào g#g và sẽ không bao giờ dừng trong trường hợp
không bằng nhau.
Từ đây, máy Turing : T1 next T next T2 có thể nhận biết Gf.
«Khi» : Cho T là một máy Turing nhận biết ngôn ngữ Gf,, ta cần chứng minh
rằng có thể xây dựng được một máy Turing thực hiện hàmf.
Giả sử T là máy Turing nhận biết ngôn ngữ (hay đồ thị của φ) Gf ⊂ S*,
Gφ = { f # g | f ∈ Dom(φ) và g = φ(f) }
Ta xây dựng một máy Turing T’ thực hiện hàm f theo cách sau : nếu f là một
dữ liệu vào của T’, máy T’ sẽ liệt kê tất cả các cặp (g, n_ ) có thể, với g là một câu,
g∈S* và n là độ dài của phép tính (hay quá trình đoán nhận) đối với dữ liệu f #g
của máy T đã cho. Nếu T dừng trên f #g, thì T’ cũng dừng sau mỗi cặp liệt kê.
Mô hình các máy RAM 45

Ở đây, n_ là một biểu diễn nào đó của số nguyên n. Từ nay về sau, ta quy ước
rằng mọi số nguyên có gạch dưới chỉ định biểu diễn nhị phân của số nguyên đó.
Cụ thể, xuất phát từ máy T, đầu tiên ta xây dựng một máy TU sao cho với mọi
dữ liệu f#g và mọi số nguyên n, máy TU thực hiện đối với dữ liệu f#g#n_. và dừng
khi gặp trạng thái qYes nếu T thực hiện phép tính đối với dữ liệu f#g dừng ở độ
dài n, và dừng ở trạng thái qNo nếu T không dừng. Ta cũng giả thiết rằng, đầu đọc
của TU không bao giờ qua trái kể từ vị trí xuất phát, và, trong trường hợp thất bại
(dừng ở trạng thái qNo), TU xóa hết nội dung trên băng vào của nó.
Tiếp theo, ta xây dựng máy các máy Turing :
− T1 nhận dữ liệu vào f#g#n_ để trả về kết quả là f#g’#n_’, với (g’, n’) là cặp
câu theo sau cặp (g, n).
− T2 thực hiện sao chép f#g#n_ thành f#g#n_#f#g#n_ và đặt đầu đọc−ghi vị trí
bắt đầu câu f thứ hai.
− T0 chép qua bên phải f cặp (g, n) đầu tiên để nhận được f#g#n_. .
Từ đó, máy Turing T’ được xây dựng như sau :
T0 next T2 next TU next while T give qNo : T1 next T2 next T_
cho phép thực hiện f.
46 Lý thuyết tính toán

IV. Các biến thế khác của mô hình máy Turing


Theo quan niệm của lý thuyết tính toán, hai mô hình được gọi là tương đương
nếu những gì tính được (một cách tương ứng : nhận biết được, liệt kê được) trong
một mô hình này thì cũng có thể tính được (một cách tương ứng : nhận biết được,
liệt kê được) trong mô hình kia. Trong mục này, ta sẽ chỉ ra rằng các mô hình
biến thể (variant model) của mô hình các máy Turing tiêu chuẩn hoá đã xét trước
đây cũng chỉ là những mô hình tương đương với chúng.
Nhờ khái niệm về phép mô phỏng (simulation), trước hết ta cần chỉ ra rằng
các máy Turing nhiều băng và các máy Turing không đơn định có thể được mô
phỏng bởi các máy Turing tiêu chuẩn hoá. Sau đó, ta sẽ xem xét vấn đề về bản số
giới hạn (số lượng ký tự) của một bảng chữ.

IV.1. Mô phỏng một máy Turing bởi một máy khác


Định nghĩa 3.3 :
Một máy Turing T được mô phỏng bởi một máy T’ nếu xây dựng được một
phép đơn ánh i từ các cấu hình của T vào các cấu hình của T’, sao cho, nếu cÃ−
c’ trong T, thì i(c) Ã−* i(c’) trong T’. Máy T’ dừng kể từ một cấu hình xuất phát
i(c) nếu và chỉ nếu T dừng kể từ một cấu hình xuất phát c.
Nếu T’ mô phỏng T, thì hàm do T’ thực hiện sẽ cho phép tìm lại hàm do T
thực hiện modulo phép biểu diễn các đối tượng ( dữ liệu và kết quả).
Một cách cụ thể hơn, giả sử TC là một máy Turing thực hiện phép đơn ánh,
nghĩa là, xuất phát từ một dữ liệu của máy T, trả về một dữ liệu tương ứng cho T’
(người ta nói rằng dữ liệu đã được mã hóa). Giả sử TD thực hiện phép đơn ánh
ngược lại, nghĩa là xuất phát từ một kết quả của máy T’ trả về một kết quả cho T
(người ta nói rằng dữ liệu đã được giải mã). Khi đó máy :
TC next T’ next TD
quả thực đã thực hiện cùng một hàm với máy T.
Ví dụ 3.8 : Phép tính giữa hai ký tự đánh dấu
Cho T =<S, Q, P> là máy Turing thực hiện hàm f, xây dựng máy T’ trên bảng
chữ S ∪ {a, b}, với a và b là hai ký tự mới. Máy T’ sẽ mô phỏng máy T sao cho
một cấu hình (f, q, g) của T sẽ được mã hóa bởi một cấu hình (af, q, gb) của T’.
Cho Q’ và Q’’ là hai tập hợp các trang thái có song ánh (bijection) với Q. Đặt
q’i và q’’i lần lượt là các trạng thái của Q’ và Q’’ có song ánh với trạng thái qi
của Q. Xây dựng các tập hợp quy tắc P và P” như sau :
P’ = { qi, b → #, R, qi’,
q’i, # → b, L, qi } với ∀qi ∈ Q
Mô hình các máy RAM 47

P’’ = { qi, a → #, L, q’’i,


q’’i, # → a, R, qi } với ∀qi ∈ Q
Khi đó, máy T’ = <S ∪ {a, b}, Q ∪ Q’ ∪ Q”, P ∪ P”> cũng là một máy
Turing.
Bây giờ xây dựng máy Turing TC (với chương trình PC) có dữ liệu vào là câu
f và kết quả là câu afb :
PC = { q1, x → x, L, q2,
q2, # → a, R, q3,
q3, x → x, R, q3,
q3, # → #, R, q4,
q4, x → x, R, q3
q4, # → #, L, q5,
q5, # → b, L, q6,
q6, y → y, L, q6
q6, a → a, R, q7 }
Ở đây, x ≠ # và x ∈ S là ký tự bất kỳ, y ∈ S cũng là ký tự bất kỳ.
Xây dựng máy Turing TD (với chương trình PD) có dữ liệu vào là câu afb và
kết quả là câu f :
PD = { q1, y → y, R, q1,
q1, b → #, L, q2,
q2, y → y, L, q2,
q2, a → #, R, q3 }
Ở đây y là ký tự bất kỳ y ≠ a và y ≠ b.
Như vậy máy Turing :
TC next T’ next TD
thực hiện hàm f.
48 Lý thuyết tính toán

IV.2. Các biến thể của máy Turing


Biến thể quan trọng nhất và thông dụng nhất là máy Turing không đơn định
(non-deterministic). Tuy nhiên vẫn còn các biến thể khác với những thay đổi
không lớn. Ta sẽ nghiên cứu các máy Turing không đơn định ở chương cuối khi
nghiên cứu các lớp độ phức tạp.

IV.2.1. Máy Turing có k băng


Máy Turing loại này có k băng vô hạn về cả hai phía, mỗi băng có đầu
đọc−ghi riêng. Mỗi quy tắc lúc này có dạng :
q, x1, x2, ..., xk → y1, m1, y2, m2, ..., yk, mk, q’
với xi là ký tự nằm dưới đầu đọc-ghi, yi là ký tự thay thế cho xi, và mi∈{L, R} chỉ
hướng (qua trái hoặc qua phải) của đầu đọc-ghi tương ứng tại băng thứ i, i=1..k.
Giả sử T =<S, Q, P> là máy Turing có k băng như đã mô tả, ta mô phỏng T
bởi một máy Turing T’ hoạt động trên bảng chữ :
G = {a, b} ∪ Z, với Z = { <z1, z2, ..., zk> | zi ∈ S ∪ {#} },
với a, b và # là những ký tự mới thêm. Ta ký hiệu pi là phép đơn ánh :
pi(<z1, z2, ..., zk>) = zi.
Một cấu hình (q, f1g1, f2g2, ..., fkgk) của T (đầu đọc−ghi của băng thứ i đặt tại
ký tự đầu tiên của câu gi, được mã hóa bởi câu awb, với w ∈ Z*, sao cho với ∀i :
pi(w) = fi#gi (phần không sử dụng của mỗi băng là các ký tự #).
Lúc này, mỗi quy tắc của T dạng :
q, x1, x2, ..., xk → y1, m1, y2, m2, ..., yk, mk, q’
sẽ được mô phỏng bởi một dãy các quy tắc của T’ thực hiện các phép tính sau :
Xuất phát từ ký tự đánh dấu a, đầu đọc−ghi của T’ đọc các ký tự của w. Với
mỗi thành phần fi#gi, máy ghi nhớ trong các trạng thái của nó, trạng thái q hiện
hành của T và ký tự theo sau # là xi (ký tự đầu tiên của gi). Sau khi đã ghi nhớ hết
các thành phần bên trái của quy tắc, T’ thực hiện các thay đổi tương ứng với
thành phần bên phải của quy tắc này. T’ xem xét câu vào w để trên mỗi băng i :
Nếu mi = R, thay đổi # và xi tương ứng bởi yi và #, nghĩa là #xi → yi#.
Nếu mi = L và giả sử zi đứng trước # (ký tự cuối của fi), thay đổi zi, # và xi
tương ứng bởi #, zi và yi, nghĩa là zi#xi → #ziyi.
Cuối cùng, đầu đọc-ghi đặt tại ký tự đánh dấu a. Như đã chỉ ra ở trên, trong
phép tính giữa các ký tự đánh dấu, các ký tự a và b có thể bị xê xịch trong quá
trình tính toán do ký tự <#, #, ..., #> gây ra. Rõ ràng, máy Turing T’ một băng đã
mô phỏng máy Turing T có k băng.
Mô hình các máy RAM 49

IV.2.2. Các máy off−line và các máy có băng ra


Máy Turing có nhiều băng có đặc tính sau : trên một băng nào đó, đầu
đọc−ghi không làm thay đổi ký tự đã đọc. Nói cách khác, đầu đọc-ghi chỉ làm
nhiệm vụ đọc không bao giờ ghi, gọi tắt là đầu đọc, không làm thay đổi nội dung
câu vào trên băng. Do băng này chỉ dùng để lưu giữ và nhận biết dữ liệu vào, nên
được gọi là băng vào của máy Turing.
Một máy Turing k + 1 băng có một băng vào với đầu đọc chỉ di chuyển theo
một chiều duy nhất (giả sử quy ước từ trái qua phải) như vừa mô tả được gọi là
máy off−line. Rõ ràng, một máy Turing k băng có thể được mô phỏng bởi một
máy off−line có k + 1 băng (chỉ cần sao chép dữ liệu trên băng vào lên một băng
nào đó và sau đó chỉ làm việc với k băng còn lại).
Tương tự, ta có thể xây dựng máy Turing nhiều băng có một băng ra có đặc
tính như sau : trên một băng nào đó chọn làm băng ra, lúc đầu chỉ chứa toàn ký tự
trắng #, đầu đọc−ghi trên băng này chỉ di chuyển theo một chiều duy nhất (từ trái
qua phải). Nói cách khác, đầu đọc−ghi chỉ làm nhiệm vụ ghi, gọi tắt là đầu ghi,
để ghi các ký tự kết quả lên các ô, sau khi ghi xong, đầu ghi không bao giờ quay
lui trở lại để thay đổi nội dung đã ghi. Do đầu ghi chỉ di chuyển theo một chiều
nên thực tế, băng ra chỉ vô hạn về một phía mà thôi.
Máy Turing vừa có một băng vào và vừa có băng ra được biểu diễn như sau:
u y v # # # ... Băng vào

...### f x g ###...
Băng làm việc
q

w # # # # ... Băng ra

Hình 3.9. Máy Turing có một băng vào và một băng ra


Kiểu máy Turing có băng vào và băng ra được xem là kiểu cơ sở của các máy
Turing. Ưu điểm của kiểu máy này là tính đồng dạng (similitude) với mô hình
các máy RAM đã xét trước đây.

IV.2.3. Các máy Turing không đơn định


Chúng ta sẽ chỉ ra rằng nếu L là ngôn ngữ được nhận biết bởi một máy Turing
không đơn định, thì L cũng được nhận biết bởi một máy Turing đơn định.
Cho T là một máy Turing không đơn định. Từ T, người ta xây dựng một máy
Turing T’ đơn định có ba băng : băng thứ nhất chứa dữ liệu vào, trên băng thứ
hai, ta chép lại dữ liệu vào và tiến hành phép tính một cách lặp đi lặp lại. Còn
50 Lý thuyết tính toán

trên băng thứ ba, ta liệt kê tất cả các dãy số thứ tự của các quy tắc đã dùng đến để
tính toán của máy Turing T (trong các dãy số này có các dãy số thứ tự của các
quy tắc được dùng cho các tính toán hợp thức).
Phép tính thực hiện trên băng thứ hai như sau : áp dụng các quy tắc của T cho
dữ liệu vào đã được chép từ băng một, nếu được, thì dãy quy tắc này được liệt kê
trên băng thứ ba. Nếu phép tính này là hợp thức và dẫn đến các cấu hình dừng
của T, thì người ta dừng tính toán. Nếu không, thay thế nội dung của băng hai bởi
dữ liệu vào (đang được lưu giữ trên băng một) và tiến hành lại phép tính.
Rõ ràng, nếu một câu được nhận biết bởi T, một tính toán dẫn đến dừng máy
và liệt kê được các quy tắc đã dùng đến trên băng ba, thì phép tính của T’ cũng sẽ
dừng. Nếu một câu không được nhận biết bởi T, thì các dãy quy tắc của T sẽ liên
tục được liệt kê, không bao giờ dừng. Vậy T’ nhận biết cùng một ngôn ngữ với T.

IV.2.4. Thu gọn một bảng chữ còn ba ký tự


Cho máy Turing T =<S, Q, P> với | S|| = n. Nếu n ≤ 1 + 2k người ta có thể sử
dụng mã sau đây :
c(#) = #
và với ∀xi ∈ S, thì c(xi) là câu thứ i trên {0, 1} có độ dài k.
Mô phỏng máy T bởi máy T’ = <S’, Q’, P’>, trong đó :
S’ = {#, 0, 1}
Q’ là tập hợp các trạng thái <q, w, w’, i, m> (có 5 thành phần) với :
− q ∈ Q,
− w và w’ là các câu ∈ S’* có độ dài nhỏ hơn hoặc bằng k,
− i ≤ k, i là một số nguyên,
− m ∈ {L, R, ε}
Một cấu hình (f, q, g) của máy T được mã hóa bởi cấu hình của máy T’ :
(c (f), < q, w, ε, 0, ε>, c (g))
Còn P’ gồm ba loại quy tắc được định nghĩa như sau :
Mô hình các máy RAM 51

z Các quy tắc nhận biết mã ký tự :


<q, w, ε, 0, ε>, x → x, R, <q, wx, e, 0, e> nếu |wx| < k
Ở đây, T’ sử dụng các trạng thái có 5 thành phần để ghi nhớ trạng thái hiện
hành q của T (thành phần thứ nhất) và ghi nhớ quá trình đọc lần lượt k−1 ký tự
đầu tiên của mã của một ký tự (thành phần thứ hai). Nội dung ghi nhớ này sẽ
dùng để xây dựng các quy tắc mô phỏng P.
z Các quy tắc thay đổi ký tự mới :
Nếu q, xi → xj, m, p là quy tắc của P, và nếu wx có giá trị c(xi) và w’y có giá
trị c(xj) thì P’ có quy tắc :
<q, w, e, 0, e>, x → y, L, <q, wx, w’, k − 1, m>
Khi nhận biết được mã wx của ký tự, mã này sẽ được thay thế bởi mã w’y của
ký tự có mặt trong vế phải. Để bắt đầu thay thế, ta viết y, ký tự cuối của mã. Phần
còn lại của mã này là w’ sẽ được ghi nhớ trong trạng thái (thành phần thứ ba).
Cuối cùng, thành phần thứ tư là một bộ đếm được khởi động đến k − 1.
z Các quy tắc di chuyển đầu đọc−ghi :
Ta phải di chuyển đầu đọc-ghi theo chiều chỉ ra bởi m, được ghi nhớ trong
thành phần thứ năm của trạng thái.
Luôn luôn nếu quy tắc q, xi → xj, m, p ∈ P, và nếu wx có giá trị c(xi), thì sau
khi tiến hành mọi sự thay thế cần thiết, T’ sẽ rơi vào trạng thái <q, wx, e, 1, m>.
z Các quy tắc di chuyển trạng thái mới :
<q, wx, e, 1, m>, z → z, m, <p, e, e, 0, e>
Những sự thay đổi cần thiết được thực hiện nhờ các quy tắc :
<q, w, w’x, k − 1, m>, y → x, L, <q, w, w’, k − 1, m> và
<q, w, e, i, m>, x → x, m, <q, w, e, i − 1, m> với i > 0.
Trạng thái đầu của T’ là <q, e, e, 0, e> ∈ Q’.
Ví dụ 3.9 :
Với bảng chữ gồm 9 ký tự {x1, x2, ..., x8, #}, ta sử dụng mã 3 ký tự sau :
c(#) = #, c(x3) =010, c(x6) = 101,
c(x1) = 000, c(x4) = 011, c(x7) = 110,
c(x2) = 001, c(x5) = 100, c(x8) = 111
Chẳng hạn ta mô phỏng quy tắc (q, x4) → (x7, R, p) thành dãy các quy tắc :
52 Lý thuyết tính toán

<q, ε, ε, 0, ε>, 0 → 0, R, <q, 0, ε, 0, ε>


<q, 0, ε, 0, ε>, 1 → 1, R, <q, 01, ε, 0, ε>
<q, 01, ε, 0, ε>, 1 → 0, L, <q, 011, 11, 2, R>,
<q, 011, 11, 2, R>, 1 → 1, L, <q, 011, 1, 2, R>,
<q, 011, 1, 2, R>, 0 → 1, R, <q, 011, ε, 2, R>,
<q, 011, ε, 2, R>, 1 → 1, R, <q, 011,ε 1, R>,
<q, 011, ε, 1, R>, 0 → 0, R, <p, ε, ε, 0, ε>

IV.2.5. Rút gọn một bảng chữ còn hai ký tự


Cho T = <S, Q, P> với S = {#, 0, 1}
Ta có thể sử dụng mã có cùng độ dài 5 như sau :
c(#) = |#|||,
c(0) = ||#||,
c(1) = ||| # |
Ta mô phỏng T bởi máy Turing T’ = <{#, 1}, Q’, P’> trong đó : Q’ là tập hợp
các trạng thái có dạng : <q, w, w’, i, m> như ở trên đã trình bày với một cấu hình
:
(f, q, g)
được mã hóa bởi cấu hình :
(c(f), <q, ε, ε, 0, ε>, c(g)).
P’ là tập hợp các quy tắc cho phép nhận biết mã của một ký tự (được đặt trong
thành phần thứ hai của trạng thái), và thực hiện ba thay đổi (ký tự mới, di chuyển
đầu đọc-ghi và trạng thái mới) tuân theo vế phải của quy tắc sao cho hai thành
phần đầu tiên của trạng thái được dùng cho vế trái.
Nếu tại một thời điểm tính toán, máy nhảy ra ngoài phần được mã hóa, thì khi
đó sẽ gặp hai ký tự trắng # liên tiếp. Người ta sẽ thay thế năm ký tự # (5 là độ dài
của mã) bởi mã của ký tự # trước khi tính toán trở lại.

IV.3. Các máy Turing có băng vô hạn một phía


Như đã biết, nhiều tác giả chỉ nghiên cứu các máy Turing có băng vô hạn về
một phía. Thực ra, mô hình này tương đương với mô hình ta đã định nghĩa trong
phần quản lý bộ nhớ (mục III.6).
Mô hình các máy RAM 53

V. Máy Turing vạn năng


Trong mục này, ta sẽ giải thích vì sao có thể mã hóa các máy Turing bởi một
câu trên một bảng chữ đã cho, từ đó có thể đánh số các máy. Tiếp theo, ta sẽ chỉ
ra sự tồn tại của một máy Turing, gọi là máy Turing vạn năng (universal Turing
machine), có dữ liệu vào là số thứ tự (number) của một máy Turing T và một dữ
liệu vào khác f cùng đạt một kết quả như T đối với f, dù T và f như thế nào.
Không làm mất tính chất tổng quát, ta xét các máy Turing có Q = {q1, q2, ...,
qn} và S có 9 ký tự kể cả ký tự trắng # được ký hiệu tổng quát S = {x1, x2, ...,
x9}. Chẳng hạn bảng chữ Z = { #, 0, 1, q, x, L, R, ,, → }. Một quy tắc r ∈ P :
qi, xj → xk, m, ql
có thể được mã hóa bởi một câu trên Z như sau :
c(r) = qi, xj, xk, m, ql
trong đó, mỗi số nguyên i được biểu diễn dưới một dạng nhị phân _i . Từ nay về
sau, ta sẽ quy ước rằng mọi số nguyên đều ở dạng biểu diễn nhị phân, chú ý rằng
một số nguyên có gạch dưới (i_, j_, k_, l_ ) chỉ định biểu diễn nhị phân của số nguyên
đó.
Mã của một quy tắc sẽ là một câu của :
R = q{0, 1}*, x{0,1}* → x{0, 1}*, M, q{0, 1}* với M = { L, R}
Chú ý rằng ở đây R không sử dụng ký tự #. Chương trình của một máy Turing
gồm các quy tắc r1, r2, ..., rs có thể được mã hóa bởi câu :
c(r1) # c(r2) # ... # c(rs).
Ta nhận thấy rằng mọi máy Turing có thể được mã hóa bởi một câu trên Z.
Do đó các máy Turing là có thể đếm được. Từ đó, có thể gán cho mỗi máy
Turing một con số, chẳng hạn hạng của nó trong một thứ tự phân cấp quy ước
nào đó.
Giả sử Ti là máy Turing thứ i và gi là hàm được tính bởi máy Turing thứ i này.
Dễ dàng xây dựng được máy Turing TD sao cho với dữ liệu vào _i , cho ra kết quả
là câu dùng để mã hóa máy Turing thứ i như sau :
Ta xây dựng một máy Turing hai băng. Băng thứ nhất chứa dữ liệu vào ._i .
Trên băng thứ hai, ta liệt kê các câu của Z*, và với mỗi câu f đã liệt kê, ta kiểm
tra nếu đó là mã của một máy Turing, nghĩa là nếu f thuộc về (R#)*R ? Nếu đúng
như vậy, thì người ta giảm đi 1 số nguyên đang ở trên băng thứ nhất ( _i ← i_ −1)
và dừng lại nếu số nguyên nhận được là số không. Nếu không phải, tức là số
nguyên chưa là số không, hoặc nếu câu vừa liệt kê không là mã của một máy
Turing, thì người ta tiếp tục liệt kê các câu của Z*.
Mệnh đề 3.6 :
54 Lý thuyết tính toán

Có thể xây dựng được một máy Turing TU, gọi là máy Turing vạn năng, cho
phép thực hiện một hàm fu có hai đối số i và f sao cho, với mọi số nguyên i và
với mọi dữ liệu vào f của máy Turing thứ i (thực hiện hàm gi), fu thỏa mãn :
fu(i_ #f) = gi (f)
Chứng minh :
Vì tồn tại máy Turing TD nhận dữ liệu vào _i và cho kết quả là câu mã hóa máy
Turing thứ i, nên chỉ cần chứng minh rằng tồn tại một máy Turing T’U thực hiện
hàm f’u sao cho với mọi wi là mã của máy Turing thứ i, và với mọi f là dữ liệu
vào, sẽ có f’u(wi#f) =gi(f).
Ta sẽ chỉ ra cách xây dựng máy T’U nhờ hai máy Turing ba băng là TC và T”U
:
Máy thứ nhất TC thực hiện việc khởi động : dữ liệu vào wi#f được đọc và câu
wi bị xóa khỏi băng thứ nhất để chép lại lên băng thứ hai. Băng thứ ba được ghi
hằng q1_ . Khi kết thúc, máy TC ở cấu hình như sau :
− Băng thứ nhất chứa câu f với đầu đọc-ghi nằm phía trái của f.
− Băng thứ hai chứa câu wi với đầu đọc-ghi nằm phía trái của wi.
− Băng thứ ba chứa câu q1_ với đầu đọc-ghi nằm phía trái của q1_. .
Máy thứ hai T”U mô phỏng hoạt động của máy Ti, với chương trình wi của Ti
được ghi trên băng thứ hai của T”U theo cách sau:
Cấu hình uqnv của Ti được mã hóa bởi :
− Câu uv trên băng thứ nhất với đầu đọc−ghi đặt tại ký tự đầu tiên của v.
− Câu qn_ trên băng thứ ba.
Giả sử rằng lúc đầu, người ta đã có cấu hình xuất phát của Ti đã được mã hóa.
Một cách lặp đi lặp lại, ta thực hiện phép toán như sau :
Đầu đọc của băng thứ hai đặt ở bên trái, lần lượt di chuyển qua bên phải của
băng cho đến khi tìm thấy dãy #q. Lúc này máy so sánh số nguyên tiếp theo (số
của trạng thái của vế trái của một quy tắc) với số nguyên của trên băng thứ ba (ở
đó có mặt trạng thái hiện hành của máy được mô phỏng Ti), sau đó, so sánh ký tự
nằm dưới đầu đọc ở băng thứ nhất với ký tự được mã hóa nằm trên băng thứ hai
ở ngay sau dấu phẩy chỉ sự kết thúc của số thứ tự của trạng thái vừa được kiểm
tra.
Xảy ra hai trường hợp như sau :
− Chúng không đồng thời bằng nhau, có nghĩa vế trái của một quy tắc không
áp dụng được trong cấu hình được mã hóa lúc này. Ta tiếp tục di chuyển
Mô hình các máy RAM 55

đầu đọc của băng thứ hai qua trái. Nếu đã qua tất cả chương trình mà
không tìm thấy quy tắc áp dụng được, máy T”U dừng lại.
− Chúng bằng nhau, có nghĩa đã tìm thấy vế trái của một quy tắc của Ti áp
dụng được cho cấu hình được mã hóa lúc này. Chỉ còn việc thay đổi trên
các băng thứ nhất và thứ ba tương ứng với việc áp dụng quy tắc này.
Trên băng thứ hai, người ta đọc ký tự nào nằm ngay sau dấu mũi tên → dùng
để thay thế cho ký tự nằm trên băng thứ nhất ở dưới đầu đọc-ghi , và người ta
tiến hành thay thế. Tiếp theo, đọc sau dấu phẩy một ký tự L hoặc R chỉ chiều di
chuyển nào của đầu đọc-ghi của băng thứ nhất sẽ được thực hiện, và tiến hành
việc di chuyển này. Sau đó, đọc sau dấu phẩy tiếp theo trạng thái hiện hành mới
nào của máy Turing được chọn để chép lại trên băng thứ ba tại vị trí cũ.
Rõ ràng, máy T’u vừa mô tả đã mô phỏng được hoạt động của máy Turing có
chương trình nằm trên băng thứ hai. Máy này dừng lại trên một dữ liệu vào f ở
băng thứ nhất nếu và chỉ nếu máy mô phỏng T’U dừng trên f. Trong trưòng hợp
này, những gì mà máy này có trên băng thứ nhất thì máy mô phỏng cũng có đúng
như vậy. Từ đó, máy :
T’U = TC next T”U
là máy cần tìm kiếm.
Chú ý rằng ta có thể dễ dàng tổ hợp máy TD đã đưa ra ở đầu chứng minh này
với máy TC. Nếu ký hiệu T’C là máy tổ hợp nhận được , thì ta có :
TU = T’C next T”U.
Cũng chú ý thêm rằng máy Turing vạn năng TU mô phỏng họat động của mọi
máy Turing trên một bảng chữ gồm có 9 ký tự. Đồng thời TU cũng là máy trên
một bảng chữ có 9 ký tự. Rõ ràng, ta có thể nhận được cùng một lúc kết quả với
bất kỳ kích thước nào (k ≥ 2) của bảng chữ.

VI. Tồn tại các hàm không là T−tính được


Trong mục này, nhờ kỹ thuật chéo (diagonization argument), ta sẽ chứng
minh rằng tồn tại các hàm không là T−tính được.
Mệnh đề 3.7 :
Không tồn tại máy Turing tính được hàm th được định nghĩa như sau : với
mọi cặp số nguyên i và j :
th(i, j) = 1 nếu máy Turing số hiệu i dừng trên dữ liệu vào j,
th(i, j) = 0 nếu không dừng.
Ta nhận thấy phát biểu này thoả mãn cho mọi biểu diễn của các số nguyên
trong một hệ đếm bất kỳ.
Chứng minh :
56 Lý thuyết tính toán

Bằng phản chứng, ta giả thiết rằng tồn tại một máy Turing T như vậy. Xuất
phát từ T, ta có thể xây dựng một máy Turing T’ khác T thực hiện hàm g như sau
: với mọi số nguyên i :
g(i) = 1 nếu th(i, i) = 0,
g(i) = không xác định nếu th(i, i) = 1
Máy Turing T’ được xây dựng như sau :
TC(i) = (i, i) ∀i∈Ν
T’ = TC next T next TD TD(0) = 1,
TD(i) không dừng ∀ i > 0

Ở đây, máy Turing TC nhận dữ liệu vào là một số nguyên i để trả về kết quả là
cặp (i, i) và máy Turing TD cho kết quả là 1 với từ dữ liệu vào là 0 và không bao
giờ dừng trên một dữ liệu vào nào khác 0.
Máy Turing T’ vừa xây dựng trên đây quả thực đã thực hiện hàm g và giả sử
T’ có số thứ tự là k, T’ = Tk. Xảy ra hai trường hợp như sau :
Giả sử hàm g(k) không xác định, điều này có nghĩa T’ không dừng trên
dữ liệu k, điều này cũng có nghĩa máy T, đến lượt nó, có kết quả là 1 trên
dữ liệu vào của cặp (k, k), tức là th(k, k) = 1. Vả lại th(k, k) = 1 nếu và chỉ
nếu máy Turing có số hiệu k dừng trên dữ liệu vào k. Nhưng máy Turing có
số hiệu k, chính là T’, không dừng trên dữ liệu vào k.
Giả sử hàm g(k) xác định và có giá trị 1, điều này có nghĩa rằng máy T
dừng trên dữ liệu vào k và có kết quả 0 trên dữ liệu vào của cặp (k,k). Nghĩa
là th(k, k) = 0. Vả lại th(k, k) = 0 nếu và chỉ nếu máy Turing có số hiệu k
không dừng trên dữ liệu vào k. Tuy nhiên, máy Turing có số hiệu k chính là
T’ lại dừng trên dữ liệu vào k.
Trong cả hai trường hợp trên, ta đều đi đến mâu thuẫn, vậy không tồn tai máy
Turing như đã giả thiết. QED
Kết quả chứng minh rất quan trọng vì đã chỉ ra rằng không tồn tại cách nào
để tính toán nhờ một máy Turing nếu một máy Turing T sẽ dừng hoặc không
dừng trên một dữ liệu vào f. Từ đây, ta cũng có thể chứng minh được :
Mệnh đề 3.8 :
Tồn tại các hàm T−tính được bộ phận (partial) không thể mở rộng thành một
hàm T−tính được nào khác.
Chứng minh
Định nghĩa hàm bộ phận g : Ν →/ Ν như sau:
g(i) = TU(i, i) + 1 nếu TU(i, i) xác định
g(i) không xác định nếu TU(i, i) không xác định
Mô hình các máy RAM 57

Hàm g là T−tính được. Thật vậy, xuất phát từ máy Turing vạn năng TU, ta có
thể dễ dàng xây dựng được một máy Turing thực thi hàm g này (chỉ việc thêm 1
vào kết quả).
Hàm g này không thể được mở rộng thành một hàm toàn phần từ Ν vào Ν dẫu
rằng T−tính được.
Ta sẽ chỉ ra bằng cách dùng phản chứng. Giả sử rằng g’ là một hàm như vậy.
Hàm g’ được thực hiện bởi một máy Turing T có số hiệu k, giả sử Tk.
Vì rằng g’ là một hàm toàn phần, nên T có một tính toán dừng cho mọi dữ liệu
vào. Chẳng hạn, với dữ liệu vào k, Tk dừng với một kết quả g’(k). Vả lại, vì Tk là
máy số hiệu k dừng trên dữ liệu vào k, TU(k, k) là xác định, khi đó g(k) được xác
định và có giá trị là TU(k, k)+1.
Tuy nhiên, TU là một máy Turing vạn năng, và do đó TU(k, k) là kết quả của
máy Turing số hiệu k trên dữ liệu vào k, giả sử là g’(k).
Vậy ta có : g(k) = g’(k) + 1
Nhưng g’ là một mở rộng của g, do đó g’(k) + 1 = g’(k).
Điều này mâu thuẫn.QED
58 Lý thuyết tính toán

Bài tập
1. Cho bảng chữ S = {a, b, c}, f và g ∈ S*. Hãy viết chương trình của một máy
Turing thực hiện các hàm sau :
− Hàm gương (miror function) hay hàm đảo ngược f → f R : φ(x1...xn ) =
xn...x1.
− Hàm chép f#g → f#g#g.
− Hàm f#g → fg.
− Hàm f → ff.
− Hàm f → ffR.
2. Cho S = {a, b, c} với thứ tự phân cấp là a<b<c. Viết chương trình máy Turing
để liệt kê các bộ ba câu và liệt kê các dãy các câu trên S.
3. Cho S = {0, 1, 2, 3} có thứ tự phân cấp là 0<1<2<3. Hãy viết chương trình
máy Turing thực hiện hàm kế tiếp Succ và hàm kế trước Pred.
4. Các số nguyên được biểu diễn lần lượt trong các hệ đếm cơ số 1, 2, 10. Hãy
viết chương trình của một máy Turing thực hiện các hàm tính tổng, tính nhân,
tính nhân với 7, tính chia, lấy phần dư (modulo), tính phần nguyên của căn
bậc hai và chuyển đổi giữa các hệ đếm này.
5. Các số nguyên được biểu diễn trong hệ cơ số 10, hãy viết chương trình của
một máy Turing thực hiện hàm :
− f(n) = 3n + 5
− g(n) = 2n
− h(n, m) = 2n + m
p
− l (n, m, p) = (nm)
6. Viết chương trình của một máy Turing không đơn định có một băng để nhận
biết ngôn ngữ L = {abi1abi2 ... abin | ∃ j, k : j ≠ k, và ij = ik }.
7. Hãy viết chương trình của một máy Turing đơn định có hai băng để nhận biết
ngôn ngữ L = {anbncn | n ≥ 1}. Tương tự đối với các ngôn ngữ :
L1 = {a2n | n ≥ 0}
L2 = {anb2n | n ≥ 0}
L3 = {anbpcq | q ≥ n ≥ 0 và p > 0}
Hãy chỉ ra rằng luôn luôn có thể giả thiết các phép tính dừng lại đều có độ dài
chẵn (một cách tương ứng : có độ dài lẻ).
CHƯƠNG 4

Luận đề Church
«The greatest ocean of truth lay all undiscovered before me»
Sir Isaac Newton

I. Sự tương đương giữa các mô hình máy Turing


và máy RAM
Trong mục này, ta sẽ chỉ ra rằng một hàm là T-tính được nếu và chỉ nếu hàm đó là tính
được nhờ một máy RAM (hàm tính được nhờ một máy RAM được gọi là R−tính được).

I.1. Mọi hàm T-tính được cũng là R−tính được


Ở đây, vấn đề là cần chỉ ra làm sao từ một chương trình P của một máy Turing giả thiết chỉ
có một băng vô hạn về một chiều, có thể suy ra được chương trình của một máy RAM thỏa
mãn cho mỗi bước tính toán của máy Turing. Cách xây dựng như sau :
Nội dung các ô trên băng của máy Turing, được đánh số 0, 1, ... là nội dung tương ứng
trong các thanh ghi R2, R3, ... của máy RAM. Số của thanh ghi tương ứng với ô nằm dưới đầu
đọc ghi của máy Turing sẽ nằm trong thanh ghi R1 (lúc đầu nội dung của R1 là 2 do đầu đọc
của máy Turing xuất phát từ ô đánh số 0).
Với mỗi trạng thái qi của máy Turing, người ta đưa vào một phần của chương trình của
máy RAM để mô phỏng các thao tác tính toán của máy Turing tại trạng thái này, tùy theo ký tự
được đọc trên băng.
Ví dụ, cho máy Turing trên bảng chữ kích thước 2 là S = {0, 1}. Giả sử nếu có hai quy tắc
của P tương ứng với trạng thái qi ∈ Q là :
qi, 1 → x, m, qr
qi, 0 → y, m’, qs
(trong đó, các di chuyển m và m’ có thể là L, R và qr, qs ∈ Q), thì một đoạn chương trình của
máy RAM tương ứng sẽ là :
ki : LOAD I: R1
JZERO k’i
LOAD A:x
STORE I:R1
INCR R1 (hoặc, tùy theo m :DECR R1)
JUMP Kr
k’i: LOAD A:y
STORE I:R1
INCR R1 (hoặc tùy theo m’ : DECR R1)
JUMP ks

PGS. TS. PHAN HUY KHÁNH biên soạn 59


60 Lý thuyết tính toán
Nếu một quy tắc tương ứng với một trạng thái qi không tồn tại, nghĩa là nếu một cặp (qi, x)
không là vế trái của một quy tắc nào, thì máy Turing dừng. Lúc đó, nhom lệnh tương ứng cuả
máy RAM sẽ là lệnh dừng Halt.
Rõ ràng, việc thực hiện của nhóm lệnh này mô phỏng một bước tính toán của máy Turing.
Các trạng thái của máy Turing tương ứng hoàn toàn với các nhãn ki của chương trình RAM.
Khi viết hết các đoạn chương trình (tương ứng với các trạng thái khác nhau của máy
Turing), người ta đã đặt chúng kề sát nhau, và có thể thay thế các nhãn ki bởi các con số. Như
vậy, việc thực hiện toàn bộ chương trình đã mô phỏng việc tính toán đầy đủ của máy Turing.

I.2. Mọi hàm R−tính được cũng là T−tính được


Ở đây, ta cần chỉ ra rằng, cho trước chương trình của một máy RAM, với giả thiết máy
RAM này rất thô sơ mà không làm mất tính tổng quát, ta có thể xây dựng được một máy
Turing cho phép kiểm chứng từng bước tính toán của máy RAM. Cách xây dựng như sau :
Nếu x0, x1, ... là nội dung tương ứng của các thanh ghi R0, R1, ..., thì băng của máy Turing
chứa :
0:x0 1:x1 ... j:xj ...
Ở đây, và : là hai ký tự mới được thêm vào.

I.2.1. Tăng nội dung thanh ghi n lên 1


Với mọi lệnh của chương trình của máy RAM có dạng :
i: I<n>
xây dựng một máy Turing Ti tiêu chuẩn hóa (normalized), có qi là trạng thái xuất phát và qi + 1
là trạng thái dừng.
Máy Ti hoạt động như sau : Ti di chuyển đầu đọc−ghi trên băng từ trái qua phải và so sánh
số đứng sau mỗi ký tự với n.
Nếu là bằng nhau thì Ti tăng số nguyên tiếp theo sau ký tự : lên 1 (increment) bằng cách
dời theo nhu cầu những gì theo sau qua bên phải, rồi dừng.

I.2.2. Giảm 1 nội dung thanh ghi n


Tương tự như vậy, với mỗi lệnh của chương trình của máy RAM có dạng :
i: D<n>
xây dựng một máy Turing Ti tiêu chuẩn hóa có qi là trạng thái xuất phát và qi + 1 là trạng thái
dừng. Máy Ti hoạt động như sau :
Ti di chuyển đầu đọc−ghi trên băng từ trái qua phải và so sánh số đứng sau mỗi ký tự với
n. Nếu là bằng nhau, thì Ti giảm một (decrement) số nguyên tiếp theo và dừng.

I.2.3. Đưa nội dung thanh ghi n về 0


Với mỗi lệnh của chương trình của máy RAM có dạng :
i: Z<n>
Mô hình các máy RAM 61
xây dựng một máy Turing tiêu chuẩn hóa có qi là trạng thái xuất phát và qi + 1 là trạng thái
dừng. Máy Ti hoạt động như sau :
Ti di chuyển đầu đọc−ghi trên băng từ trái qua phải và so sánh số đứng ngay sau mối ký tự
với n. Nếu là bằng nhau, Ti thay thế số nguyên tiếp theo bởi hằng 0 và dừng.

I.2.4. Nhảy theo nội dung thanh ghi n


Với mỗi lệnh của chương trình của máy RAM có dạng :
i: J<n> (j, k)
xây dựng một máy Turing tiêu chuẩn hóa có qi là trạng thái xuất phát và hai trạng thái dừng qj
và qk. Máy Ti hoạt động như sau :

Ti duyệt băng từ trái qua phải và so sánh số đứng ngay sau mỗi ký tự với n. Nếu là bằng
nhau, Ti so sánh số nguyên tiếp theo với hằng 0 và dừng ở trạng thái qj nếu là bằng nhau dừng
ở qk nếu không bằng nhau.

I.2.5. Hoán vị nội dung hai thanh ghi n và m


Bài tập : Xây dựng một máy Turing tiêu chuẩn hóa thực hiện lệnh của chương trình của
máy RAM có dạng :
I: S<n,m>
Rõ ràng, mỗi bước tính toán của máy RAM, hay mỗi lần thực hiện một lệnh thứ i, đã được
mô phỏng bởi một máy Turing tương ứng. Nếu tập hợp tất cả các máy Turing này thành một
máy duy nhất, thì máy này sẽ mô phỏng máy RAM.

I.3. Sự khác nhau giữa máy Turing và máy RAM


Trước đây, ta đã giới thiệu máy Turing có băng vào và băng ra. Tuy vậy mô hình máy
Turing vẫn còn khác xa mô hình của máy RAM, do các chức năng của máy Turing rất hạn chế.
Tuy nhiên, nếu ta nhớ lại rằng tập hợp các lệnh của các máy RAM có thể thu gọn đáng kể,
bằng cách chuyển qua mô hình của máy RAM thô sơ, khi đó sự khác nhau giữa hai mô hình sẽ
trở nên không đáng kể.
Vấn đề là cách biểu diễn dữ liệu khác nhau giữa hai mô hình. Với các máy Turing, dữ liệu
vào là xâu ký tự trên băng, mỗi ô của băng chỉ chứa một ký tự. Còn với máy RAM, mỗi ô của
băng chứa đúng một số nguyên.
Khi nghiên cứu về máy RAM, ta thấy rằng, nếu, một mặt, cách biểu diễn một số nguyên
trong RAM gần giống với việc lưu giữ một “số nguyên” trong một đơn vị nhớ (memory word),
mặt khác, lại không phải như vậy vì rằng kích thước của các số nguyên luôn luôn bị hạn chế
trong thực tế.
Tuy nhiên, sự khác nhau chủ yếu giữa hai mô hình máy RAM và máy Turing là cách truy
cập thông tin : trong mô hình máy RAM, nội dung một ô được đọc trực tiếp nhờ địa chỉ của ô
đó, còn trong mô hình của máy Turing, để đi từ một ô này đến một ô khác, cần phải duyệt thăm
tất cả các ô trung gian (cơ chế tuần tự).
62 Lý thuyết tính toán

II. Mô hình các hàm đệ quy


II.1. Các hàm đệ quy nguyên thủy
(primitive recursive functions)
Có rất nhiều hàm được định nghĩa không theo cách trực tiếp, mà cần đến các hàm đã được
định nghĩa trước đó, bằng cách sử dụng các sơ đồ định nghĩa. Đó là việc hợp thành
(composition) một lớp các hàm xuất phát từ một số hàm sơ cấp (elementary function) dùng
làm cơ sở.

II.1.1. Xây dựng các hàm sơ cấp


Cho S là một bảng chữ có thứ tự (có ít nhất là hai ký tự) và một ký tự x ∈ S, ta ký hiệu ls(x)
là ký tự tiếp theo ký tự x theo thứ tự này, ls(x) ∈ S. Nếu x đứng cuối cùng của bảng chữ, thì
ls(x) được quy ước là ký tự đầu tiên của bảng chữ S.
Với mỗi ký tự x ∈ S, ký hiệu ppx là hàm mà với mọi câu w ∈ S*, ppx (w) trả về câu wx.
Nghĩa là ppx(w) ∈ S*.
Tiếp tục định nghĩa các hàm first và last như sau :
first (w) =1 nếu w = e (câu rỗng)
=x nếu w = xw’ (x ∈ S)
last (w) =1 nếu w = e
=x nếu w = w’x (x ∈ S)
Tiếp tục định nghĩa các hàm prefix và suffix như sau :
prefix (w) = 1 nếu w = e
= w’ nếu w = w’x (x ∈ S)
w’ là tiền tố dài nhất của w và khác với w khi w ≠ e
suffix (w) =1 nếu w = e
= w’ nếu w = xw’ (x ∈ S)
Cuối cùng ta định nghĩa hàm equal trên S × S như sau :
equal (x, y) = 1 nếu x = y
= x0 nếu x ≠ y,
trong đó x0 là một ký tự cố định của bảng chữ S.
Chú ý : Đối với bảng chữ chỉ có một ký tự x duy nhất, các hàm prefix và suffix là đồng nhất
với nhau và chính là hàm kế trước (predecessor), còn hàm kế tiếp (successor) lúc
này chính là hàm ppx. Các hàm khác vừa được định nghĩa trên đây đều không có
nghĩa.
Sau đây, ta đưa vào một số sơ đồ định nghĩa như sau :

II.1.2. Sơ đồ hợp thành tổng quát


Cho S là một bảng chữ có thứ tự. Ta định nghĩa các hàm fi, i = 1.. k, k>0, và một hàm g như
sau :
fi : S* → S*, i = 1.. k
g : (S*)k → S*
Mô hình các máy RAM 63
Từ fi và g, ta định nghĩa hàm h bởi sơ đồ hợp thành tổng quát như sau :

h = compk (f1, f2, ..., fk, g) : S* → S*

Nghĩa là với câu vào w ∈ S*, ta nhận được :


h(w) = g(f1(w), f2(w), ..., fk(w)).

II.1.3. Sơ đồ đệ quy đơn (simple recurrence)


Cho S là bảng chữ có thứ tự. Ta định nghĩa các hàm f và g như sau :
f : S* → S *
4
g : (S*) → S*
Từ f và g, ta định nghĩa hàm h :
h = rec(f, g) : (S*)2 → S*
Nghĩa là h nhận giá trị từ f và g bởi sơ đồ đệ quy đơn :
h(1, m) = f(m)
h(wx, m) = g(w, x, h(w, m), m)
Nói cách khác, phép đệ quy tác động lên đối của hàm là câu w. Khi w = e, hàm h được khởi
động bởi hàm f.
Nếu w ≠ e, hàm h được định nghĩa bởi một hàm f phụ thuộc vào giá trị trả về h(w, m) của
hàm h từ câu bị cắt bỏ ký tự cuối cùng, bản thân câu bị cắt bỏ ký tự cuối cùng này (w), ký tự bị
cắt bỏ (x) và các đối khác.

II.1.4. Sơ đồ đệ quy đồng thời


Cho bảng chữ S có thứ tự. Ta định nghĩa các hàm fi và gi, i = 1.. k, k>0, như sau :
fi : S* → S*,
gi : (S*)k + 3 → S*, i = 1.. k.
Từ fi và gi, định nghĩa các hàm hi, i=1.. k, bởi sơ đồ đệ quy đồng thời như sau :

hi : (S*)2 → S*
Nghĩa là mỗi hàm hi nhận giá trị từ fi và gi bởi sơ đồ đệ quy đồng thời :
hi(1, m) = fi(m)
hi(wx, m) = gi(w, x, h1(w, m), ..., hk(w, m), m)

Ta định nghĩa lớp P các hàm đệ quy nguyên thủy S* → S* là các lớp bé nhất các hàm chứa
các hàm sơ cấp sau :
identity (hàm hằng, trả về một câu cố định),
ls, ppx, first, last, prefix, suffix,
equal,
copy, identity, proiection, antiprojection.
Lớp các hàm này là đóng đối với các sơ đồ hợp thành và đệ quy đơn.
Ví dụ 4.1 :
Cho bảng chữ S, ta xây dựng các hàm đệ quy nguyên thuỷ sau đây :
64 Lý thuyết tính toán
1. Ghép hai câu
Hàm concat ghép hai câu u và w thành uw như sau :
concat (u, w) =u nếu w = 1
concat (u, wx) = ppx(concat(u, w))
Người ta cũng có thể viết :
concat = rec(f, g)
với f là hàm identity và g được hợp thành từ các hàm ppx và phép chiếu thứ ba :
P3 : g = ppx ° P3
2. Nghịch đảo câu
Hàm mirror trả về câu nghịch đảo (reverse) của câu w là wR, nghĩa là nếu
w = x1x2 ... xn thì mirror(w) = xnxn-1 ... x2x1, như sau :
mirror(1) =1
mirror(wx) = concat (x, mirror(w))
3. Nuốt (hấp thu) câu
Hàm đệ quy nguyên thuỷ absorb như sau :
absorb (1, f) = 1
absorb (w, f) = f nếu w ≠ e
4. Kiểm tra không bằng nhau
Xây dựng hàm nonequal :
nonequal(x, y) = x0 nếu x = y với x0 ∈ S là ký tự cố định
=1 nếu x ≠ y
5. Các hàm case
Giả sử S = { x1, x2, ..., xk }, x1 là ký tự đầu tiên, xk là ký tự cuối cùng trong S.
Xây dựng hàm case1 trả về câu kế tiếp của câu w trong thứ tự phân cấp khi ký tự cuối cùng
của w không là ký tự cuối cùng của bảng chữ S như sau :
case1(1) =1
case1(wx) = absorb(equal(x, xk), ppx (w))
1
Xây dựng hàm case2 như sau :
case2(1, u) =1
case2(wx, u) = absorb(nonequal(x, xk), ppx(u)) nếu x = last(w)
Từ cách xây dựng các hàm đệ quy nguyên thuỷ trên đây, ta định nghĩa lại hàm kế tiếp
successor :
successor(1) = x1
successor(wx) = concat(case1(wx), case2(wx, successor(w)))
Cũng như trước đây, ta đã chuyển từ một ngôn ngữ sang một hàm bằng cách sử dụng hàm
đặc trưng và ta có định nghĩa sau :
Định nghĩa 4.1 :
Một phần L ⊂ S* được gọi là đệ quy nguyên thủy nếu hàm đặc trưng của nó là một hàm đệ
quy nguyên thuỷ.
Mô hình các máy RAM 65

II.1.5. Các hàm được định nghĩa bởi case


Hàm được định nghĩa bởi case là một hàm có miền xác định được phân hoạch (thành các
trường hợp khác nhau), trong đó, mỗi phân hoạch xác định một hàm. Nhiều hàm được định
nghĩa bởi case. Ví dụ hàm xác định từ các dữ liệu được tạo thành bởi một số chẵn ký tự (hoặc
từ một số chẵn thành phần dữ liệu).
Ta có mệnh đề sau :
Mệnh đề 4.1 :
Cho f1, f2, ..., fk là các hàm đệ quy nguyên thuỷ từ S* → S* và giả sử S được phân hoạch
thành k lớp L1, L2, ..., Lk, khi đó hàm f định nghĩa bởi case như sau :
f(w) = fi(w) nếu w ∈ Li, i ∈ 1..k,
thì f cũng là một hàm đệ quy nguyên thuỷ.
Chứng minh :
Thật vậy, giả sử d1, d2, ..., dk lần lượt là các hàm đặc trưng của các ngôn ngữ L1, L2, ..., Lk,
được định nghĩa như sau :
di(w) = 1 nếu w ∉ Li
di(w) = x0 nếu w ∈ Li (x0 ∈ S là một ký tự cố định)
Khi đó hàm f được xây dựng :
f(w) = concat(absort(di(w), fi(w)))
Do các hàm xuất hiện trong định nghĩa của f đều đệ quy nguyên thuỷ, do đó f cũng đệ quy
nguyên thuỷ.QED
Mệnh đề 4.2 :
Lớp P các hàm đệ quy nguyên thuỷ là đóng đối với sơ đồ đệ quy đồng thời.
Chứng minh :
Ta cần chỉ ra rằng, với S là một bảng chữ có thứ tự, nếu cho :
fi : S*→S*,
gi : (S*)k+3 → S*, i = 1 .. k,
là các hàm đệ quy nguyên thuỷ, thì các hàm :
hi : (S*)2 → S*
được xây dựng từ các hàm fi và gi bởi sơ đồ đệ quy đồng thời, cũng là đệ quy nguyên thuỷ. Lấy
k = 2 để chứng minh, với k bất kỳ được chứng minh tương tự.
Giả sử S là bảng chữ có thứ tự, cho trước các hàm :
f1, f2 : S* → S* và
g1, g2 : (S*)5 → S*
là đệ quy nguyên thuỷ. Xây dựng các hàm :
h1, h2 : (S*)2 → S*
từ các hàm f1, f2 và g1, g2 theo sơ đồ đệ quy đồng thời như sau :
hi(1, m) = fi(m)
66 Lý thuyết tính toán
hi(wx, m) = gi(w, x, h1(w, m) = gi(w, x, h1(w, m), h2(w, m), m)
2
Tiếp tục xây dựng hàm h từ (S*) → S* như sau :
h(w, m) = C(h1 (w, m), h2(w, m))

trong đó C là một hàm mã hóa từ S* × S*→ S* thỏa mãn C(1,1) = 1 và sao cho các hàm h1 và
h2 nhận được từ h bởi phép giải mã nhờ các hàm đệ quy nguyên thuỷ P1 và P2 :
hi(w, m) = Pi(h(w, m))
Vấn đề còn lại là chứng minh rằng h cũng là một hàm đệ quy nguyên thuỷ.
4
Hàm h nhận được bỡi sơ đồ đệ quy đơn nhờ hai hàm f và g, hàm f từ S* → S* và g từ (S*)
→ S*, như sau :
f(m) =C(f1(m), f2(m)) và
g(w, x, C(u1, u2), m) = C(g1(w, x, u1, u2, m), g2(w, x, u1, u2, m))
Bây giờ kí hiệu f = rec(f, g), theo định nghĩa, ta có :
f(1, m) = f(m),
f(mx, m) = g(w, x, f(w, m), m)
Với câu rỗng, rõ ràng ta có f(1, m) = h(1, m), còn đối với các câu khác, ta có :
f(wx, m) = C( g1(w, x, P1 ° f(w, m), P2 ° f(w, m), m),
g2 (w, x, P1 ° f(w, m), P2 ° f(w, m), m))
Như vậy, ta có f = h cho mọi câu w và mọi câu m.
Do f và g đều là đệ quy nguyên thuỷ bởi các hàm f1, f2 và g1, g2 cũng là đệ quy nguyên
thuỷ, nên h cũng là đệ quy nguyên thuỷ. Vậy h1 và h2 cũng là các hàm đệ quy nguyên thuỷ.
Cần phải chú ý rằng tất cả các hàm đệ quy nguyên thuỷ đều là các hàm toàn phần. Người ta
có thể mở rộng khái niệm đệ quy nguyên thuỷ cho các hàm bộ phận nhờ đưa vào định nghĩa
sau đây :
Định nghĩa 4.2 :
Một hàm được gọi là đệ quy nguyên thuỷ bộ phận (partial primitive recursive function) nếu
hàm đó được định nghĩa trên một miền xác định đệ quy nguyên thuỷ (partial primitive
recursive domain) nhờ một hàm đệ quy nguyên thuỷ.
Rõ ràng, một hàm đệ quy nguyên thuỷ bộ phận là một hàm có thể được mở rộng thành một
hàm đệ quy nguyên thuỷ.
Mô hình các máy RAM 67

II.2. Các hàm đệ quy


Sau đây ta tiếp tục đưa vào một số sơ đồ định nghĩa như sau :

II.2.1. Sơ đồ tối thiểu


Cho g là một hàm từ (S*)2 → S*, với S là một bảng chữ có thứ tự.
Xuất phát từ g, định nghĩa hàm h = Min(g) từ S* → S* theo sơ đồ tối thiểu như sau : h(w)
là câu nhỏ nhất f (trong thứ tự phân cấp) sao cho g(f, w) hoặc là câu rỗng, nếu một câu f như
vậy tồn tại, và nếu g(u, v) được xác định bởi u trước khi xác định f, còn h(w) sẽ không xác định
nếu trái lại.
Bây giờ ta định nghĩa lớp k các hàm đệ quy bộ phận từ S* → S* là lớp nhỏ nhất các hàm
chứa các hàm sơ cấp sau đây :
− hằng (trả về một câu cố định)
− ls, ppx, first, last, prefix, suffix
− equal
− copy, identity, projection, antiprojection
Lớp k là đóng đối với các sơ đồ hợp thành, đệ quy đơn và tối thiểu.
Rõ ràng, sơ đồ tối thiểu có thể đưa vào trong các hàm bộ phận. Tuy nhiên, một hàm được
định nghĩa nhờ sơ đồ tối thiểu có thể toàn phần. Người ta gọi một hàm đệ quy bộ phận nhưng
toàn phần là một hàm đệ quy toàn phần (total recursive function) hay còn gọi là hàm đệ quy.
Vấn đề đầu tiên đặt ra là : lớp r các hàm đệ quy toàn phần có chứa ngặt (trictly) lớp p các
hàm đệ quy nguyên thuỷ ?
Câu trả lời là có. Để chứng minh, người ta sử dụng kỹ thuật đường chéo.
Mệnh đề 4.3 :
Phép bao hàm p ⊂ r là ngặt.
Chứng minh :
Theo định nghĩa, vì các hàm đệ quy nguyên thuỷ được xây dựng từ tập hợp hữu hạn các
hàm nhờ một số hữu hạn các sơ đồ nên chúng tạo thành một tập hợp đếm được, và liệt kê
được. Giả sử pi là hàm thứ i trong phép liệt kê đã cho. Người ta cũng liệt kê các câu theo thứ tự
phân cấp và wj là câu thứ j trong thứ tự này. Xét hàm f được định nghĩa như sau :
f(wi) = successor(pi(wi))
Người ta chứng minh rằng hàm toàn phần này là một hàm đệ quy và không phải là một
hàm pi nào đó.

Chú ý rằng kỹ thuật đường chéo đều được áp dụng cho tất cả lớp p’ các hàm được xây
dựng tương tự như đã xây dựng trong p, nghĩa là từ các hàm cơ sở và từ một số hữu hạn sơ đồ
xây dựng hàm. Như vậy không tồn tại một cách xây dựng hàm như vậy cho p.
Định nghĩa 4.3 :
Một phân hoạch L ⊂ S* được gọi là đệ quy (hiểu là toàn phần) nếu hàm đặc trưng của L là
một hàm đệ quy toàn phần.
68 Lý thuyết tính toán
Trong số các hàm đệ quy bộ phận có thể phân biệt được những hàm mở rộng được thành
một hàm đệ quy toàn phần và những hàm không thể kéo mở rộng. Loại hàm mở rộng được có
miền xác định là đệ quy.

II.2.2. Các hàm đệ quy trừu tượng (abstract recursive functions)


Phép chuyển đổi cách biểu diễn một số nguyên từ một hệ đếm này sang một hệ đếm khác
được tiến hành nhờ các hàm đệ quy nguyên thuỷ. Do đó cần định nghĩa các hàm đệ quy không
được biểu diễn (gọi là trừu tượng). Vấn đề là các hàm xác định từ Νp → Νk làm việc với các số
nguyên trừu tượng (không quan tâm đến cách biểu diễn chúng như thế nào). Thực tế vấn đề
này rất gần với trường hợp biểu diễn các số nguyên trên một bảng chữ chỉ chứa một ký tự.
Người ta định nghĩa lớp hàm đệ quy nguyên thủy (một cách tương ứng : lớp hàm đệ quy bộ
phận) từ Νp → Νk là lớp hàm bé nhất chứa các hàm sơ cấp sau đây :
− hằng (chỉ trả về một số nguyên cố định)
− kế tiếp, kế trước (theo nghĩa số nguyên)
− gấp đôi (duplication), chiếu, phản chiếu
Lớp này là đóng đối với các sơ đồ hợp thành và đệ quy đơn (một cách tương ứng: tối
thiểu). Ở đây, sơ đồ đệ quy đơn được xác định một cách đơn giản hơn như sau :
Nếu f là một hàm từ Νp → Νk, g là một hàm từ Νp+k+1 → Νk, xây dựng hàm h = rec(f, g)
từ Νp+1 → Νk nhờ các hàm f và g như sau :
h(0, m) = f(m)
h(n + 1, m) = g(n’, h(n’, m), m)
ở đây, m là một bộ−p các số nguyên.
Tương tự, sơ đồ tối thiểu được định nghĩa một cách đơn giản như sau :
Cho hàm g : Νp+1 → Νk, xuất phát từ g, xây dựng hàm h = Min(g) : Νp → Νk như sau :
h(m) là số nguyên n bé nhất sao cho g(n, m) = 0, nếu n như vậy tồn tại và nếu g(i, m) xác
định với i < n.
h(m) không xác định nếu trái lại.
Người ta dùng cách viết tắt như sau :
m(m) [g(n, m) = 0]
để chỉ rằng số nguyên bé nhất n sao cho g(n, m) = 0

II.2.3. Một số ví dụ
1. Tính tổng và tích hai số nguyên
Các hàm tính tổng sum và tích product của hai số nguyên sau đây đều là đệ quy nguyên
thuỷ :
sum(n, m) = P1 (m) nếu n = 0,
= succ ° P2 (n', sum (n', m), m) nếu n = n' + 1
Hàm chiếu thứ nhất P1 (là hàm đồng nhất) là đệ quy nguyên thuỷ. Hàm tổ hợp succ°P2
cũng là đệ quy nguyên thuỷ vì cả hai hàm, hàm kế tiếp succ và hàm chiếu thứ hai P2, đều là đệ
quy nguyên thuỷ. Từ đó, hàm sum viết dưới dạng
sum = rec(P1, succ°P2) là đệ quy nguyên thuỷ. Có thể viết lại đơn giản hơn :
Mô hình các máy RAM 69
sum (n, m) = m nếu n = 0
= succ(sum (n', m)) nếu n = n' + 1
Tương tự :
product (0, m) =0
product (n + 1, m) = sum (product (n, m), m)
Người ta thường viết n+m và n*m thay vì viết sum (n, m) và product (n, m).
2. Kiểm tra bằng 0
Hàm zt (zerotest) kiểm tra số nguyên n có bằng 0 không được định nghĩa :
zt (n) = 1 nếu n = 0
=0 nếu n ≠ 0
là một hàm đệ quy nguyên thuỷ, vì rằng zt = rec(1, 0) với 0 và 1 là hai hàm hằng.

3. Kiểm tra chẵn lẻ


Các hàm kiểm tra số nguyên n có là chẵn et (even test) hoặc có là lẻ ot (odd test) được định
nghĩa như sau :
et (n) =1 nếu n = 2p
=0 nếu n = 2p + 1
ot (n) =0 nếu n = 2p
=1 nếu n = 2p + 1
là các hàm đệ quy nguyên thuỷ, vì chúng được viết :
et (0) = 1 và et (n + 1) = zt (et (n))
ot (n) = zt (et (n))

4. Chia đôi lấy phần nguyên


Hàm half chia đôi lấy phần nguyên một số n được định nghĩa như sau :
half (n) = phần nguyên của n/2
là đệ quy nguyên thuỷ, vì có thể được viết :
half (0) =0
half (n + 1) = et (n) + half (n)

5. Tính hiệu hai số nguyên


Hàm tính hiệu hai số nguyên n và m, ký hiệu n ⎯ m, định nghĩa như sau :
n⎯m=0 nếu n ≤ m
n⎯m=n−m nếu n > m
là đệ quy nguyên thuỷ, vì được viết như sau (với pred là hàm kế trước) :
n⎯0 =n
n ⎯ m + 1 = pred (n m)
Ở đây, phép đệ quy nguyên thủy tác động lên đối thứ hai.

6. Phép chia nguyên


Hàm chia nguyên n div m, là đệ quy nguyên thuỷ, vì được viết :
0 div m =0
n + 1 div m = n div m + zt (m + m * (n div m) ⎯ (n + 1))

7. Phép chia lấy phần dư


70 Lý thuyết tính toán
Hàm lấy phần dư, ký hiệu n mod k, là đệ quy nguyên thuỷ vì được viết :
n mod k = n ⎯ (n div m) * m
Từ đây ta dễ dàng nhận thấy rằng, tất cả các hàm số học thông dụng đều được cấu thành từ
các hàm đệ quy nguyên thuỷ.

II.3. Các hàm đệ quy đều T−tính được


Ta có mệnh đề sau :
Mệnh đề 4.4 :
Mọi hàm đệ quy bộ phận là T−tính được.
Chứng minh :
Thật vậy, chỉ cần chỉ ra rằng tất cả các hàm cơ sở đều là T−tính được, và chỉ ra rằng cả ba
sơ đồ (hợp thành, đệ quy đơn và tối thiểu) đều bảo tồn đặc trưng T−tính được. Vả lại, nhớ lại
rằng các hàm cơ sở quả thực là những hàm đầu tiên ta đã xây dựng trong chương trước đây
nhờ các máy Turing. Như vậy chỉ cần chứng minh rằng có thể thực hiện mỗi một trong ba sơ
đồ nhờ các máy Turing.

II.3.1. Sơ đồ hợp thành tổng quát


Cho f1, f2, ..., fk và g đều là các hàm T−tính được, khi đó hàm :
compk (f1, f2, ..., fk, g)
cũng là T−tính được.
Thật vậy, giả sử T1, T2, ..., Tk và T là các máy Turing thực hiện một cách tương ứng các
hàm f1, f2, ..., fk và g. Có thể giả thiết thêm rằng chúng có đầu đọc−ghi không bao giờ vượt qua
bên trái vị trí xuất phát.
Xây dựng máy T' như sau : T' bắt đầu bởi thực hiện k phép sao chép dữ liệu w, rồi thì với i
chạy lùi từ k về 1, và, nhờ các Ti, T' thực hiện phép tính trên câu w về bên phải, được kết quả là
fi (w) và hoán vị kết quả này với các câu khác. Khi T' kết thúc, trên băng có kết quả :
f1(w)# ... #fk(w)
Sau đó, nhờ máy T, T' thực hiện phép tính trên câu :
g (f1(w) , f2(w), ..., fk(w))
Rõ ràng, T' đã thực hiện hàm compk (f1, f2, ..., fk, g)

II.3.2. Sơ đồ đệ quy đơn


Cho f và g là các hàm T−tính được, khi đó hàm rec(f, g) cũng là T−tính được.
Thật vậy : Cho T và T' là các máy Turing thực hiện một cách tương ứng các hàm f và g. Có
thể giả thiết rằng chúng có đầu đọc-ghi không bao giờ vượt qua bên trái vị trí xuất phát. Xây
dựng máy Turing T’’ như sau:
Nếu w là câu rỗng, T’’ lấy lại tính toán của T trên m. Nếu w ≠ e (khác rỗng), T" ghi trên
băng của nó dãy các phép tính thực hiện được là :
G(wk, H(wk), m)#...#G(wi, H(wi), m)#...#G(w1, H(w1), m)#F(m)
Mô hình các máy RAM 71
Trong đó các wi là các câu theo thứ tự phân cấp tăng dần kể từ wk = w', kế trước của w.
Còn các ký tự mới thêm vào G, H, F dùng để đánh dấu.
Rõ ràng, điều này có thể được thực hiện bởi một máy Turing : chỉ cần sao chép các dữ liệu
đã được thêm vào các ký tự đánh dấu bằng cách giảm 1 (decrement) liên tiếp, chừng nào dãy
này còn khác rỗng. Sau đó T" tiếp tục thực hiện tất cả các phép tính trong thứ tự ngược lại, từ
phải qua trái. Đầu tiên T" sử dụng T để tính hàm f(m), rồi với i chạy từ 1 đến k, T" sao chép kết
quả vừa tìm thấy tại vị trí H(wi) và tính hàm g(wi, h(wi, m), m).
Rõ ràng, T' thực hiện hàm rec(f, g).

II.3.3. Sơ đồ tối thiểu


Cho g là một hàm T-tính được, khi đó Min(g) cũng là T-tính được.
Thật vậy :
Cho T là một máy Turing thực hiện g. Xây dựng máy Turing T' có hai băng để liệt kê tất cả
các câu trên băng thứ nhất, và với mỗi câu đã liệt kê, tiến hành sao chép trên băng thứ hai. Sau
đó T' thực hiện phép tính toán của T trên câu đã sao chép này. Khi tính xong, thì T' dừng, nếu
chưa rỗng, thì T' tiếp tục liệt kê và cứ thế tiếp tục.
Một cách rõ hơn, ta xem rằng các máy Turing có hai băng như sau: T0 viết lên băng thứ
nhất câu đầu tiên, T1 tính câu kế tiếp của câu được viết trên băng thứ nhất, T2 sao chép lại câu
đã được viết trên băng thứ nhất lên băng thứ hai và bao bọc phần câu sao chép này bởi ký tự
đánh dấu. T3 kiểm tra nếu câu được viết giữa hai ký tự đánh dấu trên băng thứ hai có phải là
câu rỗng hay không.
Nếu là câu rỗng, T3 rơi vào trạng thái qyes và T3 dừng.
Nếu không phải là câu rỗng, T3 rơi vào trạng thái qno.
Cuối cùng, T’ thực hiện trên băng thứ hai phép tính giữa các ký tự đánh dấu mà T đã thực
hiện trên băng của nó.
Khi đó, giả sử ta có:
T' = T0 next T2 next T next T3
next while T3 give qyes : T1 next T2 next T next T3
Rõ ràng, T' thực hiện hàm Min(g).

II.4. Mọi hàm T−tính được là đệ quy bộ phận


Trong mục này, ta chứng minh mệnh đề ngược lại như sau :
Mệnh đề 4.5 :
Mọi hàm T−tính được là đệ quy bộ phận.
Chứng minh :
Cho F là một hàm T-tính được nhờ máy Turing T = < S, Q, P> tiêu chuẩn hoá và chuẩn
hoá có một trạng thái dừng duy nhất qN. Giả thiết rằng, S là bảng chữ có kích thước n.
Chương trình của máy T có ba hàm nc, mh và ns được định nghĩa như sau:
nc (q, x) = y
mh (q,x) = m
ns (q,x) = q'
nếu và chỉ nếu (q, x, y, m, q') là một quy tắc của P.
72 Lý thuyết tính toán
Cả ba hàm này đều được định nghĩa bởi case, rõ ràng chúng đều là đệ quy bộ phận (và
cũng là đệ quy nguyên thuỷ nếu mở rộng chúng cho đến khi chúng không còn được xác định,
nghĩa là đến khi đối thứ nhất là qN).
Bây giờ nhờ phép đệ quy đồng thời, ta sẽ xây dựng một số hàm mô tả các phần tử khác
nhau của một cấu hình của máy T sau k bước tính toán trên dữ liệu f :

1. Hàm "trạng thái "


Giả sử S là một hàm "trạng thái " được định nghĩa bởi :
S(f, k) = q nếu q là trạng thái của T sau khi bước tính toán trên dữ liệu f

2. Hàm " vế bên trái"


Giả sử L là hàm " vế bên trái" được định nghĩa bởi :
L(f, k) = w nếu w là phần hữu ích phía bên trái đầu đọc ghi của T sau k bước tính toán trên
dữ liệu f.
Ta sẽ xem n ký tự của S như là các con số (ký tự # được xem là 0). Như vậy, câu w sẽ là
một số nguyên viết trong hệ cơ số n.
Do giá trị số nguyên không thay đổi khi thêm một số 0 về phía trái (trước) của câu (dãy số)
biểu diễn số nguyên đó, nên không đặt ra vấn đề xác định phần hữu ích. Hơn nữa, các phép
toán tác động lên các câu như ghép một ký tự, hay loại bỏ một ký tự đứng cuối cùng của câu,
hay chỉ giữ lại ký tự đứng cuối cùng của câu, được thể hiện một cách trực tiếp theo cách viết số
học thông thường.

3. Hàm " vế bên phải"


Giả sử R là "vế bên phải" được định nghĩa bởi :
R(f, k) = wx nếu x là ký tự nằm dưới đầu đọc-ghi và nếu w là ảnh gương (nghịch đảo) của
phần hữu ích phía bên phải của đầu đọc-ghi của T sau k bước tính toán trên dữ liệu vào f. Ở
đây, ta sử dụng câu nghịch đảo để sao cho việc thêm một số 0 về phía bên phải của câu biểu
diễn không làm thay đổi giá trị của số nguyên đó.
Rõ ràng, cả ba hàm này xác định hoàn toàn cấu hình của máy T sau k bước tính toán trên
dữ liệu vào f.
Để cho tiện, ta đưa thêm hàm thứ tư như sau:
4. Hàm " ký tự"
Giả sử C là hàm "ký tự" được định nghĩa :
C(f, k) = x nếu x là ký tự nằm dưới đầu đọc-ghị của T sau k bước tính toán trên dữ liệu vào
f.
Rõ ràng ta có C(f, k) = [R(f, k)] mod n
Với k = 0, phép tính chưa đựơc bắt đầu. Lúc này ta đang ở cấu hình xuất phát. Ta có các
giá trị khởi động của các hàm như sau:
S(f, 0) = q1 q1 là trạng thái đầu,
L(f, 0) = 0 trong cấu hình xuất phát, phía trái đầu đọc-ghi không có gì,
R(f, 0) = mir(f) là câu đảo ngược của f, trong cấu hình xuất phát, trên băng có dữ liệu f,
đầu đọc-ghi đặt tại ký tự đầu tiên của f.
Từ các giá trị khởi động này, ta có phép đệ quy đồng thời :
Mô hình các máy RAM 73
S(f, k + 1) = ns (S(f, k), C(f, k))
L(f, k+1) = [ L(f, k) ] div n nếu mh(S(f, k), C(f, k)) = L
=n × L(f, k) + nc(S(f, k), C(f, k)) nếu mh (S(f, k), C(f, k)) = R
R(f, k + 1) = n × R(f, k) + nc (S(f, k), C(f, k)) nếu mh (S(f, k), C(f, k)) = L
=[ R(f, k) ] div n nếu mh (S(f, k), C(f, k)) = R
Ở đây, ta đã viết theo cách viết số học. Tuy nhiên có thể dịch các định nghĩa này theo cách
viết các câu.
Các hàm S, L và R do được định nghĩa bởi phép đệ quy đồng thời nhờ các hàm đệ quy
nguyên thuỷ, nên chúng là đệ quy nguyên thuỷ.
Rõ ràng, quá trình tính toán của máy T trên dữ liệu vào f là dừng nếu và chỉ nếu tồn tại một
số nguyên k sao cho S(f, k) = qN. Khi đó ta có kết quả của phép tính trên băng, nghĩa là kết quả
này là câu nghịch đảo của R(f, k).
Từ đó, ta có:
F(f) = mir (R(f, mk[ S(f, k) = qN ]))
Vậy quả thật F là một hàm đệ quy bộ phận. QED
Chú ý:
Trong cách xây dựng trên đây, ta đã thấy rằng nếu máy Turing T luôn luôn dừng, giá trị
mk[ S(f, k) = qN ] luôn luôn xác định, và do vậy F là toàn phần.
Cách xây dựng trên đây chỉ ra rằng tất cả các hàm đệ quy bộ phận có thể được viết bằng
cách sử dụng một lần duy nhất sơ đồ tối thiểu.

III. Luận đề Church


Cho đến lúc này, ta đã nghiên cứu một số mô hình tính toán :
− Mô hình các máy RAM (và các máy RASP), rất gần với chức năng của một máy tính
chạy trên ngôn ngữ assembler
− Mô hình các máy Turing, xa hơn mô hình RAM, nhưng trong đó, ta tìm thấy một số vấn
đề của các máy thực như các máy xử lý dữ liệu, quản lý bộ nhớ, v.v...
− Mô hình các hàm đệ quy, từ S* → S*, trong đó những vấn đề vừa xét không đặt ra,
nhưng lại giữ nguyên những vấn đề về biểu diễn dữ liệu
− Cuối cùng ta cũng đã xét mô hình các hàm đệ quy trừu tượng thao tác trên các đối tượng
(các bộ−n của các số nguyên) không được biểu diễn.
Ta thấy rằng các lớp hàm tính được nhờ các phần tử của mỗi một trong các mô hình trên
đây luôn luôn là như nhau. Hơn nữa, những mô hình khác đã được nghiên cứu cho đến nay
như :
− các văn phạm (grammar),
− hệ viết lại (rewriting system),
− thuật toán Markov (Markov algorithm),
− phép tính l (l-calculus),
− các hệ Post (Post systems),
− hệ L, v.v...,
74 Lý thuyết tính toán
đều chưa cho phép định nghĩa một lớp hàm tính được rộng hơn. Với một số nhà nghiên cứu, thì
lớp các hàm này là lớp lớn nhất mà người ta có thể định nghĩa như một mô hình tính toán.
Niềm tin này đối với lớp các hàm tính được một cách máy móc (mechanically) được thể
hiện qua luận đề Church (Church's thesis, hay Church-Turing thesis) phát biểu như sau :

LUẬN ĐỀ CHURCH
Mọi hàm tính được một cách máy móc là Turing-tính được.
Để chứng minh luận đề Church, ta cần so sánh các thủ tục hiệu quảf (effective procedure)
là một khái niệm trực giác với các máy Turing là một khái niệm hình thức. Do đó, ta cần hình
thức hoá khái niệm về thủ tục hiệu quả. Nhưng khi đó, ta lại phải giải quyết vấn đề là có sự
tương đương giữa phương pháp hình thức hoá đưa ra và khái niệm trực giác hay không ? Lời
giải của vấn đề này lại nảy sinh ra một luận đề Church khác và như vậy, ta sẽ đi đến một sự
truy lùi vô hạn.
Nhưng một khi đã chấp nhận luận đề Church, thì tồn tại các hàm không là T-tính được do
tồn tại các hàm không tính được một cách máy móc.
Cũng có thể giả thiết rằng người ta sử dụng một cơ chế mới cho phép nhận được một lớp
hàm lớn hơn, khi đó tính có hạn của việc mô tả các phần tử tuân theo cơ chế này sẽ dẫn đến
một tập hợp đếm được các hàm tính được bởi cơ chế này, và bởi kỹ thuật đường chéo, người ta
cũng có thể chỉ ra rằng, các hàm rơi ra ngoài tập hợp này.
Như vậy, ta đã khẳng định rằng, không thể tính toán được hết (giải hết các bài toán) nhờ
máy tính. Chương sau đây sẽ chỉ ra một số bài toán không thể giải được bằng máy tính.

Bài tập
1. Chứng minh rằng các hàm sau đây là đệ quy nguyên thuỷ :
a) remainder (n, m) = phần dư của phép chia n cho m
b) power (n, m) = nm
c) factorial (n) = n!
d) divesiontest (n,m) = 1 nếu n chia hết m
= 0 nếu n không chia hết m
e) primetest (n) = 1 nếu n là số nguyên tố
= 0 nếu n không phải là số nguyên tố
f) prime (n) = số nguyên tố thứ n
g) exponent (n, m) = max { k ∈ Ν | mk chia hết cho n }
2. Ta định nghĩa sơ đồ tối thiểu bị chặn mink bởi : xuất phát từ một hàm f,
mink (f) là một hàm h được xác định bởi :
h(m) = số bé nhất y ≤ k sao cho f (y, m ) = 0 nếu một số y như vậy tồn tại
= 0 nếu không.
Chứng minh rằng nếu f là một hàm đệ quy nguyên thuỷ, thì mink (f) cũng là hàm đệ quy
nguyên thuỷ.

f
Ta có thể đồng nhất thuật ngữ này với thuật toán.
Mô hình các máy RAM 75
3. a) Cho hàm c được định nghĩa bởi :
c(n, m) = 2n + 2n + m + 1
Chứng minh răng c là một đơn ánh đệ quy nguyên thuỷ từ Ν × Ν → Ν.
Cho d là hàm "ngược lại" từ Ν → Ν × Ν được định nghĩa bởi :
d(p) = (n, m) ⇔ c (n, m) = p
Gọi d1 và d2 là các hàm Ν → Ν được định nghĩa bởi :
d1(p) = n và d2(p) = m ⇔ c (n, m) = p.
Hãy chứng minh rằng d, d1 và d2 đều là các hàm đệ quy nguyên thuỷ.
b) Phép mã hoá các dãy số nguyên dưới đây được gọi là phép đánh số Gdel :
g : N* → N được định nghĩa bởi : g (i1, i2, ..., ir) = 2 i 1 3 i 2....p i i r
với pi là số nguyên tố thứ i
Hãy chứng minh rằng g và g-1 là các hàm đệ quy nguyên thuỷ.
4. Cho S là bảng chữ có thứ tự kích thước k. Giả sử n là ánh xạ từ S* → Ν để đánh số các câu
theo thứ tự phân cấp. Chứng minh rằng các hàm sau đây đều là đệ quy nguyên thuỷ :
- letter (i, n) = 0 nếu i > | n-1 (n) |
letter (i, n) = số thứ tự của ký tự thứ i của câu n-1(n) nếu i ≤ | n-1 (n) |
- factor (i, j, n) = số thứ tự của thừa số của câu n-1(n) bắt đầu từ ký tự thứ i và kết thúc ở
ký tự thứ j nếu i ≤ j ≤ | n-1 (n) |
- factortest (m,n) = 1 nếu n-1(m) là một thừa
số của n-1(n)
= 0 nếu không phải.
5. Cho ri là hàm đệ quy toàn phần thứ i trong phép đánh số hàm đã cho. Người ta cũng đánh
số các câu theo thứ tự phân cấp và ký hiệu wj là câu thứ j theo thứ tự này. Chứng minh hàm
toàn phần f được định nghĩa bởi :
f (wi) = successor (ri (wi))
là một hàm đệ quy, đối với các hàm ri thì f không phải đệ quy.
6. Cho h là một hàm, xây dựng từ h hàm h~ như sau:
h~ (0, m) = 1
h~ (n + 1, m) = ∏ p h (i , m ) + 1
i trong đó pi là số nguyên tố thứ i
0≤ ≤
i n
Tiếp tục định nghĩa sơ đồ đệ quy tổng quát renrec(f, g) như sau : xuất phát từ hai hàm f và
g, định nghĩa hàm h = renrec(f, g) :
h(n, m) = f (m ) nếu n = 0
= g (n', h~(n', m), m) nếu n = n' + 1
Chứng minh rằng f là một hàm đệ quy nguyên thuỷ, thì renrec(f, g) cũng là hàm đệ quy
nguyên thuỷ.
7. Cho hàm Ackermann từ Ν × Ν → Ν:
A (0, m) = m + 1
A (n + 1, 0) = A (n + 1)
A (n + 1, m + 1) = A (n, A (n + 1, m))
76 Lý thuyết tính toán
Gọi Ai là các hàm từ Ν → Ν được định nghĩa bởi : Ai (m) = A (i, m).
a) Tính giá trị hàm Ai với i = 0, 1, 2, 3 và 4.
Người ta nói rằng hàm g : Ν → Ν làm tăng (increase) hàm f : Νk → Ν nếu:
∀x1, x2, ..., xk : f (x1, x2, ..., xk) < g (max { x1, x2, ..., xk }).
b) Chứng minh rằng nếu f là một hàm đệ quy nguyên thuỷ, thì tồn tại một số nguyên i sao
cho Ai làm tăng f.
c) Chứng minh rằng A không làm tăng một hàm Ai nào khác.
8. Tập hợp k các hàm đệ quy bộ phận đã cho là đếm được. Ký hiệu gi là hàm thứ i của k. Hãy
chứng minh định lý Kleene về sự tham số hoá (parameterrization) như sau :
∀ n, p, tồn tại hàm đệ quy snp : Νn + 1 → Ν sao cho : ∀x1, x2, ..., xn+p và ∀ i :
gi (x1, x2, ..., xn+p) = gj (xn+1, xn+2, xn+p)
với j = snp (i, x1, x2, ..., xn).
Định lý đệ quy của Kleene : Xét hàm h được định nghĩa như sau :
h (j, x) = gr (x) nếu gj (j) = r xác định
= không xác định nếu không phải.
Cho i là số thứ tự của h, và k là số thứ tự của s11. Hãy kiểm tra rằng :
gi (i, x) = ggk (i, j) (x)
1
gk (i, j) = gs (j) với s = s1 (k, i)
Với mọi hàm đệ qui f, người ta kết hợp f với số nguyên p là số thứ tự của phép hợp thành
của f và gs, gia sử n = gs (p).
Chứng minh rằng ∀x : gn (x) = gf (n) (x).
CHƯƠNG 5

Các bài toán không quyết định được


(Undecidable Problems)
« Very unlike a divine man would he be who
is unable to count one, two, three »
Plato

I. Các ngôn ngữ liệt kê đệ quy


và các ngôn ngữ đệ quy
Trong mục này, ta sẽ định nghĩa các ngôn ngữ liệt kê đệ quy (recursively
enumerable languages) và các ngôn ngữ đệ quy (recursive languages) nhờ các máy
Turing có trạng thái thừa nhận (accepted states). Ta cũng chỉ ra các đặc điểm của
chúng dựa theo các máy liệt kê (enumerator machines).
Định nghĩa 5.1 :
Một máy Turing có một tập hợp A các trạng thái là các trạng thái thừa nhận thì
được gọi là một máy Turing có trạng thái thừa nhận.
Lúc này máy Turing là một bộ bốn :
T = <S, Q, P, A>
trong đó S, Q, P cùng nghĩa với các máy Turing thông thường, còn A ⊆ Q là tập hợp
các trạng thái thừa nhận.
Một trạng thái được gọi là loại bỏ (reject states) nếu không phải là trạng thái thừa
nhận.
Định nghĩa 5.2 :
Một câu f là được nhận biết (recognized, accepted) bởi một máy Turing có trạng
thái thừa nhận T = <S, Q, P, A> nếu tồn tại một tính toán hợp thức dừng để chuyển
một cấu hình xuất phát có câu vào f ở trên băng về một cấu hình mà trạng thái của
cấu hình này thuộc A.
Cho trước một câu vào f, xảy ra ba trường hợp như sau :
Không có một tính toán hợp thức nào dừng.
Tồn tại một tính toán hợp thức dừng và tất cả các tính toán hợp thức dừng đều
dẫn đến các trạng thái không thuộc A.
Tồn tại một tính toán hợp thức dừng và dẫn đến một trạng thái thuộc A.
Như vậy, ngôn ngữ được nhận biết bởi một máy Turing có trạng thái thừa nhận là
tập hợp các câu được nhận biết bởi máy này.
Trong trường hợp đơn định, ba trường hợp trên đây được phát biểu lại đơn giản
hơn như sau :

PGS. TS. PHAN HUY KHÂNH biên soạn 77


78 Lý thuyết tính toán

Tính toán hợp thức không dừng.


Tính toán hợp thức dừng và dẫn đến một trạng thái không thuộc A.
Tính toán hợp thức dừng và dẫn đến một trạng thái thuộc A.
Mệnh đề 5.1 :
Một ngôn ngữ L được nhận biết bởi một máy Turing (không đơn định) có các
trạng thái thừa nhận (một cách tương ứng : có một tính toán dừng cho mọi dữ liệu
vào) nếu và chỉ nếu tồn tại một máy Turing đơn định có trạng thái dừng (một cách
tương ứng : có một tính toán hợp thức dừng và dẫn đến một trạng thái thuộc A) thừa
nhận ngôn ngữ này.
Chứng minh :
Ta chỉ cần chứng minh đặc trưng cần thiết của mệnh đề này. Muốn vậy, chỉ cần
kiểm tra nếu T là một máy Turing có trạng thái dừng không đơn định nhận biết ngôn
ngữ L, thì việc xây dựng một máy Turing đơn định T’ mô phỏng máy T có các trạng
thái thừa nhận nhận biết L.
Ta cũng chỉ ra rằng nếu T có một tính toán dừng cho mọi câu vào, thì T’ cũng có
tính toán dừng cho mọi câu vào.
Căn cứ vào mệnh đề này, từ nay, ta chỉ cần xem xét các máy Turing đơn định mà
thôi.
Mệnh đề sau đây có nghĩa rằng sự nhận biết (recognition) theo kiểu mới (không
dừng trong một trạng thái thừa nhận) là tương đương với kiểu không dừng đã trình
bày trong chương trước.
Mệnh đề 5.2 :
Một ngôn ngữ là được nhận biết bởi một máy Turing có các trạng thái
thừa nhận nếu và chỉ nếu ngôn ngữ này được thừa nhận (không dừng) bởi một máy
Turing.
Chứng minh :
“⇒” Cho L là ngôn ngữ được nhận biết bởi một máy Turing có các trạng thái
dừng T = <S, Q, P, A>.
Xây dựng từ T một máy Turing T’ = <S, Q’, P∪P’> bằng cách thêm vào Q một
trạng thái mới qv : Q’ = Q ∪ {qv}, và thêm vào P tập hợp P’ các quy tắc như sau :
P’ = { qv, x → x, R, qv } ∀x ∈ S
∪ { q, x → x, R, qv } ∀q, x sao cho (q, x) không là vế trái của một
quy tắc nào trong P và q ∉ A
Như thế, mọi tính toán dừng trong một trạng thái không thuộc A đều có thể kéo
dài vô hạn. Các câu rơi vào trường hợp thứ hai thì cũng sẽ rơi vào trong trường hợp
thứ nhất. Vậy L là được nhận biết bởi T’ (không dừng).
“⇐” Ngược lại, nếu L được nhận biết (không dừng) bởi T = <S, Q, P>, L sẽ được
nhận biết bởi các trạng thái thừa nhận của T’ = <S, Q, P, Q>.
Các bài toán không quyết định được 79

Có vẻ khác thường khi ta đưa vào kiểu nhận biết mới tương đương với kiểu nhận
biết trước đây. Tuy nhiên, việc đưa kiểu nhận biết mới này đã được chứng minh vì
rằng ta sẽ nghiên cứu tiếp theo đây về các máy Turing luôn luôn dừng.
Định nghĩa 5.3 :
Một ngôn ngữ là liệt kê đệ quy nếu tồn tại một máy Turing với các trạng thái dừng
nhận biết nó.
Một ngôn ngữ là đệ quy nếu tồn tại một máy Turing với các trạng thái dừng có
một tính toán dừng cho mọi dữ liệu vào và nhận biết ngôn ngữ đó.
Rõ ràng, nếu T = <S, Q, P, A> là một máy Turing (đơn định) với trạng thái dừng
có một tính toán dừng cho mọi dữ liệu vào, thì với một dữ liệu f, sẽ chỉ có hai trường
hợp sau đây xảy ra :
− Tính toán hợp thức dừng và dẫn đến một trạng thái không thuộc A.
− Tính toán hợp thức dừng và dẫn đến một trạng thái thuộc A.
Cần phải chú ý rằng, sự kiện một máy Turing thỏa mãn hay không thỏa mãn điều
kiện có một tính toán dừng cho mọi dữ liệu vào không có mặt trong định nghĩa của
máy Turing này. Và, không tồn tại một phương pháp có tính hệ thống nào (nghĩa là
có hiệu lực cho tất cả các máy Turing) cho phép biết được là điều kiện này có thỏa
mãn hay không.
Ta sẽ ký hiệu RE là họ tất cả các ngôn ngữ liệt kê đệ quy, và R là họ tất cả các
ngôn ngữ đệ quy.
Mệnh đề 5.3 :
Họ R là đóng đối với phép bù (complement).
Chứng minh :
Dễ thấy rằng nếu T = <S, Q, P, A> là một máy Turing đơn định với các trạng thái
dừng nhận biết ngôn ngữ L, thì T’ = <S, Q, P, Q\A> là một máy Turing (đơn định)
với trạng thái dừng nhận biết phần bù của L.
Mệnh đề 5.4 :
Nếu một ngôn ngữ L và phần bù S*\L của nó đều là liệt kê đệ quy, thì chúng cũng
là các ngôn ngữ đệ quy.
Chứng minh :
Cho T là một máy Turing nhận biết L và giả sử T’ là một máy Turing nhận biết
*
S \L. Xuất phát từ T và T’, xây dựng một máy Turing thứ ba T” theo cách sau đây :
Máy Turing T” có hai băng và được khởi động bằng cách chép lại dữ liệu vào f từ
băng thứ nhất lên băng thứ hai. Sau đó, T” mô phỏng cách tính toán của T trên băng
thứ nhất và cách tính toán của T’ trên băng thứ hai bằng cách thực hiện lần lượt một
bước tính toán trên băng thứ nhất rồi lại một bước tính toán trên băng thứ hai. T”
dừng ngay khi sự mô phỏng một trong hai máy dẫn đến một cấu hình dừng.
Nếu đó là T, thì T” dừng trong một trạng thái qh . Nếu đó là T’, thì dừng trong
1
một trạng thái qh .
2
80 Lý thuyết tính toán

Một câu f là dữ liệu đã cho hoặc thuộc L, hoặc thuộc S*\L, hoặc T, hoặc T’ dừng
trên dữ liệu f, do vậy T” dừng trên mọi dữ liệu vào.
Bằng cách lấy qh1 như là một trạng thái dừng duy nhất, T” nhận biết L là một
ngôn ngữ đệ quy. Tương tự S*\L cũng là đệ quy : ngôn ngữ bù này được nhận biết
bởi T” với một trạng thái dừng duy nhất qh .
2

Máy Turing liệt kê các câu


Khi ta có một máy Turing một băng ra (xem chương 3 về các máy Turing có băng
ra), máy này ghi các ký tự của bảng chữ S lên băng. Điều này chỉ có thể có ích nếu S
chứa ít nhất hai ký tự.
Trong trường hợp này, nếu ta phân biệt một ký tự # của S, gọi là dấu phân cách,
thì những gì đã được ghi trên băng ra là dãy các câu trên bảng chữ S\{#} được đặt
cách nhau bởi các dấu #.
Định nghĩa 5.4 :
Nếu T là một máy Turing với một băng ra, T ghi lên băng ra các ký tự của một
bảng chữ S có chứa một ký tự đánh dấu #, thì người ta gọi ngôn ngữ được liệt kê bởi
T là tập hợp các câu được ghi trên băng cách nhau bởi các ký tự # này.
Mệnh đề 5.5 :
Ngôn ngữ L ∈ RE nếu và chỉ nếu tồn tại một máy Turing liệt kê L.
Ngôn ngữ L ∈ R nếu và chỉ nếu tồn tại một máy Turing liệt kê L trong thứ tự
phân cấp.
Chứng minh :
“⇐” (L ∈ RE ⇐ tồn tại một máy Turing liệt kê L)
Giả sử T là một máy Turing liệt kê ngôn ngữ L. Xuất phát từ T, xây dựng một máy
Turing T’ nhận biết L theo cách như sau :
T’ có nhiều hơn T một băng, trên đó ghi dữ liệu vào f. Còn các băng khác, T’ sử
dụng như T sử dụng để mô phỏng chức năng của T, nhưng xem băng ra của T như là
một băng làm việc bình thường. T’ liệt kê các câu của L, nhưng với mỗi câu đã liệt kê
(nghĩa là mỗi lần T’ viết ký tự đánh dấu lên băng vừa thêm), T’ kiểm tra câu vừa đánh
dấu là khác với câu f. Nếu khác, T’ tiếp tục việc đánh dấu, còn nếu giống nhau (nghĩa
là câu vừa đánh dấu chính là f), thì T’ dừng.
Rõ ràng máy T’ vừa mô tả nhận biết L.
“⇐” (L ∈ R ⇐ tồn tại một máy Turing liệt kê L trong thứ tự phân cấp)
Xảy ra hai trường hợp :
- L hữu hạn, rõ ràng L là ngôn ngữ đệ quy
- L là vô hạn, việc chứng minh hoàn toàn tương tự trên đây.
Người ta đòi hỏi thêm rằng, khi T kiểm tra nếu câu đã liệt kê là khác với câu f
đang xét, nếu câu trả lời là đúng, T’ sẽ chỉ tiếp tục đánh số nếu f có mặt, trong thứ tự
Các bài toán không quyết định được 81

phân cấp, sau câu đã liệt kê và T’ dừng nếu f không có mặt trong một trạng thái loại
bỏ (T’ dừng trong một trạng thái dừng khi xảy ra sự bằng nhau).
Rõ ràng, máy T’ dừng cho mọi dữ liệu và nhận biết L.
“⇒” (L ∈ R ⇒ tồn tại một máy Turing liệt kê L trong thứ tự phân cấp)
Cho T là một máy Turing dừng cho mọi dữ liệu và nhận biết L. Từ T, xây dựng
một máy Turing T’ liệt kê L theo cách như sau :
T’ có nhiều hơn T hai băng. Trên một băng này, tất cả câu của S* được liệt kê
(trong thứ tự phân cấp). Còn trên băng kia dùng làm băng ra, tất cả các câu của L
được liệt kê. Với mỗi câu được liệt kê f ∈ S*, T’ sao chép lại câu này trên băng mà
trong T, đó là băng chứa dữ liệu.
Máy T’ sẽ mô phỏng hoạt động của T trên dữ liệu nà. Nếu T dừng cho dữ liệu f
trong một trạng thái thừa nhận, thì T’ ghi câu f lên băng ra theo sau ký tự đánh dấu.
Trong mọi trường hợp, T’ bắt đầu trở lại việc đánh số các câu của S*.
Vậy, rõ ràng máy T’ mô phỏng L trong thứ tự phân cấp.
“⇒” (L ∈ RE ⇒ tồn tại một máy Turing liệt kê L)
Nếu ta sử dụng cách chứng minh vừa mới trình bày trên đây thì sẽ không nhận
được kết quả, vì rằng máy Turing nhận biết L khi không dừng cho một câu bị loại bỏ
sẽ không cho phép chuyển qua câu tiếp theo, mà câu này có thể ∈ L.
Như thế, ta phải sử dụng cách chứng minh phức tạp hơn như sau :
Cho T là một máy Turing nhận biết L. Từ T, xây dựng một máy Turing T’ liệt kê L
theo cách như sau :
T’ có nhiều hơn T hai băng. Trên một băng này, liệt kê tất cả các cặp (f, n) trong
đó f là một câu ∈ S* và n là một số nguyên. Còn trên băng kia dùng làm băng ra, liệt
kê tất cả các câu của L. Với mỗi câu f đã liệt kê ∈ S*, T’ sao chép câu này lên băng
mà trong T, đó là băng chứa dữ liệu. T’ mô phỏng n bước tính toán của T trên dữ liệu
này. Nếu T dừng với dữ liệu f sau n bước tính toán, T’ ghi câu f lên băng ra phía sau
ký tự đánh dấu, và trong mọi trường hợp, T’ lại tiếp tục đánh số các cặp.
Dễ dàng kiểm chứng rằng máy T vừa mô tả liệt kê L trong thứ tự phân cấp.
Mệnh đề 5.5 :
Ngôn ngữ Lu sau đây không là đệ quy :

Lu = { <w, f>| máy Turing có mã w dừng trên dữ liệu vào f } ∈ RE\R.


Chứng minh :
Kết quả này đã được chỉ ra dưới một dạng khác ở chương 3.
Ta nhớ lại rằng máy Turing vạn năng Tu thỏa mãn cho ∀i và ∀f :
Tu (i#f) = gi (f) với gi là hàm được tính bởi máy Turing thứ i.
Một dạng khác của máy Turing vạn năng là Tu" thỏa mãn mọi mã w của máy
Turing thứ i, và với mọi câu f :
82 Lý thuyết tính toán

Tu" (<w, f>) = gi (f) với gi là hàm được tính bởi máy Turing thứ i.
Mặt khác, ta cũng nhớ lại rằng hàm th, xác định trên mọi cặp số nguyên i, j, cho
bởi định nghĩa sau đây không là T-tính được :
th (i, j) = 1 nếu máy Turing thứ i dừng trên dữ liệu j.
th (i, j) = 0 nếu không phải.
Do miền xác định của hàm được tính bởi máy Turing vạn năng Tu" là Lu, nên Tu"
sẽ nhận biết L. Vậy, Lu ∈ RE.
Mặt khác, ta có thể dễ dàng suy ra rằng hàm th không là T−tính được và
Lu ∉ R. Thật vậy, nếu không phải như thế, bằng phản chứng, xuất phát từ một máy
Turing T có trạng thái dừng dừng cho mọi dữ liệu vào và nhận biết Lu, ta xây dựng
một máy Turing T’ thực hiện hàm th. Chỉ cần mở rộng các tính toán của T thành hàm
với trạng thái dừng : nếu trạng thái này thuộc về tập hợp các trạng thái thừa nhận của
T, phép tính toán được mở rộng bằng cách xóa kết quả của T rồi ghi thành hằng 1.
Nếu không phải như vậy thì xóa kết quả của T rồi ghi thành hằng 0.QED
Bổ đề 5.1 :
Tồn tại các ngôn ngữ không là liệt kê đệ quy.
Thật vậy, nếu không phải như vậy thì ngôn ngữ Lu sẽ là liệt kê đệ quy, và phần bù
của Lu là S*\Lu sẽ là đệ quy, nhưng điều này là không đúng QED.

II. Các bài toán không quyết định được


(Undecidable problems)
Ta nhớ lại rằng một bài toán được cấu thành bởi hai yếu tố :
1. Mô tả cách biểu diễn (hữu hạn) các phần tử của một tập hợp D hữu hạn hoặc
vô hạn đếm được. Mỗi phần tử của D được gọi là một câu.
2. Một phát biểu dựa vào tập hợp D này, có thể đúng, hoặc có thể sai tùy theo
phần tử (câu) được lựa chọn từ D.
Với mỗi bài toán♣ P, được hợp thành từ các câu của tập hợp D đang xét và từ một
phát biểu dựa theo D, ta xét một ngôn ngữ đặc trưng LP của P. Ngôn ngữ LP được
cấu thành từ tập hợp câu của D có lời giải là đúng. Tương tự như vậy, người ta xét
ngôn ngữ đặc trưng LCP của bài toán ngược CP nhận được từ P bằng cách giữ
nguyên cách biểu diễn các dữ liệu nhưng phát biểu theo nghĩa trái ngược (lời giải có
giá trị sai - contrary).
Như vậy, lời giải của một bài toán dẫn đến sự nhận biết của một ngôn ngữ : một
máy giải một bài toán P nếu và chỉ nếu với mọi câu w ∈ D (là biểu diễn một phần tử
của D cho bài toán này), máy cho phép xác định, trong một khoảng thời gian hữu hạn,
nếu w ∈ LP hay w ∈ LCP.

♣ Ta đồng nhất hai thuật ngữ vấn đề và bài toán (problem).


Các bài toán không quyết định được 83

Nếu ta thừa nhận luận đề Church, thì việc giải một bài toán chính là việc đưa ra
một máy Turing cho phép xác định, trong một khoảng thời gian hữu hạn, nếu quả thật
câu w ∈ LP hay w ∈ LCP. Như vậy, tồn tại một máy Turing dừng cho mọi dữ liệu và
nhận biết LP. Từ đó ta có định nghĩa sau đây.
Định nghĩa 5.5 :
Một bài toán P được gọi là quyết định được (decidable) nếu ngôn ngữ đặc trưng
LP là đệ quy.
Bài toán P được gọi là không quyết định được (undecidable) nếu LP không phải là
đệ quy.
Người ta còn gọi một bài toán P là nửa quyết định (semi−decidable) nếu ngôn ngữ
đặc trưng LP là liệt kê đệ quy (không là đệ quy).
Một trong những kết quả quan trọng nhất của Tin học cơ bản là tồn tại những bài
toán không quyết định được.
Chẳng hạn, bài toán say đây là không quyết định được :
Dữ liệu : Một cặp (w, f), w là mã của một máy Turing và f là một câu.
Câu hỏi : Máy Turing có mã w có dừng trên dữ liệu f hay không ?
Thật vậy, ngôn ngữ đặc trưng LP của bài toán này là Lu mà ta đã chỉ ra rằng, Lu
không phải là ngôn ngữ đệ quy.
Bài toán này được gọi là bài toán dừng (halting problem) của các máy Turing.
Dưới đây, ta sẽ chỉ ra đặc trưng không quyết định được của nhiều bài toán khác
nhưng có thể đưa về bài toán này một cách trực tiếp hoặc gián tiếp.

III. Thuật toán rút gọn một bài toán về bài toán
khác
Định nghĩa 5.6
Ta nói rằng bài toán A được rút gọn theo một thuật toán nào đó (gọi tắt là rút gọn)
về bài toán B nếu tồn tại một máy Turing dừng cho mọi dữ liệu và thực hiện tính hàm
f, là ánh xạ từ tập hợp các biểu diễn của các dữ liệu của bài toán A vào tập hợp các
biểu diễn của các dữ liệu của bài toán B, thỏa mãn :
w ∈ LA ⇔ f (w) ∈ LB
Trong định nghĩa này, câu theo một thuật toán nào đó (algorithmically) có nghĩa
nhờ một thuật toán, theo luận đề Church, tức là nhờ một máy Turing.
Người ta nói rằng máy Turing như vậy rút gọn bài toán A về bài toán B.
84 Lý thuyết tính toán

Anh của f từ các


Biểu diễn dữ f biểu diễn dữ liệu của
liệu của bài LP LP bài toán A
A B
toán A
f
S*\LP S*\LP Biểu diễn dữ liệu
A B của bài toán B

Hình 5.1 Rút gọn bài toán A về bài toán B

Ta có mệnh đề sau :
Mệnh đề 5.7 :
Nếu một bài toán A được rút gọn thành bài toán B, thì nếu B là bài toán quyết định
được, thì A cũng là bài toán quyết định được.
Chứng minh :
Thật vậy, giả sử T là một máy Turing luôn luôn dừng và nhận biết LB, T’ là một
máy Turing thực hiện việc rút gọn từ bài toán A về bài toán B. Rõ ràng, máy Turing
T’ next T là một máy Turing luôn luôn dừng và nhận biết LA.
Thực tế, người ta sử dụng mệnh đề trái lại như sau :
Mệnh đề 5.8 :
Nếu bài toán A được rút gọn thành bài toán B, thì nếu A là một bài toán không
quyết định được, thì B cũng là một bài toán không quyết định được.
Ví dụ 5.1 : Bài toán dừng đều (uniform halting problem) của các máy Turing.
Người ta gọi bài toán dừng đều của các máy Turing là bài toán như sau :
Dữ liệu : Một máy Turing M.
Câu hỏi : M có dừng cho mọi dữ liệu vào ?
Bây giờ ta rút gọn bài toán dừng của các máy Turing về bài toán mới này.
Giả sử T là một máy Turing và f là một câu, hợp thành một trường hợp cá biệt
(instance) của bài toán dừng của các máy Turing. Xuất phát từ (T, f), xây dựng một
máy Turing M đọc dữ liệu của T và dừng trong một trạng thái loại bỏ nếu dữ liệu này
không phải là câu f. Sau đó, nếu dữ liệu đúng là f, thì M bắt chước cách tính toán của
T trên dữ liệu f. Rõ ràng, T dừng trên dữ liệu f nếu và chỉ nếu M dừng trên mọi dữ
liệu.
Sau khi rút gọn một bài toán không quyết định được về bài toán dừng đều của các
máy Turing, người ta suy ra rằng bài toán dừng đều của các máy Turing là không
quyết định được.
Các bài toán không quyết định được 85

Chú ý :
Cho A là một bài toán, nếu thay đổi cách biểu diễn dữ liệu nhưng vẫn giữ nguyên
câu hỏi, thì ta nhận được bài toán A’.
Nếu cách biểu diễn dữ liệu được thay đổi như sau :
- Tồn tại một máy Turing T, xuất phát từ cách biểu diễn của cùng phần tử của bài
toán A, trả về một biểu diễn của cùng phần tử đó của bài toán A’.
- Tồn tại một máy Turing T’, xuất phát từ cách biểu diễn một phần tử của bài
toán A’, trả về một biểu diễn của cùng phần tử đó của bài toán A.
Thì khi đó, A và A’ đồng thời là quyết định được hoặc không quyết định được.
Thật vậy, bài toán A được rút gọn theo một thuật toán nào đó về bài toán A’ tương
ứng với máy Turing A, và ngược lại A’ được rút gọn về A tương ứng với Turing T’.
Đặc trưng quyết định được hay không quyết định được của một bài toán vẫn là
không thay đổi khi thay đổi, trong phạm vi hợp lý, sự biểu diễn của các dữ liệu.
Người ta thường sai lầm khi chỉ định một bài toán chỉ bởi câu hỏi mà thôi. Do vậy
cần phải tránh sai lầm này.
Khi người ta xét đến độ phức tạp (complexity) của một bài toán, sự biểu diễn các
dữ liệu là tuyệt đối cần thiết để đánh giá độ phức tạp.
Bây giờ ta tiếp tục xét các bài toán không quyết định được. Chúng rất nhiều như
định lý Rice sau đây khẳng định.
Định lý Rice :
Mọi tính chất không tầm thường của các ngôn ngữ liệt kê đệ quy là không quyết
định được.
Ta nhớ lại rằng một tính chất được nói là tầm thường (trivial) nếu tất cả các phần
tử của tập hợp đang xét đều cùng có tính chất này, hoặc không một phần tử nào trong
chúng có tính chất này cả.
Định lý Rice có nghĩa là nếu P là một tính chất không tầm thường, thì bài toán sau
đây là bài toán không quyết định được :
Dữ liệu : Một máy Turing (nhận biết một ngôn ngữ liệt kê đệ quy).
Câu hỏi : Ngôn ngữ này có tính chất P không ?
Chứng minh
Cho P là một tính chất không tầm thường và J là họ các ngôn ngữ liệt kê đệ quy
có tính chất P. Ta có thể luôn luôn giả thiết rằng ngôn ngữ trống (∅) không thuộc J.
Khi đó, tồn tại ít nhất một ngôn ngữ L ≠ f và L ∈ J, L được nhận biết bởi một máy
Turing TL.
Xuất phát từ một dữ liệu <w, f>, trong đó w là mã của một máy Turing T và f là
một dữ liệu cho máy này, và xuất phát từ TL, xây dựng một máy Turing T’ thực hiện
các phép toán sau đây : trên mọi dữ liệu g, T’ mô phỏng tính toán của T trên f, độc lập
với dữ liệu g, rồi khi thành công, T’ thực hiện tính toán của TL trên dữ liệu g.
86 Lý thuyết tính toán

Rõ ràng T’ nhận biết được hoặc ngôn ngữ trống, nếu T không dừng trên f, hoặc
ngôn ngữ L, nếu T dừng trên f. Do đó, ngôn ngữ nhận biết bởi T’ là trong J nếu và chỉ
nếu T có một tính toán và dừng trên dữ liệu f.
Nếu ta giả thiết rằng tính chất đang xét là quyết định được, ta có một máy Turing
luôn luôn dừng và xác định nếu ngôn ngữ nhận biết bởi T’ là thuộc J. Từ đó suy ra
tồn tại một máy Turing luôn luôn dừng và, xuất phát từ một dữ liệu <w, f>, trong đó
w là mã của một máy Turing T, máy này xác định nếu T dừng hoặc không dừng trên
dữ liệu vào f.
Tuy nhiên, ta biết rằng một máy Turing như vậy (dừng trên mọi dữ liệu và nhận
biết Lu) là không tồn tại QED.
Ngoài các bài toán không quyết định được này, theo định lý Rice, còn rất nhiều
bài toán khác đến từ các miền xác định khác nhau, đều không quyết định được. Chính
vì vậy mà khái niệm về bài toán không quyết định được đóng vai trò quan trọng trong
tin học lý thuyết.
Bây giờ ta đưa ra bốn ví dụ cổ điển. Mỗi lần đưa ra một bài toán không quyết định
được, ta tìm cách rút gọn về bài toán đã xét.
Ví dụ 5.2 :
1. Bài toán tương ứng Post (Post’s correspondence problem)
Dữ liệu : Một dãy các cặp câu (u1, v1), ..., (uk, vk) trên một bảng chữ S
(S có ít nhất 2 ký tự).
Câu hỏi : Tồn tại hay không một câu w∈ S* thừa nhận hai phân tách
tương ứng với : w = ui ui ...ui = vi v i ... v i ?
1 2 r 1 2 r
Trong đó i1 , i2 , ..., ir ∈ { 1, 2, ..., k }

1bis. Bài toán tương ứng Post cải biên (Post’s correspondence problem)
Dữ liệu : Một dãy các cặp câu (u1, v1), ..., (uk, vk) trên một bảng chữ S
(S có ít nhất 2 ký tự).
Câu hỏi : Tồn tại hay không một câu w∈ S* thừa nhận hai phân tách
tương ứng với phần tử đầu tiên là cặp đầu tiên :
w = u1ui ...ui = v1vi ... vi ?
2 r 2 r
Giả sử cho S = {a, b, c} và cho dãy các cặp câu trên S :
((ab, aba), (ab, ba), (bab, ba), (ab, bab)).
Dễ dàng thấy rằng câu babababab được phân tách thành hai cách :
bab.ab.ab.ab = ba.ba.ba.bab
là tương ứng với nhau. Tuy nhiên, không có câu được phân tách thành hai cách tương
ứng với phần tử đầu tiên là cặp đầu tiên.
Như vậy, với dữ liệu này (là dãy các cặp câu đã cho), bài toán tương ứng Post
thừa nhận (ít nhất) một lời giải. Thế nhưng, cũng với dữ liệu này, thì bài toán Post cải
biên lại không có lời giải.
Các bài toán không quyết định được 87

Bây giờ ta sẽ chứng minh rằng cả hai bài toán này đều không quyết định được
bằng cách bắt đầu từ bài toán thứ hai.
Giả sử T = < S, Q, P> là một máy Turing tiêu chuẩn hóa (rormalized) có một
trạng thái dừng qh duy nhất. Xuất phát từ T, ta định nghĩa một tập hợp F1 các cặp câu
trên y = S ∪ Q ∪ { }, với là một ký tự mới, được cấu thành như sau :
FT = { (qxz, yq’z) | z ∈ S và q, x → y, R, q’ }
1
∪ { (qx , yq’# ) | q, x → y, R, q’ },
FT = { (zqx, q’zy) | z ∈ S và q, x → y, L, q’ }
2
∪ { qx, q’#y) | q, x → y, L, q’ },
FT = { (z, z) | z∈S} ,
3
FT = { (zqh, qh), (qh, qhz) | z ∈ S } ∪ { ( qh , ) }
4
Ứng với mỗi trường hợp cá biệt của bài toán dừng của các máy Turing, nghĩa là
với mọi dữ liệu của bài toán này, được cấu thành từ T là máy Turing tiêu chuẩn hóa
theo giả thiết và f là câu xuất phát trên băng vào của T, ta có thể kết hợp một dữ liệu
FT, f cho bài toán tương ứng Post cải biên được cấu thành từ cặp đầu tiên ( , q1f )
và các cặp của FT.
Ta sẽ chỉ ra rằng trường hợp cá biệt này của bài toán tương ứng Post cải biên có
một lời giải nếu và chỉ nếu T có một tính toán dừng trên dữ liệu f.
Nếu T có một tính toán dừng trên dữ liệu f, tính toán được viết như sau :
co = q1f, c1, ..., cn = g1qhg2
Ta xét câu sau :
w = q1f c1 ... cn-1 g1qhg2 g’1qhg2 ... qhg2 qhg’2 ... qh
trong đó câu g1 bị cắt cụt một ký tự cuối cùng, sau mỗi ký tự ; tiếp đến g2 bị cắt cụt
một ký tự phía đầu, sau mỗi .
Dễ dàng thấy rằng câu w này có hai cách phân tách tương ứng với nhau.
Ngược lại, nếu ta có hai cách phân tách một câu sao cho tương ứng với nhau với
đầu câu là cặp đầu tiên, dễ dàng thấy rằng nếu ci là một cấu hình, và nếu trong cả hai
cách phân tách mà cấu hình theo các u có độ dài hơn cấu hình theo các v của các
thành phần ci , thì khi phân tách theo các u cho đến khi gặp tiếp theo, cấu hình này
có độ dài lớn hơn cấu hình theo các v của thành phần ci+1 .
Hơn nữa, tham đối sơ cấp về số các ký tự chỉ ra rằng cặp cuối cùng đã sử dụng
là ( qh , ). Dễ dàng thấy rằng khi qh xuất hiện lần đầu tiên trong câu thuộc về hai
cách phân tách, qh được bao bởi các câu g1 và g2 sao cho nếu tồn tại một tính toán
hợp thức trong T :
q1f Ã−* g1qhg2
88 Lý thuyết tính toán

Do tính toán hợp thức dẫn đến trạng thái qh, cho nên T sẽ dừng.
Như vậy, ta đã rút gọn bài toán dừng của các máy Turing về bài toán tương ứng
Post cải biên.
Bây giờ giả sử (u1, v1), ..., (uk, vk) là dãy các cặp câu trên một bảng chữ S, tạo
thành một dữ liệu cho bài toán tương ứng Post cải biên. Giả sử a là một ký tự mới.
Với mọi câu f ∈ S*, ta kết hợp các câu p(f) và d(f) được định nghĩa bởi :
nếu f = x1, x2 ... xr, thì p(f) = ax1ax2 ..., axr và
d(f) = x1ax2a ..., xra.
Với mọi dữ liệu cho bài toán tương ứng Post cải biên, ta kết hợp tập hợp U gồm
các cặp như sau :
U = { (p(u1), d(v1)), ..., (p(uk), d(vk)), (p(u1)a, d(v1)), ...,
(p(uk)a, d(vk)), (p(u1), ad(v1)) }
tạo thành một dữ liệu cho bài toán tương ứng Post.
Nếu w = u1ui ...ui = v1vi ... vi là một lời giải của bài toán tương ứng Post cải
2 r 2 r
biên xuất phát, thì rõ ràng, câu p(w)a = ad(w) có hai cách phân tách tương ứng với
nhau theo U :
p(w)a = p(u1)p(ui ) ... p(uir)a = ad(v1) d (vi ) ... d (vi ).
2 2 r
Ngược lại một cách tương ứng, nếu một câu m có hai cách phân tách tương ứng
với nhau theo U, thì cặp đầu tiên sử dụng đến sẽ chỉ có thể là cặp :
(P (u1), ad (v1)).
Bằng cách xóa tất cả chữ a trong m và hai phân tách của m, ta nhận được câu w và
hai phân tách của w tương ứng với nhau dựa theo dãy xuất phát của bài toán tương
ứng Post cải biên, với thành phần đầu tiên là cặp đầu tiên. Như vậy, bài toán tương
ứng Post cải biên đã được rút gọn về bài toán tương ứng Post.
2. Bài toán zero trong các ma trận 3 x 3 hệ số trong Z
Dữ liệu : Một tập hợp hữu hạn M các ma trận hệ số 3´3 trong Z.
Câu hỏi : Tồn tại hay không một tích hữu hạn M = Mi M i ... Mi các ma trận của
1 2 r
M sao cho phần tử (3, 2) của M là bằng 0 ?
Cho bảng chữ có thứ tự S với |S| = n, với mọi câu f ∈ S*, ta ký hiệu như sau :
el (f) = n|f| (|f| là độ dài của câu f)
nu (f) = số thứ tự của f trong thứ tự phân cấp.
Rõ ràng, với mọi câu f, g ∈ S*, ta đều có :
el (fg) = el (f) × el (g)
nu (fg) = nu (f) × el (g) + nu (g)
Bây giờ xét ánh xạ j từ S* × S* vào tập hợp các ma trận hệ số 3´3 trong Z được
xác định như sau :
Các bài toán không quyết định được 89

⎡ el (u) el (v) - el (u) 0 ⎤



j (u, v) = ⎢ 0 el(v) 0 ⎥⎥
⎣⎢nu (u) nu (v) - nu (u) 1⎥⎦
Ta có thể dễ dàng chứng minh rằng j là một đơn ánh đồng cấu, và phần tử (3, 2)
của j (u, v) là bằng 0 nếu và chỉ nếu u = v.
Bây giờ giả sử (u1, v1), ..., (uk, vk) là một dãy các cặp câu trên bảng chữ S tạo
thành một dữ liệu vào cho bài toán tương ứng Post. Tương ứng với trường hợp cá biệt
này, ta đưa vào một tập hợp hữu hạn M các ma trận hệ số 3×3 trong Z :
M = {j (u1, v1), ..., j (uk, vk)}.
Rõ ràng bài toán Post này có lời giải nếu và chỉ nếu tồn tại một tích hữu hạn các
ma trận của M sao cho phần tử (3, 2) của M là bằng 0. Như vậy ta đã rút gọn bài toán
tương ứng Post về bài toán zero trong các ma trận hệ số 3´3 trong Z.
3. Bài toán về sự hội tụ của một dãy phần tử của Z
Người ta nói một dãy đã cho là xác định đệ quy (recursively defined sequence)
nếu với mọi số nguyên n, có thể tìm được một cách hiệu quả, phần tử thứ n của dãy
này.
Bài toán về sự hội tụ của một dãy phần tử của Z được phát biểu như sau :
Dữ liệu : Một dãy phần tử của Z là xác định đệ quy.
Câu hỏi : Hỏi rằng dãy này là một máy Turing và f là một dữ liệu vào của T.
Giả sử T = <S, Q, P> là một máy Turing và f là một dữ liệu vào của T. Ta đánh số
trên Z các ô của băng làm việc của T bắt đầu từ 0 là ô nằm dưới đầu đọc tại vị trí xuất
phát của T.
Xuất phát từ T và f, xác định dãy (un) với un là số thứ tự của ô dưới đầu đọc sau n
bước tính toán của T trên dữ liệu f. Theo quy ước, nếu việc tính toán này là dừng sau
p trước trên ô có số thứ tự 1, thì tất cả các hạng của dãy có vị trí lớn hơn p sẽ có giá
trị 1.
Như vậy, u0 = 0, khoảng cách (độ lệch) giữa un và un+1 bị chặn bởi 1 theo trị
tuyệt đối và chỉ có thể bằng 0 nếu máy T dừng sau tối đa n trước tính toán. Mặt khác,
dãy này là xác định đệ quy.
Vả lại, dãy này là hội tụ nếu và chỉ nếu dãy này không đổi (stationary). Như vậy,
dãy này là hội tụ nếu và chỉ nếu việc tính toán của máy Turing T dừng trên dữ liệu f.
Như vậy ta đã rút gọn bài toán dừng của các máy Turing về bài toán hội tụ của một
dãy.

4. Bài toán về tính kết hợp của một luật cấu thành
Dữ liệu : Một luật cấu thành bên trong của một tập hợp, đệ quy hoàn toàn.
Câu hỏi : Có phải luật này là kết hợp ?
Giả sử T = <S, Q, P> là một máy Turing và f là một dữ liệu của T.
90 Lý thuyết tính toán

Tương tự bài toán 3 đã xét, ta đánh số trên Z các ô của băng làm việc của T kể từ
0 là ô nằm dưới đầu đọc tại vị trí xuất phát của T. Xuất phát từ T và f, xây dựng các
hàm ϕ và s như sau :
ϕ:Ν→Z
s:Z→N
Với ϕ(n) là số thứ tự của ô nằm dưới đầu đọc sau n bước tính toán của T trên dữ
liệu vào f.
Theo quy ước, nếu việc tính toán này là dừng sau p bước trên ô có đánh số thứ tự
1, thì tất cả các hạng của dãy có số thứ tự lớn hơn p sẽ có giá trị 1.
s(z) = µn [ϕ(n) = z]
nghĩa là s(z) là số bước tính toán cần thiết nhỏ nhất để thăm ô có số thứ tự là z. Hàm s
là hàm bộ phận : một số ô trên băng có thể không bao giờ được đầu đọc đến thăm.
Cuối cùng, ta định nghĩa ánh xạ ⊕ từ N × N → N như sau :
⊕ (n, m) = s (j (n) + j (m)) nếu số này xác định
=0 nếu số này không xác định
Ánh xạ ⊕ là một luật cấu thành bên trong của N và là đệ quy hoàn toàn.
Như vậy, ta có thể dễ dàng chứng minh được rằng, nếu :
Imϕ = [-k, +k] với k ≥ 1,
thì ⊕ không có tính kết hợp, và cũng chứng minh được rằng, nếu :
Imϕ = [-∞, +∞],
thì ⊕ là có tính kết hợp.
Bây giờ ta xem xét một dữ liệu cho bài toán dừng của các máy Turing, nghĩa là
một máy T và một câu f. Xuất phát từ T, ta xây dựng một máy T’ thực hiện các phép
tính sau đây : một cách tương hỗ, T’ mô phỏng một bước tính toán của máy T, rồi thì,
trong khi không làm thay đổi nội dung của băng, T’ đi từ trái qua phải đến một ô khác
mà T’ chưa xử lý ở bước trước đó.
Như vậy, trên f, nếu việc tính toán của T, và cũng là của T’, mà dừng, thì các ô đã
được thăm bởi T’ khi tính toán sẽ có các số thứ tự [-k, +k]. Còn nếu như việc tính toán
vừa xét không dừng, thì số thứ tự sẽ là [-∞, +∞].
Bằng cách áp dụng vào T’ và f để xây dựng một luật ⊕ như vừa mô tả trên đây, ta
nhận được kết quả là luật ⊕ có tính kết hợp nếu và chỉ nếu T có một tính toán dừng
trên dữ liệu f. Như vậy, ta đã rút gọn bài toán dừng của các máy Turing về bài toán
tìm tính kết hợp của một luật cấu thành.
Ngoài các bài toán trên, các bài toán sau đây cũng là không quyết định được :
- Bài toán thứ 10 của Hilbert
(một đa thức nhiều biến có nghiệm nguyên không ?)
- Tính đúng đắn (truthfulness) của các công thức số học bậc một.
- Bài toán Thue và nửa−Thue về các câu có cấu trúc đại số bất kỳ.
Các bài toán không quyết định được 91

- Bài toán về tính bằng nhau (equality) của các ngôn ngữ được sinh ra bởi hai
văn phạm đại số (algebra grammars), hay bài toán về tính nhập nhằng
(ambiguity) của một văn phạm đại số.
− v, v...
92 Lý thuyết tính toán

Bài tập
1. Chứng minh rằng ngôn ngữ L là RE nếu và chỉ nếu L là ảnh của N bởi một hàm
đệ quy bộ phận.
2. Xuất phát từ một máy Turing T nhận biết một ngôn ngữ L đã cho và từ một máy
Turing T’ nhận biết phần bù S*\L, xây dựng một máy Turing không đơn định đơn
giản cho phép nhận biết L hoặc S*\L tùy theo một trạng thái thừa nhận đã chọn.
Từ đó suy ra một cách chứng minh mới rằng nếu L và S*\L là các ngôn ngữ liệt kê
đệ quy, thì chúng cũng là các ngôn ngữ đệ quy.
3. Phát biểu bài toán dừng của một máy RAM.
Chứng minh bài toán này là không quyết định được.
4. Chứng minh rằng bài toán sau đây là không quyết định được :
Dữ liệu : Một máy RAM M được xác định bởi chương trình của nó, một dữ liệu
vào f cho máy RAM này và một số nguyên j.
Câu hỏi : Việc tính toán của M trên f có sử dụng đến lệnh thứ j không ?
5. Chứng minh rằng bài toán sau đây là không quyết định được :
Dữ liệu : Một máy RAM M được xác định bởi chương trình của nó và một số
nguyên j.
Câu hỏi : Tồn tại hay không một dữ liệu f để việc tính toán của M trên f sử dụng
đến lệnh thứ j ?
6. Gọi gi là hàm được tính bởi máy Turing thứ i. Các bài toán sau đây có là quyết
định được hay không ?
a) Dữ liệu : Cho trước một số nguyên i.
Câu hỏi : gi có phải là một hàm không ?
b) Dữ liệu : Cho trước ba số nguyên i, j, k.
Câu hỏi : gi (j) = k ?
c) Dữ liệu : Cho trước hai số nguyên i, k.
Câu hỏi : Có tồn tại hay không một số nguyên j sao cho gi (j) = k ?
d) Dữ liệu : Cho trước hai số nguyên i, j.
Câu hỏi : Có phải gi = gj ?
e) Dữ liệu : Cho trước một số nguyên i.
Câu hỏi : Có phải hàm gi có một ảnh hữu hạn.
CHƯƠNG 6

Độ phức tạp tính toán


(Computational Complexity)
« Better one safe way than a hundred on
which you cannot reckon »
Aesop

Trong chương trình này, ta tập trung xem xét những vấn đề liên quan đến các bài
toán quyết định được. Nếu tồn tại một thuật toán giải một bài toán đã cho, thì có thể
xảy ra rằng chưa chắc đã triển khai được thuật toán đó trên một máy tính, vì lý do độ
phức tạp tính toán.
Trong thực tế, độ phức tạp của một thuật toán bắt nguồn từ thời gian tính toán và
bộ nhớ cần sử dụng đến có thể rất lớn. Nhờ những lập luận đơn giản, ta sẽ chỉ ra làm
cách nào để có thể phân lớp các bài toán quyết định được thành những bài toán ít
nhiều phức tạp hơn, không phụ thuộc vào hiện trạng của công nghệ Tin học.
Có nhiều cách đo độ phức tạp tính toán đã được nghiên cứu, đó là độ phức tạp
trung bình, độ phức tạp trong trường hợp xấu nhất, v. v... Dưới đây, ta sẽ chỉ xét độ
phức tạp tính toán trong trường hợp xấu nhất.

I. Độ phức tạp về thời gian và về bộ nhớ


Người ta thường đưa vào khái niệm độ phức tạp cho các ngôn ngữ . Độ phức tạp
của một bài toán là độ phức tạp của ngôn ngữ đặc trưng cho bài toán này.
Ta xét một máy Turing đơn định có k băng và dừng trên mọi dữ liệu. Xuất phát từ
một cấu hình ban đầu (1, q1, f), máy Turing có một tính toán dừng ở độ dài m. Ta
xem rằng tập hợp Ln của tất cả các câu f cùng có một độ dài như nhau là n. Nếu Ln
khác rỗng, với mỗi số nguyên n, ta cho kết hợp với số nguyên :
T(n) = Maxf∈L { độ dài tính toán nhận biết f }
n
Nếu Ln = ∅ (tập hợp trống), ta đặt T (n) = 0.
Hàm T : N → N vừa định nghĩa xác định độ phức tạp về thời gian (time
complexity) T(n) của máy Turing k băng (ta quy ước mỗi bước tính toán kéo dài
trong một khoảng thời gian bằng đơn vị).
Người ta cũng nói rằng ngôn ngữ được nhận biết bởi máy Turing có một độ phức
tạp về thời gian nhiều nhất là T (n).

PGS. TS. PHAN HUY KHÂNH biên soạn 93


94 Lý thuyết tính toán

Tương tự, ta xét một máy Turing off-line đơn định có k băng và dừng với mọi dữ
liệu. Từ một cấu hình xuất phát (1, q1, f), máy này có một tính toán trên f và dừng.
Trong quá trình tính toán, máy Turing di chuyển các đầu đọc-ghi của nó, mỗi một đầu
đọc-ghi đến thăm một số ô phân biệt.
Bây giờ ta xét tập hợp Ln của tất cả các câu f có cùng một độ dài n. Với mỗi số
nguyên n, ta cho kết hợp với số nguyên :
S (n) = Maxf∈L
n
là số các ô đã được thăm trên các băng làm việc khi tính toán để nhận biết f .
Nếu Ln = ∅, ta đặt S (n) = 0
Hàm S : N → N vừa định nghĩa xác định độ phức tạp về bộ nhớ (space
complexity) S(n) của máy Turing 0ff-line k băng. Người ta nói rằng ngôn ngữ được
nhận biết bởi máy Turing có một độ phức tạp về bộ nhớ nhiều nhất là S(n).
Chú ý rằng khi xét độ phức tạp về bộ nhớ, người ta không xét không gian nhớ sử
dụng trên băng đọc : không gian nhớ này đúng bằng độ dài n của câu cần nhận biết.
Vì nếu không, người ta sẽ không thể nhận được hàm S(n).
Sau đây, ký hiệu I (x) là phần nguyên của x, ta viết :
T (n) = f (n) hàm T (n) được tăng lên max { n+1, I (f (n)) + 1 }
S (n) = f (n) hàm S (n) được tăng lên max { 1, I (f (n) + 1 }
Ví dụ 6.1 :
Cho L = { w wR | w∈ {0, 1}* và wR là câu đảo của w }
Tồn tại một máy Turing T1 có hai băng nhận biết ngôn ngữ L với chi phí về thời
gian là T(n) = n + 1. Máy này sao chép lên băng thứ hai các ký tự đã đọc trên băng
thứ nhất cho đến khi gặp ký tự rồi kiểm tra sự bằng nhau tương ứng của các ký tự
tiếp theo trên băng thứ nhất với các ký tự đã ghi trên băng thứ hai nhưng theo chiều
ngược lại.
Rõ ràng, thời gian tính toán đúng bằng độ dài của câu cộng thêm một thời gian
đọc ký tự # để kết thúc.
Tồn tại một máy Turing T2 có hai băng nhận biết ngôn ngữ L có chi phí về
bộ nhớ là S (n) = log2 (n). Máy này tính ghi theo hệ nhị phân trên băng thứ hai số các
ký tự đã đọc trên băng thứ nhất cho đến khi gặp ký tự C, sau đó kiểm tra số ký tự kế
tiếp ký tự này trên băng thứ nhất đúng bằng số ký tự vừa ghi trên băng thứ hai bằng
cách giảm dần từng ký tự.
Trường hợp thành công, máy kiểm tra từng đôi ký tự giống nhau cho tới một
khoảng cách i của ký tự # ở mỗi phía, và kiểm tra tất cả các giá trị i cần thiết. Các giá
trị này liên tiếp được ghi dưới dạng nhị phân trên băng thứ hai.
Rõ ràng, không gian nhớ sử dụng trên băng thứ hai được tăng thêm một lượng là
độ dài của câu dạng nhị phân, hay là logarit cơ số 2 của số nguyên này.
Độ phức tạp tính toán 95

Như vậy, đối với các máy Turing không đơn định, có thể định nghĩa theo cách
tương tự độ phức tạp tính toán không đơn định về thời gian và độ phức tạp tính toán
không đơn định về bộ nhớ. Chỉ cần định nghĩa các hàm T (n) và S (n), cho trường hợp
Ln ≠ ∅, như sau:
T (n) = Maxf∈L { độ dài của tính toán ngắn nhất để nhận biết f }
n
S (n) = Maxf∈L { số các ô đã được thăm trên băng khi tính toán
n
một cách tiết kiệm nhất để nhận biết f }
Rõ ràng, các định nghĩa đã đưa ra trong trường hợp các máy Turing đơn định chỉ
là trường hợp đặc biệt của các định nghĩa về tính chất không đơn định này.

II. Các lớp của độ phức tạp


(Complexity classes)
Trong mục trước, ta đã định nghĩa độ phức tạp của một ngôn ngữ cho trước.
Ngược lại, bây giờ ta có thể xem xét họ các ngôn ngữ có một độ phức tạp đã cho.
Giả sử f là một hàm tăng, ta có các định nghĩa sau :
Ký hiệu Ý nghĩa
DSPACE (f (n)) Họ các ngôn ngữ có độ phức tạp về bộ nhớ S (n) = f (n)
NSPACE (f (n)) Họ các ngôn ngữ có độ phức tạp không đơn định
về bộ nhớ S (n) = f (n)
DTIME (f (n)) Họ các ngôn ngữ có độ phức tạp về thời gian T (n) = f (n)
NTIME (f (n)) Họ các ngôn ngữ có độ phức tạp không đơn định
về thời gian T (n) = f (n)
Tất cả các họ trên được gọi là các lớp của độ phức tạp. Từ các định nghĩa trên, ta
suy ra rằng :
DSPACE (f (n)) ⊆ NSPACE (f (n))
DTIME (f (n)) ⊆ NTIME (f (n))
và, nếu f ≤ g, thì:
DSPACE (f (n)) ⊆ DSPACE (g (n))
NSPACE (f (n)) ⊆ NSPACE (g(n))
DTIME (f (n)) ⊆ DTIME (g (n))
NTIME (f (n)) ⊆ NTIME (g(n))
Giả sử L là ngôn ngữ được cho trong ví dụ 6. 1 trước đây, ta có:
L ∈ DTIME (n) ∩ DSPACE (log2 (n)),
nhưng ta cũng có :
L ∈ DTIME (n2) ∩ NTIME ( n) ∩ DSPACE (n)
96 Lý thuyết tính toán

II.1. Hiện tượng nén


Giả sử T là một máy Turing có độ phức tạp về bộ nhớ là S(n) = f(n), bằng cách sử
dụng một bảng chữ trong đó, mỗi ký tự biểu diễn k ký tự liên tiếp của bảng chữ của T,
ta có thể xây dựng một máy Turing T’ nhận biết cùng ngôn ngữ và có cùng độ phức
tạp về bộ nhớ là f(n)/k. Máy T’ này mã hóa trên bảng chữ mới thông tin ghi trên mỗi
một băng làm việc (nhớ rằng không kể không gian nhớ dùng để ghi dữ liệu vào).
Rõ ràng, nhờ phương pháp này, bằng cách sử dụng một thừa số c không đổi, ta có
thể giảm bớt độ phức tạp về bộ nhớ để nhận biết một ngôn ngữ đã cho.
Nếu T là một máy Turing off-line có k băng, ta có thể nhận biết cùng một ngôn
ngữ bằng cách sử dụng một máy Turing off−line chỉ có một băng, sử dụng cùng một
phương pháp để không sử dụng không gian nhớ nhiều hơn T. Đối với độ phức tạp về
bộ nhớ, việc ta giảm bớt số lượng băng làm việc không có nghĩa, cho nên, từ nay, ta
chỉ xét đến các máy Turing off−line có một băng, thậm chí, trong trường hợp S(n) =
n, ta chỉ xét các máy Turing có một băng mà không thêm gì nữa.
Ta cũng có thể áp dụng phương pháp nén vừa trình bày trên đây đối với độ phức
tạp về thời gian. Tuy nhiên phương pháp này không miễn đọc dữ liệu, mà cần một
thời gian n + 1 để đọc dữ liệu có độ dài n. Như vậy, ta có thể giảm bớt nhờ một thừa
số không đổi là c ngay khi T(n)/n có khuynh hướng tăng vô hạn.
Bây giờ ta xem xét hiệu quả của độ phức tạp về thời gian khi giảm bớt số lượng
các băng làm việc.
Khi giảm bớt còn một băng, phân tích phương pháp đã trình bày ở chương 3 để
chuyển từ k băng về một băng, ta chứng minh được :
L ∈ DTIME (T (n)) ⇒ L được thừa nhận bởi một máy Turing một băng
với chi phí thời gian là T2(n).
Khi cần thực hiện việc sao chéo, ta có thể chuyển từ một băng sang hai băng
nhằm làm giảm đáng kể số bước tính toán. Ta chứng minh được rằng việc rút gọn còn
hai băng thay vì chỉ còn một băng làm tối ưu rõ rệt chi phí về thời gian :
L ∈ DTIME (T (n)) ⇒ L được thừa nhận bởi một máy Turing có hai băng
với thời gian T (n).log2(T (n))
Tuy nhiên, để trả lời câu hỏi :
Với chi phí thời gian nhiều hơn (tương ứng : nhiều bộ nhớ hơn) thì người ta có
nhận biết được thực sự nhiều ngôn ngữ hơn không ?
ta có mệnh đề sau đây :
Mệnh đề 6.1 :
Với mọi hàm đệ quy toàn phần f, tồn tại một ngôn ngữ đệ quy L không thuộc họ
DTIME (f (n)) (một cách tương ứng : không thuộc họ DSPACE (f (n))).
Chứng minh :
Sử dụng kỹ thuật đường chéo cho ngôn ngữ :
L = { wi | Ti không thừa nhận câu wi sau f (|wi|) bước tính toán }
Thật vậy, L là một ngôn ngữ đệ quy không thuộc họ DTIME (f (n)).
Độ phức tạp tính toán 97

Giữa các phép đo độ phức tạp tính toán khác nhau này, ta có thể thiết lập các mối
quan hệ. Một số quan hệ dễ dàng nhận được như sau :
L ∈ DTIME (f (n)) ⇒ L ∈ DSPACE (f (n))
Thật vậy, máy Turing thăm một ô tại mỗi bước tính toán. Trường hợp xấu nhất
xảy ra khi tất cả các ô đều khác nhau.
L ∈ DSPACE (f (n)) và f (n) = log2 (n) ⇒ L ∈ DTIME (cf (n))
Thật vậy, nếu f (n) = log2 (n), tồn tại một hằng c sao cho cf(n) là lớn hơn số các
cấu hình phân biệt có độ dài tối đa là f (n) của một máy Turing đã cho.
L ∈ NTIME (f (n)) ⇒ L ∈ DTIME (cf (n)).
Thật vậy, quan hệ này đến từ việc tăng thêm số cấu hình phân biệt đối với một dữ
liệu có độ dài n. Thời gian tăng thêm là cf (n).
Sau đây là một quan hệ được cho bởi định lý Savitch.
Định lý Savitch WJ :
L ∈ NSPACE (f (n)) và f (n) = log2 (n) ⇒ L ∈ DSPACE (f2 (n)).

II.2. Các họ P, NP và P−bộ nhớ (P−space)


Các lớp của độ phức tạp tính toán sau đây đủ quan trọng để có tên riêng :
P = U DTIME (ni),
i ≥1
NP = U NTIME (ni).
i ≥1
Như vậy :
P là lớp các ngôn ngữ được nhận biết bởi một máy Turing đơn định
cần một lượng thời gian bậc đa thức,
NP là lớp các ngôn ngữ được nhận biết bởi một máy Turing
không đơn định cần một lượng thời gian bậc đa thức.
Ta đưa vào các lớp P−bộ nhớ (P−space) và NP−bộ nhớ (NP−space) như sau :
P−bộ nhớ = U DSPACE (ni),
i ≥1
NP−bộ nhớ = U NSPACE (ni).
i ≥1
P−bộ nhớ là lớp các ngôn ngữ được nhận biết bởi một máy Turing
đơn định cần một lượng bộ nhớ bậc đa thức,
NP−bộ nhớ là lớp các ngôn ngữ được nhận biết bởi một máy Turing
không đơn định cần một lượng bộ nhớ bậc đa thức.
Rõ ràng ta có đẳng thức :
98 Lý thuyết tính toán

P−bộ nhớ = NP−bộ nhớ


Và ta có các bao hàm sau đây :
DSPACE (log2 (n)) ⊆ P ⊆ NP ⊆ P−bộ nhớ = NP−bộ nhớ.
Trong thực tế, người ta ước lượng một bài toán là :
− xử lý được (tractable), nếu bài toán đó thuộc lớp P
hay giải được (workable)
− không xử lý được (untractable), nếu bài toán đó không thuộc lớp P.
hay không giải được (unworkable)
Vì vậy, ít khi người ta giải quyết những bài toán cần một lượng thời gian và bộ
nhớ dạng đa thức có bậc lớn hơn 4 vì sẽ làm tăng độ phức tạp tính toán.

III. Rút gọn đa thức và các bài toán NP−đầy đủ


III.1. Khái niệm
Rút gọn đa thức (polynomial reduction) là làm mịn (refinement) khái niệm rút gọn
số học đã định nghĩa ở chương 5. Ta vẽ lại sơ đồ rút gọn số học như sau :

Anh của f từ các


Biểu diễn dữ biểu diễn dữ liệu của
liệu của bài LP f LP
A B
bài toán A
toán A
f
S*\LP S*\LP Biểu diễn dữ liệu
B
A của bài toán B

Hình 6.1 Rút gọn bài toán A về bài toán B


Định nghĩa 6.1
Người ta nói bài toán A được rút gọn kiểu đa thức về bài toán B nếu tồn tại một
máy Turing dừng cho mọi dữ liệu và thực hiện tính hàm f hết một lượng thời gian đa
thức (polynomial time). Hàm f được xác định từ tập hợp các biểu diễn dữ liệu của
bài toán A vào tập hợp các biểu diễn dữ liệu của bài toán B, thỏa mãn :
w ∈ LA ⇔ f (w) ∈ LB
Người ta nói rằng máy Turing này đã thực hiện kiểu đa thức (polynomially work)
việc rút gọn bài toán A về bài toán B. Từ đó, ta có mệnh đề sau :
Mệnh đề 6.2 :
Nếu bài toán A được rút gọn kiểu đa thức về bài toán B, thì nếu B là một bài toán
thuộc lớp P (một cách tương ứng : thuộc lớp NP), thì A cũng là một bài toán thuộc
lớp P (một cách tương ứng : thuộc NP).
Người ta cũng nói rằng các lớp P và NP là đóng đối với phép rút gọn đa thức.
Độ phức tạp tính toán 99

Chứng minh :
Thật vậy, giả sử T là một máy Turing luôn luôn dừng và nhận biết ngôn ngữ LB
một lượng thời gian đa thức. Giả sử T’ là một máy Turing thực hiện việc rút gọn hết
một lượng thời gian đa thức từ bài toán A về bài toán B. Rõ ràng, máy Turing T’ next
T luôn luôn dừng và nhận biết ngôn ngữ LA một lượng thời gian đa thức.
Một cách tương tự, ta định nghĩa khái niệm rút gọn sử dụng bộ nhớ logarit.
Định nghĩa 6.2 :
Người ta nói bài toán A được rút gọn về bài toán B cần một lượng bộ nhớ logarit
nếu tồn tại một máy Turing luôn luôn dừng cho mọi dữ liệu và thực hiện tính hàm f
sử dụng một lượng bộ nhớ theo logarit. Hàm f được xác định từ tập hợp các biểu
diễn dữ liệu của bài toán A vào tập hợp các biểu diễn dữ liệu của bài toán B, thỏa
mãn :
w ∈ LA ⇔ f (w) ∈ LB
Ta có mệnh đề sau :
Mệnh đề 6.3 :
Lớp P đóng đối với phép rút gọn sử dụng bộ nhớ logarit.
Việc chuyển một chương trình RAM thành một chương trình của một máy Turing
được thực hiện sao cho thời gian chạy của máy Turing được tính theo số bước tính
toán, là một đa thức theo thời gian chạy chương trình của máy RAM được tính theo
số các lệnh (instructions) đã thực hiện.
Tương tự, việc chuyển một công thức trong một ngôn ngữ bậc cao thành một công
thức của một máy RAM được thực hiện sao cho thời gian chạy công thức của máy
RAM được tính theo số các lệnh của RAM đã thực hiện, là một đa thức về thời gian
chạy công thức trên ngôn ngữ bậc cao, được tính theo số các lệnh đã thực hiện.
Từ đó, việc định nghĩa các lớp P và NP được dựa trên mô hình các máy Turing
nhưng không phụ thuộc chính xác vào mô hình này, và để đảm bảo rằng một ngôn
ngữ là thuộc một trong hai lớp này, chỉ cần đếm số lượng các phép toán một cách đơn
giản.

III.2. Các bài toán cổ điển


Sau đây là sáu bài toán cổ điển trong Tin học.
1. Bài toán tô màu các đỉnh của một đồ thị
Dữ liệu : Một đồ thị G = <S, V> và một số nguyên k.
Câu hỏi : Ta có thể tô mỗi đỉnh của đồ thị một màu sao cho cứ hai đỉnh của đồ thị
được nối với nhau bởi một cung thì không được tô cùng màu được chọn
trong số k màu ?
2. Bài toán lập kế hoạch làm việc
Dữ liệu : Cho n việc và một số nguyên k, mỗi việc được đặc trưng bởi bộ ba các
số nguyên (ti, di, pi), với ti, di, và pi lần lượt biểu diễn thời gian thực
hiện, thời gian kết thúc và hình phạt ứng với việc thứ i.
100 Lý thuyết tính toán

Câu hỏi : Có thể sắp xếp các việc sao cho tổng số các hình phạt là nhỏ hơn hoặc
bằng k ? Nói cách khác, với mọi hoán vị P của n số nguyên đầu tiên, ta
kết hợp một số nguyên :
⎧= ∑ ⎡ P ⎤ nãu
ú ∑ t p(r) > d p(j)
⎪ ⎣ p (j) ⎦
Pp = ⎨ j = 1, n r = 1, j
⎪= 0
⎩ nãú
u khäng
và người ta tìm một hoán vị P nếu hoán vị P tồn tại sao cho Pp = k.
3. Bài toán sắp xếp trong các thùng chứa
Dữ liệu : Cho số nguyên c (dung lượng của các thùng), n vật đặc trưng bởi các
kích thước s1, s2, ..., sn với 0 < si ≤ c và một số nguyên k.
Câu hỏi : Có thể đặt n vật vào nhiều nhất là k thùng chứa được không ?
4. Bài toán ba-lô (rucksack)
Dữ liệu : Cho một số nguyên c (kích thước ba-lô) và n vật có các kích thước lần
lượt s1, s2, ..., sn.
Câu hỏi : Có thể bỏ đầy hoàn toàn ba-lô bởi một số vật lấy từ n vật đã cho ?
5. Bài toán thỏa mãn các biểu thức boolean ở dạng chuẩn hội
Dữ liệu: Một biểu thức boolean ở dạng chuẩn hội.
Câu hỏi : Có thể gán giá trị nào đó cho các biến làm biểu thức thỏa mãn ?
6. Bài toán đường đi Hamilton
Dữ liệu: Một đồ thị G = < S, V>.
Câu hỏi : Tồn tại hay không một đường đi Hamilton (đi qua tất cả các đỉnh) trong
đồ thị đã cho ?

III.3. Ví dụ về rút gọn kiểu đa thức


Bây giờ ta xét một ví dụ : hãy rút gọn kiểu đa thức bài toán ba-lô về bài toán sắp
đặt các việc có hình phạt.
Giả sử I = (s1, s2, ..., sn; c) là một dữ liệu vào cho bài toán ba-lô.
- Nếu ∑ sj < c thì câu trả lời là không.
j = 1, n
Khi đó, ta xét bài toán sắp đặt các việc có hình phạt được định nghĩa bởi
ti = 2, di = pi = 1 và k = 0 với câu trả lời không.
- Nếu trái lại, ∑ sj ≥ c thì câu trả lời là thoả mãn.
j = 1, n
Ta xét bài toán sắp đặt các việc có hình phạt được định nghĩa bởi ti = pi = si và
di = c với ∀i = 1 .. n, và k = ∑ sj − c
j = 1, n
Bây giờ ta kiếm tra trường hợp cá biệt I của bài toán ba-lô có một lời giải nếu và
chỉ nếu bài toán sắp đặt các việc có hình phạt mà ta sẽ đưa về cũng có một lời giải :
Độ phức tạp tính toán 101

Nếu bài toán ba-lô có một lời giải, khi đó tồn tại một tập hợp con J thuộc khoảng
{ 1, ..., n } sao cho ∑j∈J sj = c. Ta chọn một hoán vị P sao cho tất cả các việc có chỉ
số trong J được chọn trước các việc khác.
Cả || J || việc này đều được làm xong trước ngày kết thúc của chúng, trong khi đó,
các việc khác được làm xong sau ngày kết thúc, từ đó sinh ra một hình phạt:
∑J = || J|| + 1, npP (J) = ∑J = || J|| + 1, n sP (J)
= ∑J = 1, n J ∈J
= ∑J = 1, n sJ - c = k
Như vậy, các việc được làm xong với một hình phạt nhỏ hơn hoặcbằng k, giả sử m
là số nguyên lớn nhất sao cho m việc đầu tiên được làm xong trước ngày kết thúc
chung của chúng là c. Như vậy, ta có: ∑J -- 1, m tP(J) ≤ c và hình phạt là : ∑J = m + 1, n
PP(J) ≤ k
Do ti = Pi = si, ta có
∑J - 1, m tP(J)z + ∑J - m + 1, n PP(J) = ∑J - 1,n sJ = c + k
Do đó, cả hai bất đẳng thức đều bằng nhau và các vật có chỉ số P(j) với
j = 1..m sẽ làm đầy ba-lô. Ta cần kiểm chứng rằng việc rút gọn là theo thời gian đa
thức, nghĩa là chỉ có một phép tính duy nhất là tính giá trị ∑J - 1, n sJ - c.
Rõ ràng phép tính này đòi hỏi một thời gian đa thức. Việc xây dựng bài toán sắp
đặt các việc có hình phạt sẽ là có thời gian hằng nếu số nguyên này âm, có thời gian
tuyến tính nếu số nguyên này dương.
Cho đến lúc này, ta chưa biết có bài toán nào trong sáu bài toán trên thuộc vào lớp
không P. Tuy nhiên, người ta dễ dàng chứng minh được rằng chúng đều thuộc lớp
NP.
Ví dụ 6. 2
Bài toán tô màu các đỉnh của một đồ thị là thuộc lớp NP.
Thật vậy, máy Turing không đơn định sau đây nhận biết ngôn ngữ kết hợp với bài
toán này về thời gian tuyến tính (và do vậy, là đa thức) : trong thời gian đầu, máy
Turing thực hiện tô cho mỗi đỉnh, một cách không đơn định, một màu nào đó trong số
k màu.
Sau đó, máy Turing kiểm tra việc tô màu này đã thỏa mãn chưa, nghĩa là kiểm tra
tại các mút của các cung xem các đỉnh có cùng một tô một màu không ?.
Bây giờ ta chứng minh rằng thực tế tất cả sáu bài toán trên đều có thể rút gọn kiểu
đa thức từ bài toán kia. Từ đó, cả sáu bài toán đều thuộc lớp P nếu và chỉ nếu một
trong chúng thuộc P. Ta có định nghĩa sau đây :
Định nghĩa 6.3
Một bài toán là NP-cứng (NP - Comlete) nếu nó ở trong lớp NP.
Rõ ràng, định nghĩa trên có ích vì tồn tại những bài toán NP-đầy đủ như vậy.
102 Lý thuyết tính toán

Định ký Cook - 1971 (Stephen Cook) :


Bài toán về tính thỏa mãn của các biểu thức boolean dưới dạng chuẩn hội là một
bài toán NP -đầy đủ.
Ta không chứng minh định lý này.
Bổ đề 6. 1
Cả sáu bài toán trên đây đều là NP-đầy đủ.
Ta có mệnh đề sau:
Mệnh đề 6. 4
P = NP nếu và chỉ nếu tồn tại ngôn ngữ L ∈ P sao cho L là NP-đầy đủ.

Bài tập
1. Xét ngôn ngữ L = { wcw’ | w ∈ { a, b }* và w ≠ w’ }
Chứng minh rằng L ∈ NTIME (n) ∩ DSPACE (log2 (n)).
2. Chứng minh rằng cả sáu bài toán đã nêu đều có thể rút gọn kiểu đa thức từ bài
toán này về bài toán kia.
3. Một đồ thị được gọi là đầy đủ nếu có hai đỉnh bất kỳ được nối với nhau bới một
cạnh. Đồ thị được gọi là k-đầy đủ nếu tồn tại một đồ thị con có k đỉnh là đầy đủ.
Bài toán đầy đủ k-đầy đủ như sau:
Dữ liệu : Một đồ thị G và một số nguyên k
Câu hỏi : G có phải là k-đầy đủ?
Chứng minh rằng bài toán đồ thị k-đầy đủ là bài toán NP đầy đủ.
4. Những bài toán sau đây thuộc lớp NP, thuộc lớp P, thuộc lớp NP-bộ nhớ ?
Bài toán nào là NP-đầy đủ ?
a) Dữ liệu : Một câu w biểu diễn một biểu thức Boolean.
Câu hỏi : Câu w có phải là một hằng đúng (tautology) không ?
b) Dữ liệu : Một máy Turing T trên bảng chữ { a, b }.
Câu hỏi : Có tồn tại không một câu w ∈ S* có độ dài n sao cho máy Turing
T nhận biết w hết một lượng thời gian nhỏ hơn boặc bằng n ?
c) Dữ liệu : Một máy Turing trên bảng chữ { a, b }.
Câu hỏi : Tồn tại hay không một câu có độ dài n sao cho T nhận biết
câu này về bộ nhớ nhỏ hơn hoặc bằng n ?
d) Dữ liệu : Một cặp đồ thị (G, G’).
Câu hỏi : Đồ thị G’ có đẳng cấu (isomorphic) với một đồ thị con của G hay
không ?

You might also like