Thư viện bài tháng 04 năm 2005

Một thống kê thú vị

Ngô Quang Hưng | 26 tháng 04, 2005 | Bản để in Bản để in

Giới bảo thủ (conservatives) ở Mỹ càm ràm rằng khuôn viên đại học của Mỹ có thành kiến với dân bảo thủ. Một bài thống kê gần đây đưa ra con số thú vị: đa số giáo sư ở các trường đại học lớn có khuynh hướng ngả về cánh trái. Những người ngả về cánh phải thường không có record nghiên cứu khoa học tốt bằng. Điều này đúng cho tất cả các ngành học, từ khoa học tự nhiên đến khoa học xã hội, chính trị học, văn học, vân vân.

Cái nào là con gà, cái nào là quả trứng?

Chủ đề: Giáo dục | Bình luận »

Các cú chơi khăm trong giới hàn lâm

Ngô Quang Hưng | 22 tháng 04, 2005 | Bản để in Bản để in

Sau vụ chơi khăm SCI, vụ Sokal, tôi tình cờ tìm thấy một vụ khác hay không kém: affair của anh em Bogdanoff. Nếu các bạn tìm được vụ nào khác thì cho tôi biết. Ta có thể làm một bộ sưu tập.

Chủ đề: Giáo dục & Nhân vật và sự kiện | Bình luận »

Tiến hóa của tinh thần

Ngô Quang Hưng | 20 tháng 04, 2005 | Bản để in Bản để in

Tối qua tôi xem một chương trình của PBS với tựa đề beyond human. Chương trình nói về robotics và các công nghệ hiện tại, tương lai, xung quanh ngành robotics. Có vài câu hỏi cực kỳ thú vị:

  1. Giả sử một ngày kia ta làm được robots thông minh hơn người, có tình cảm như người, lại có thể tự tái sinh được. Bạn cảm thấy thế nào nếu loài người tuyệt chủng, chỉ còn các robots này đại diện và cưu mang tinh thần của nhân loại đi khắp vũ trụ?
    [Con người với cấu trúc sinh học như hiện nay sẽ không đi nổi hành trình đó, trừ khi ta tìm được đường tắt qua không-thời gian (lỗ sâu, lỗ đen, vân vân)].
  2. Bạn cảm thấy thế nào nếu chính bọn robots này làm loài người tuyệt chủng?
    [Chúng ta lã làm cho nhiều chủng loài khác tuyệt chủng. Khi đến lượt mình, chúng ta có chịu ra đi và chấp nhận tương lai này không? Nhất là khi tinh thần, trí tuệ của nhận loại vẫn còn sống?]

Nếu điều này xảy ra, thì tiến hóa sẽ chuyển sang dạng mới: tiến hóa của tinh thần! Sẽ có sự tách biệt giữa tinh thần và thể xác không theo ý nghĩa tôn giáo. Khi đó nhân loại có thể xem là đã “xuất hồn” nhập vào xác khác!

Chủ đề: KHMT và sinh học & Trí tuệ nhân tạo | Bình luận »

Thêm nguồn về xuất bản hàn lâm

Ngô Quang Hưng | 20 tháng 04, 2005 | Bản để in Bản để in

Thêm một tham khảo tốt liên quan đến các bài đã viết (một, hai, ba) về xuất bản hàn lâm.

Chủ đề: Xuất bản | Bình luận »

Chuyện khó tin

Ngô Quang Hưng | 18 tháng 04, 2005 | Bản để in Bản để in

Vài chục năm trước, có anh chàng giết người vì paper không được nhận báo cáo trong một hội nghị.

Chủ đề: Nhân vật và sự kiện | Bình luận »

Kỷ niệm ngày sinh của luật Moore

Ngô Quang Hưng | 18 tháng 04, 2005 | Bản để in Bản để in

Tháng 4 này có kỷ niệm 30 năm kể từ khi chiến tranh Việt Nam kết thúc (30/04/75), 40 năm ngày ra đời của luật Moore (19/04/1965), 50 năm ngày Einstein mất (18/04/1955). Cả McDonald cũng kỷ niệm 50 năm ngày thành lập vào thứ sáu tuần này.

Sự kiện nào có tầm ảnh hưởng lớn nhất đến nhân loại?

Luật Moore đại khái nói rằng tổng số transitors trong một con chip silicon sẽ được nhân đôi vài năm một lần. Luật này đầu tiên xuất hiện trong một bài báo của Moore (tạp chí Electronic, 19 tháng 4 năm 1965) và sau đó được nhà vật lý Carver Mead đặt tên là Moore’s Law. Luật Moore ban đầu chỉ là một dự đoán, nhưng đã dần biến thành mục tiêu của cả nền công nghệ phần cứng máy tính. Một loại self-fulfilling prophecy.

Gordon Moore là một trong các đồng sáng lập viên của tập đoàn Intel. Thật ra Moore nghe được dự đoán này từ một bài nói của khoa học gia máy tính Douglas C. Engelbart ở hội nghị quốc tế về mạch (International Circuit Conference) tháng 2 năm 1960. Engelbart lãnh đạo một nhóm các nhà nghiên cứu ở viện nghiên cứu Stanford sáng chế ra con chuột máy tính đầu tiên.

Tờ New York Times hôm nay có một bài xung quanh nguồn gốc và ảnh hưởng của luật Moore.

Chủ đề: Nhân vật và sự kiện | Bình luận »

Tầm quan trong của toán học

Ngô Quang Hưng | 16 tháng 04, 2005 | Bản để in Bản để in

Giáo sư Tim Gowers (giải thưởng Fields năm 1998) của đại học Cambridge có một bài nói rất hay về tầm quan trọng của toán học. Rất nhiều ý trong bài này áp dụng cả cho các khoa học khác, bao gồm khoa học máy tính.
Có vài quyển sách liên quan đến đề tài của bài nói này: “Toán học là gì?“, “Toán học: một giới thiệu cực ngắn“, và “Sự hiệu quả đến mức vô lý của Toán học trong các khoa học tự nhiên“.
Giáo sư Gowers viết khá nhiều các bài giới thiệu về nhiều đề tài khác nhau trong Toán.

Chủ đề: Dành cho du học sinh & Nghiên cứu nghiên kiếc | Bình luận »

Vai trò của conference papers trong khoa học máy tính

Nguyễn Xuân Long | 13 tháng 04, 2005 | Bản để in Bản để in

Vì nhiều lí do lịch sử và bản chất ngành, những xuất bản trong các hội nghị (dưới dạng conference proceedings) trong ngành khoa học máy tính (KHMT) thường được xem có sức nặng tương đương một xuất bản trong một tạp chí. Ví dụ, theo tôi biết thì khoa máy tính đại học Washington , một trong những khoa về CS hàng đầu ở Mỹ, đánh giá một bài báo ở hội nghị AAAI tương đương với tạp chí Journal of Artificial Intelligence Research trong việc xem xét tenure của một giáo sư trong khoa.

Trên thực tế có nhiều công trình của KHMT có tính đột phá được xuất bản đầu tiên dưới dạng một conference proceeding. Mặc dù vậy, có những khác biệt căn bản giữa việc xuất bản trên một tạp chí định kỳ, và việc xuất bản trong một conference proceeding. Sự khác biệt lớn nhất là, vì những lý do hạn chế về mặt thời gian, những bài báo ở hội nghị thường không được đánh giá (review) một cách cẩn thận; vì lý do hạn chế về độ dài bài báo (thường là 6 đến 8 hoặc 10 hoặc 12 trang), nhiều chi tiết quan trọng trong kết quả trình bày thường bị bỏ qua mà vẫn được châm chước. Dẫn đến, nhiều claims trong bài báo có thể bị thổi phồng mà không ai có thể kiểm chứng được.

Điều này có thể dẫn đến hậu quả tai hại đối với một vấn đề nghiên cứu cụ thể nói riêng, cũng như thái độ nghiên cứu nói chung trong KHMT, dễ bị mắc phải cả với những người nghiên cứu lâu năm cũng như những học sinh sinh viên cao học trẻ tuổi: Một công trình nghiên cứu có triển vọng nhưng được thực hiện và trình bày một cách hời hợt vẫn có thể được xuất bản ở những hội nghị có uy tín, và được coi như một xuất bản ở một tạp chí đầu ngành.

Lấy một ví dụ về ngành machine learning , một lĩnh vực mang đậm tính liên ngành (liên quan đến thống kê (statistics), thuật toán (algorithms), lý thuyết thông tin (information theory)), và có ứng dụng rộng khắp trong các vấn đề xử lý dữ liệu (data analysis) trong các ngành khoa học ứng dụng. Một trong những hội nghị có uy tín nhất của ML là NIPS . Để được chấp nhận vào hội nghị này không dễ. Quả thực có khá nhiều ý tưởng, phát hiện có tính đột phá được trình bày từ đây, như sự giới thiệu của thuật toán support vector machines , statistical inference algorithms in graphs, v.v. Mặc dù vậy, rất nhiều bài báo ở NIPS cũng rất tầm thường về nội dung, và người ta quên đi chúng rất nhanh sau khi được xuất bản. Một trong những lý do là format của bài báo chỉ có 6 trang nhỏ (một cột), không đủ để trình bày tỉ mỉ những chi tiết quan trọng về thuật toán, chứng minh, cũng như kết quả thực nghiệm. Những người ở trong ngành đủ lâu đều biết là có những “magic formula” để có thể làm một bài báo được xuất bản ở những hội nghị (kể cả là có uy tín nhất) như thế.

Dầu sao thì NIPS cũng là một hội nghị có uy tín, và được nhiều người đầu ngành đến tham dự, cũng như nhiều sinh viên trẻ đến dự. Nó cũng là một trong những hội nghị thú vị nhất mà tôi hay đến dự. Nhưng sự coi trọng có phần thái quá của giới nghiên cứu ngành KHMT dẫn đến một sự thực là càng ngày càng có nhiều hội nghị vô cùng vớ vẩn về chất lượng. Một chuyện nực cười nhất là vừa qua, một nhóm học sinh KHMT ở MIT đã viết một chương trình tự động có thể viết ra những “research papers” , và ít nhất một bài báo của họ đã được nhận tại một hội nghị với một cái tên rất kêu 9th World Multi-Conference on Systemics, Cybernetics and Informatics . Hội nghị này được tổ chức năm thứ 9, và có đến 2904 bài báo chấp nhận năm naỵ Đây là một trong rất nhiều hội nghị liên quan đến ngành máy tính, được tổ chức bởi một nhóm người đứng ra để thu lời từ tiền registration fee, và được sự ủng hộ của những người mong muốn cải thiện publication records của mình bằng mọi cách.

Có nhiều điều có thể rút ra về câu chuyện này. Có lẽ cần phải có sự điều chỉnh về quan niệm xuất bản ở hội nghị và các tạp chí. Việc đánh giá khả năng bằng số lượng bài báo thay vì chất lượng, sự coi trọng thái quá đối với xuất bản ở hội nghị, đang góp phần dẫn đến sự thờ ơ của nhiều người trong việc tìm cách xuất bản những kết quả nghiên cứu trọn vẹn của mình tới những tạp chí đầu ngành.

Những công trình có giá trị nhất phải là những công trình sẽ giữ được giá trị của nó với thời gian, và do đó, cần phải được thẩm định và xuất bản ở các tạp chí có uy tín. Hạn chế lớn nhất đối với việc xuất bản ở một tạp chí là, thời gian từ lúc nộp bài đến lúc được xuất bản trên một tạp chí có thể rất lâu. Ví dụ với một số tạp chí mà giới làm về machine learning, thống kê hay xử lý dữ liệu hay tham khảo, như
the Annals of Statistics , hay IEEE Transactions on Information Theory có thể mất đến 2 năm. Trong khi đó, với các hội nghị, thời gian đó chỉ khoảng 6 tháng. Hiện tại, các tạp chí điện tử (on-line journals) đang được hình thành để rút ngắn khoảng thời gian turn-around đó.

Chủ đề: Chính trị trong ngành & Các hội nghị KHMT | Bình luận (3) »

Chương trình xấu, đẹp, ướt át, khô khan, tồi, tốt

Ngô Quang Hưng | 13 tháng 04, 2005 | Bản để in Bản để in

Khi dạy lớp mạng máy tính, tôi cho sinh viên viết chương trình trên mạng. Dù nội dung chính của lớp là mạng máy tính, tôi vẫn đặt tiêu chuẩn cao trong kỹ năng lập trình và cách trình bày chương trình. Tôi rất thích một đoạn trong quyển sách “cấu trúc và biên dịch các chương trình máy tính” của các giáo sư Harold Belson và Gerald Jay Sussman:

  • Ngôn ngữ máy tính không chỉ dùng để bảo máy tính làm các tác vụ này khác. Ngôn ngữ máy tính còn là phương tiện truyền tải các ý tưởng về mặt phương pháp. Vì thế, các chương trình máy tính phải được viết để cho người đọc; việc máy tính hiểu và chạy một chương trình chỉ là mục tiêu phụ.

Đây là một trong những quyển sách về máy tính hay nhất mà tôi biết (dù là nó được viết trong ngữ cảnh của ngôn ngữ Scheme). Cá nhân tôi rất ghét các chương trình viết cẩu thả. Vì thế, tôi thường cho sinh viên các ví dụ về các chương trình loại này. Sau đây là ví dụ của một chương trình tồi và chương trình tốt.

Để cho lớp học thêm sinh động, tôi cho cả các ví dụ các chương trình ướt át, khô khan, đẹp, và xấu. Đoạn chương trình xấu là đoạn đáng chú ý. Nó là một ví dụ của một chương trình C được cố ý làm cho rối rắm lên (obfuscated C code). Có cả một cuộc thi quốc tế hàng năm cho các chương trình loại này. Lần tới ta sẽ bàn thêm về chúng.

Chủ đề: Giáo dục & Vui - Giải Trí | Bình luận (3) »

Chương trình tự tái sinh

Ngô Quang Hưng | 10 tháng 04, 2005 | Bản để in Bản để in

Một trong các bài tập rất hay cho người đang học lập trình (bất kể ngôn ngữ nào) là: hãy viết một chương trình in chính nó ra. Chú ý là phải in ra giống hệt, từng giòng từng chữ từng cái xuống hàng. Ở đây ta giả sử có thể viết chương trình bằng một tệp (file) thôi.

Nếu bạn chưa bao giờ nghĩ về các chương trình kiểu này, hãy dành vài chục phút nghĩ trước khi đọc các ví dụ dưới đây. Bạn sẽ thấy bài tập này liên quan mật thiết đến khái niệm “tự tham chiếu”, một trong những khái niệm trung tâm trong bài Chung qui chỉ tại Cantor.

Thử xét vài ví dụ sau:

  • C/C++:
main(){char *c="main(){char *c=%c%s%c;printf(c,34,c,34);}";printf(c,34,c,34);}
  • Java:
  import java.text.*;class a{public static void main(String x[]){char b[]={34};
  char c[]={123};String s[]=new String[3];s[0]=”import java.text.*;class a{2}
  public static void main(String x[]){2}char b[]={2}34};char c[]={2}123};
  String s[]=new String[3];s[0]={1}{0}{1};s[1]=new String(b);s[2]=new String(c);
  System.out.println(MessageFormat.format(s[0],s));}}”;s[1]=new String(b);s[2]=
  new String(c);System.out.println(MessageFormat.format(s[0],s));}}
  • Common Lisp:
((lambda (x)
(list x (list (quote quote) x)))
(quote
(lambda (x)
(list x (list (quote quote) x)))))
  • Perl:
#!/usr/bin/perl
$_=<<'eof';eval $_; print “#!/usr/bin/perln$_=<<’eof’;eval $_;n${_}eofn”
eof

Các ví dụ trên tôi lấy ở đây, và ở đây. Dưới đây ta sẽ thiết kế một ví dụ cho riêng ta, không cần đi “chôm” về. Các trương trình tự in bản thân còn được gọi là Quine, họ của triết gia Willard van Orman Quine. Có hai câu hỏi liên quan:

  1. Có nguyên tắc gì để viết các chương trình lọai này không? Cho một ngôn ngữ mới thì làm thế nào ta viết được một chương trình như vậy?
  2. Các chương trình lọai này có ứng dụng gì không?

Trước hết, ta bàn về nguyên tắc viết các chương trình tự in được bản thân. Ta sẽ làm việc trên một mô hình tổng quát (nhưng hoàn có thể hiện thực được với bất kỳ ngôn ngữ máy tính nào). Giả sử trong mô hình máy tính này có một vùng nhớ mà tất cả các chương trình đều lấy input từ đó và ghi ra đó được. Có hai quan sát nhỏ:

  1. Cho một chuỗi x bất kỳ, ví dụ x = “học như nghịch thủy hành châu”, gọi P(x) là chương trình ghi x vào vùng nhớ chung. Có thể có nhiều P(x) khác nhau, ta cứ thống nhất một loại P(x) duy nhất. Bạn có thể nghĩ đến phát biểu
strcpy(buffer, "Học như nghịch thủy hành châu");

trong ngôn ngữ C chẳng hạn.

  1. Cho một chuỗi x bất kỳ trong vùng nhớ, ta có thể dễ dàng viết một đoạn chương trình sẽ ghi P(x) vào vùng nhớ.

Ý tưởng của chương trình tự in bản thân (vào vùng nhớ chung) như sau: chương trình này có hai đoạn, đoạn A và đoạn B, nghĩa là nối A với B thì ta có toàn bộ chương trình.

Đoạn B làm công việc như sau:

  1. x = chuỗi các bytes trong vùng nhớ
  2. Ghi P(x) vào vùng nhớ
  3. Ghi x vào vùng nhớ

Chú ý rằng, sau khi B hoạt động xong thì trong vùng nhớ chung chứa P(x) rồi đến x. Bạn nên tưởng tưởng viết một đoạn chương trình như B trong ngôn ngữ bạn thích.

Đoạn chương trình A thì làm gì? Nó sẽ ghi x vào vùng nhớ cho B đọc và ghi P(x), x. Thế A ghi gì? A ghi ra chính đoạn B ở trên!!!

Vì A ghi B vào vùng nhớ, A = P(B), và x = B. Còn B ghi ra “P(x)x” = “P(B)B” = “AB”, chính là chương trình ta đang viết.

Ta thử dùng nguyên tắc mô tả trong ví dụ trước để viết một chương trình C tự in bản thân. Lần thử đầu tiên, chương trình A ghi x vào biến buffer, chương trình B in ra đoạn chương trình P(x), sau đó in x. Kết quả đại khái như sau:

int main() {
 char* buffer = "printf(\"int main() {\\n char* buffer = %s;\\n %s\\n}\\n\", buffer, buffer);";
 printf("int main() {\n char* buffer = \"%s\";\n %s\n}", buffer, buffer);
}

Lần thử này không thành công lắm, dù chương trình này in ra một chương trình gần giống nó. Vấn đề nằm ở cả đống ký tự thoát (escape characters ‘\’). Nó in thế này:

int main() {
 char* buffer = "printf("int main() {\n char* buffer = %s;\n %s\n}\n", buffer, buffer);";
 printf("int main() {\n char* buffer = %s;\n %s\n}\n", buffer, buffer);
}

Rút kinh nghiệm, tôi tránh các escape characters và thay chúng bằng mã ASCII. Mã ASCII của ký tự xuống dòng (linefeed) là 10, và của ký tự ngoặc kép (”) là 34. Kết quả lần thử thứ hai cho đoạn chương trình:

int main() {
 char* buffer = "printf(\"int main() {%c char* buffer = %c%s%c;%c %s%c}\", 10, 10, 34, buffer, 34, 10, buffer, 10);";
 printf("int main() {%c char* buffer = %c%s%c;%c %s%c}", 10, 34, buffer, 34, 10, buffer, 10);
}

Chương trình này in ra

int main() {
 char* buffer = "printf("int main() {%c char* buffer = %c%s%c;%c %s%c}", 10, 10, 34, buffer, 34, 10, buffer, 10);";
 printf("int main() {%c char* buffer = %c%s%c;%c %s%c}", 10, 10, 34, buffer, 34, 10, buffer, 10);
}

Giống lắm rồi. Nhưng vẫn bị một escape character \ cho dấu ” của printf. Lý do là vì cả printf lẫn định nghĩa buffer đều dùng “, mà nếu bỏ ” vào trong định nghĩa buffer thì phải escape nó. Nhưng ta hoàn toàn có thể printf mà không dùng ” như sau:

int main() {  char* buf1 = "char buf2[] = {’i', ‘n’, ‘t’, ‘ ‘, ‘m’, ‘a’, ‘i’, ‘n’, ‘(’, ‘)’, ‘ ‘, ‘{’, ‘%’, ‘c’, ‘ ‘, ‘c’, ‘h’, ‘a’, ‘r’, ‘*’, ‘ ‘, ‘b’, ‘u’, ‘f’, ‘1′, ‘ ‘, ‘=’, ‘ ‘, ‘%’, ‘c’, ‘%’, ’s’, ‘%’, ‘c’, ‘;’, ‘%’, ‘c’, ‘ ‘, ‘%’, ’s’, ‘%’, ‘c’, ‘}’, (char) 0}; printf(buf2, 10, 34, buf1, 34, 10, buf1, 10);”;
char buf2[] = {’i', ‘n’, ‘t’, ‘ ‘, ‘m’, ‘a’, ‘i’, ‘n’, ‘(’, ‘)’, ‘ ‘, ‘{’, ‘%’, ‘c’, ‘ ‘, ‘c’, ‘h’, ‘a’, ‘r’, ‘*’, ‘ ‘, ‘b’, ‘u’, ‘f’, ‘1′, ‘ ‘, ‘=’, ‘ ‘, ‘%’, ‘c’, ‘%’, ’s’, ‘%’, ‘c’, ‘;’, ‘%’, ‘c’, ‘ ‘, ‘%’, ’s’, ‘%’, ‘c’, ‘}’, (char) 0}; printf(buf2, 10, 34, buf1, 34, 10, buf1, 10);
}

Bạn có thể dịch và chạy thử đoạn trên, in ra chương trình y hệt.

Chương trình tự tái sinh có nhiều ứng dụng thú vị. “In bản thân” chỉ là một ví dụ của sự tái sinh.

Các virus máy tính đều có chức năng tái sinh “y chang” này, nhưng thay vì in ra stdout, chúng tự copy bản thân qua một địa chỉ mới (trong bộ nhớ, qua mạng, hay xuống đĩa cứng). Trong bài tiến hóa số tôi có đề cập đến các chương trình máy tính tự tái sinh dùng để mô phỏng tiến hóa của các loại “vi khuẩn số” đơn giản.

Trong tương lai, bạn có thể tưởng tượng các chương trình phức tạp hơn, hay các robots tự tái sinh. Hy vọng đến đây bạn đã được thuyết phục rằng sự tự tái sinh không phải là thứ vô vọng về mặt triết học.

Trong các ví dụ trước, ta chỉ thiết kế các chương trình có chức năng duy nhất là in ra bản thân. Còn bọn “vi khuẩn số” hay viruses còn làm các việc khác nữa. Chuyện này không có gì khó. Giả sử ta có chương trình T làm việc gì đó (phá đĩa cứng chẳng hạn), ta có thể thiết kế chương trình ABT bao gồm đoạn A = P(x), đoạn B giống như trước, và đoạn T. Thay vì A ghi x = B vào vùng nhớ, thì trong trường hợp này A sẽ ghi x = BT, còn B thì in P(x)x như cũ. Như vậy ta đã bổ túc cho chương trình T chức năng tự tái sinh mà không cần suy nghĩ gì nhiều.

Cái mô hình máy có bộ vi xử lý truy cập một vùng nhớ chung của ta chính là mô hình máy Turing. Lần tới ta sẽ dùng ý tưởng về sự tự tái sinh này để chứng minh rằng có bài toán không quyết định được bằng máy Turing (xem thêm chung qui chỉ tại Cantor). Như đã nói trong bài “chung qui chỉ tại Cantor”, khái niệm tự tham chiếu là một khái niệm then chốt. Vì thế, cũng không ngạc nhiên lắm khi sự tự tái sinh có liên quan đến vấn đề không quyết định được.

Bài tập 1: viết một chương trình C chép file X sang file Y, sau đó tự in bản thân nó (C) ra stdout.

Để minh họa khái niệm tự in và tự tham chiếu một lần nữa, hãy xét ví dụ sau (tôi lấy ở đây):

  • This sentence has three a’s, two c’s, two d’s, twenty-eight e’s, four f’s, four g’s, ten h’s, eight i’s, two l’s, eleven n’s, six o’s, seven r’s, twenty-seven s’s, eighteen t’s, three u’s, five v’s, six w’s, three x’s, and three y’s.

Bài tập 2: viết một chương trình C tìm một câu tiếng Việt có nội dung tương tự.

Bài tập 3: có phải tất cả các ngôn ngữ đều có một câu dạng này hay không? Ngôn ngữ với tính chất gì thì có một câu như vậy?

Ta đã “chứng minh” rằng mọi chương trình có thể lấy được đoạn mã của chính nó. (Chứng minh điều này một cách chặt chẽ bằng toán học cũng không có gì khó khăn, tương tự như các ý tưởng ta đã trình bày, chỉ cần định nghĩa rõ ràng thế nào là một chương trình.) Phát biểu này thường được gọi là định lý đệ qui (recursion theorem).

Đến đây, ta minh họa một ứng dụng của định lý đệ qui. Ta sẽ dùng định lý này để chứng minh rằng bài toán dừng không quyết định được. Tôi sẽ thảo luận ý tưởng chính, bỏ qua các chi tiết toán không quan trọng. Bài toán dừng đại khái có thể phát biểu như sau: “cho một đoạn mã chương trình [M] và một chuỗi w, quyết định xem với input w thì M có dừng sau một số hữu hạn các bước hay không?” (Ta dùng [M] để chỉ đoạn mã của chương trình M.)

Định lý: không tồn tại chương trình nào giải bài toán dừng.

Chứng minh: giả sử có chương trình A giải bài toán dừng, ta thiết kế một chương trình M để làm phản chứng như sau

  1. Gọi input của Mw
  2. M tự lấy đoạn mã [M] của chính nó
  3. M chạy A với input là ([M], w).
  4. Nếu A trả lời là “dừng” thì M nhảy vào một vòng lặp vô tận.
  5. Nếu A trả lời là “không dừng thì M dừng.

Như vậy A không thể nào quyết định xem M có dừng hay không!

Chứng minh trên rất đặc trưng cho lập luận đường chéo của Cantor, thường được dùng cho các bài toán mà đối tượng có tính tự tham chiếu. Lý luận kiểu như trên là một trong những công cụ rất mạnh để chứng minh phản chứng trong lý thuyết tính toán.

Không biết các bạn thế nào chứ lúc đầu tôi thấy việc thiết kế chương trình tự in khá là phản trực quan. (Tưởng tượng một nhà máy sản xuất gỗ lại có thể sản xuất một nhà máy sản xuất gỗ y hệt như nó.) Thế mà câu trả lời không những là có các chương trình như vậy, mà còn có cả một nguyên tắc viết các chương trình đó.

Trong bài này, ta đã đi từ một câu hỏi tự tham chiếu này (chương trình tự in) sang câu hỏi tự tham chiếu khác (bài toán dừng). Ta dùng câu trả lời cho câu hỏi đầu để trả lời không cho câu hỏi thứ hai.

Chủ đề: Bảo mật và mật mã học & Lý thuyết tính toán | Bình luận »

Hai khách mới

Ngô Quang Hưng | 08 tháng 04, 2005 | Bản để in Bản để in

Mấy hôm nay tôi khá bận rộn tiếp khách của khoa (đi ăn, nói chuyện, xếp kế hoạch gặp gỡ, vân vân).

Đầu tiên là giáo sư Joe Mitchell của Stony Brook. Ông làm về hình học tính toán (computational geometry) và đã có các đóng góp đột phá trong ngành này. Kết quả nổi tiếng nhất của ông là một hệ xấp xỉ thời gian đa thức (polynomial time approximation scheme - PTAS) cho vấn đề người bán hàng trong không gian Euclid (Euclidean TSP). Kết quả này ra đời năm 1996, khi mà giáo sư Sanjeev Arora cũng xuất bản cùng kết quả. Bài nói của ông hôm qua giới thiệu rất nhiều các vấn đề về hình học tính toán chưa có lời giải.

Tôi giới thiệu cho Joe một vấn đề tôi đang làm: mô hình hóa hacking và tìm cách tốt nhất để hack vào một hệ thống trên mô hình này. Joe đặt góc nhìn hình học vào bài toán và thế là chúng tôi có bài toán mới khá thú vị:

  • Giả sử bạn muốn đi từ A đến B nhanh nhất. Địa hình thì có đồi núi, sông, cầu, phà, bè, cầu khỉ, đường cao tốc … mà bạn phải vượt qua. Rải rác trong khu địa hình lộn xộn này có nhiều dụng cụ và các loại xe cộ (xe đạp, xe ô tô, thuyền bè, mái chèo, quần áo leo núi, vân vân). Mỗi loại có một tốc độ nhất định trong một địa hình nhất định. Làm thế nào mà bạn đi từ A đến B nhanh nhất?
    [Chú ý: tôi đã chứng minh được là bài toán này không xấp xỉ được trong thời gian đa thức đến tỉ lệ xấp xỉ 2^{log^{1-d}(n)}, trong đó d tiến về 0 khi n tiến về vô cùng.]

Người kế tiếp là giáo sư Dave Farber, được mệnh danh là một trong những “ông đẻ” (grand farther) của Internet. Trong buổi ăn tối, Dave kể hết chuyện hài này đến giai thoại khác. Ông sẽ trình bày chiều nay.

Chủ đề: Nhân vật và sự kiện | Bình luận »

Chương trình tự tái sinh (4)

Ngô Quang Hưng | 06 tháng 04, 2005 | Bản để in Bản để in

Chương trình tự tái sinh có nhiều ứng dụng thú vị. “In bản thân” chỉ là một ví dụ của sự tái sinh.

Các virus máy tính đều có chức năng tái sinh “y chang” này, nhưng thay vì in ra stdout, chúng tự copy bản thân qua một địa chỉ mới (trong bộ nhớ, qua mạng, hay xuống đĩa cứng). Trong bài tiến hóa số tôi có đề cập đến các chương trình máy tính tự tái sinh dùng để mô phỏng tiến hóa của các loại “vi khuẩn số” đơn giản.

Trong tương lai, bạn có thể tưởng tượng các chương trình phức tạp hơn, hay các robots tự tái sinh. Hy vọng đến đây bạn đã được thuyết phục rằng sự tự tái sinh không phải là thứ vô vọng về mặt triết học.

Trong các ví dụ trước, ta chỉ thiết kế các chương trình có chức năng duy nhất là in ra bản thân. Còn bọn “vi khuẩn số” hay viruses còn làm các việc khác nữa. Chuyện này không có gì khó. Giả sử ta có chương trình T làm việc gì đó (phá đĩa cứng chẳng hạn), ta có thể thiết kế chương trình ABT bao gồm đoạn A = P(x), đoạn B giống như trước, và đoạn T. Thay vì A ghi x = B vào vùng nhớ, thì trong trường hợp này A sẽ ghi x = BT, còn B thì in P(x)x như cũ. Như vậy ta đã bổ túc cho chương trình T chức năng tự tái sinh mà không cần suy nghĩ gì nhiều.

Cái mô hình máy có bộ vi xử lý truy cập một vùng nhớ chung của ta chính là mô hình máy Turing. Lần tới ta sẽ dùng ý tưởng về sự tự tái sinh này để chứng minh rằng có bài toán không quyết định được bằng máy Turing (xem thêm chung qui chỉ tại Cantor). Như đã nói trong bài “chung qui chỉ tại Cantor”, khái niệm tự tham chiếu là một khái niệm then chốt. Vì thế, cũng không ngạc nhiên lắm khi sự tự tái sinh có liên quan đến vấn đề không quyết định được.

Bài tập 1: viết một chương trình C chép file X sang file Y, sau đó tự in bản thân nó (C) ra stdout.

Để minh họa khái niệm tự in và tự tham chiếu một lần nữa, hãy xét ví dụ sau (tôi lấy ở đây):

  • This sentence has three a’s, two c’s, two d’s, twenty-eight e’s, four f’s, four g’s, ten h’s, eight i’s, two l’s, eleven n’s, six o’s, seven r’s, twenty-seven s’s, eighteen t’s, three u’s, five v’s, six w’s, three x’s, and three y’s.

Bài tập 2: viết một chương trình C tìm một câu tiếng Việt có nội dung tương tự.

Bài tập 3: có phải tất cả các ngôn ngữ đều có một câu dạng này hay không? Ngôn ngữ với tính chất gì thì có một câu như vậy?

Chủ đề: Bảo mật và mật mã học & Lý thuyết tính toán | Bình luận »

Chương trình tự tái sinh (3)

Ngô Quang Hưng | 02 tháng 04, 2005 | Bản để in Bản để in

Ta thử dùng nguyên tắc mô tả trong ví dụ trước để viết một chương trình C tự in bản thân. Lần thử đầu tiên, chương trình A ghi x vào biến buffer, chương trình B in ra đoạn chương trình P(x), sau đó in x. Kết quả đại khái như sau:

int main() {
char* buffer = “printf(”int main() {\n char* buffer = %s;\n %s\n}\n”, buffer, buffer);”;
printf(”int main() {\n char* buffer = “%s”;\n %s\n}”, buffer, buffer);
}

Lần thử này không thành công lắm, dù chương trình này in ra một chương trình gần giống nó. Vấn đề nằm ở cả đống ký tự thoát (escape characters ”). Nó in thế này:

int main() {
char* buffer = “printf(”int main() {\n char* buffer = %s;\n %s\n}\n”, buffer, buffer);”;
printf(”int main() {\n char* buffer = %s;\n %s\n}\n”, buffer, buffer);
}

Rút kinh nghiệm, tôi tránh các escape characters và thay chúng bằng mã ASCII. Mã ASCII của ký tự xuống dòng (linefeed) là 10, và của ký tự ngoặc kép (”) là 34. Kết quả lần thử thứ hai cho đoạn chương trình:

int main() {
char* buffer = “printf(”int main() {%c char* buffer = %c%s%c;%c %s%c}”, 10, 10, 34, buffer, 34, 10, buffer, 10);”;
printf(”int main() {%c char* buffer = %c%s%c;%c %s%c}”, 10, 34, buffer, 34, 10, buffer, 10);
}

Chương trình này in ra

int main() {
char* buffer = “printf(”int main() {%c char* buffer = %c%s%c;%c %s%c}”, 10, 10, 34, buffer, 34, 10, buffer, 10);”;
printf(”int main() {%c char* buffer = %c%s%c;%c %s%c}”, 10, 10, 34, buffer, 34, 10, buffer, 10);
}

Giống lắm rồi. Nhưng vẫn bị một escape character \ cho dấu ” của printf. Lý do là vì cả printf lẫn định nghĩa buffer đều dùng “, mà nếu bỏ ” vào trong định nghĩa buffer thì phải escape nó. Nhưng ta hoàn toàn có thể printf mà không dùng ” như sau:

int main() {
char* buf1 = “char buf2[] = {’i', ‘n’, ‘t’, ‘ ‘, ‘m’, ‘a’, ‘i’, ‘n’, ‘(’, ‘)’, ‘ ‘, ‘{’, ‘%’, ‘c’, ‘ ‘, ‘c’, ‘h’, ‘a’, ‘r’, ‘*’, ‘ ‘, ‘b’, ‘u’, ‘f’, ‘1′, ‘ ‘, ‘=’, ‘ ‘, ‘%’, ‘c’, ‘%’, ’s’, ‘%’, ‘c’, ‘;’, ‘%’, ‘c’, ‘ ‘, ‘%’, ’s’, ‘%’, ‘c’, ‘}’, (char) 0}; printf(buf2, 10, 34, buf1, 34, 10, buf1, 10);”;
char buf2[] = {’i', ‘n’, ‘t’, ‘ ‘, ‘m’, ‘a’, ‘i’, ‘n’, ‘(’, ‘)’, ‘ ‘, ‘{’, ‘%’, ‘c’, ‘ ‘, ‘c’, ‘h’, ‘a’, ‘r’, ‘*’, ‘ ‘, ‘b’, ‘u’, ‘f’, ‘1′, ‘ ‘, ‘=’, ‘ ‘, ‘%’, ‘c’, ‘%’, ’s’, ‘%’, ‘c’, ‘;’, ‘%’, ‘c’, ‘ ‘, ‘%’, ’s’, ‘%’, ‘c’, ‘}’, (char) 0}; printf(buf2, 10, 34, buf1, 34, 10, buf1, 10);
}

Bạn có thể dịch và chạy thử đoạn trên, in ra chương trình y hệt.

Chủ đề: Bảo mật và mật mã học & Lý thuyết tính toán | Bình luận »