Có bao nhiêu cặp dấu ngoặc đủ để làm cho Brainfuck Turing hoàn thành?


12

Brainfuck là ngôn ngữ lập trình hoàn chỉnh Turing chỉ sử dụng 8 ký hiệu (6 nếu bạn bỏ qua I / O).

Hai thứ đáng chú ý nhất đẩy nó đến sự hoàn thiện của Turing là []về cơ bản là nhãn và goto của Brainfuck.

Thông thường, các chương trình trong Brainfuck sử dụng nhiều bộ [], nhưng tôi đã tự hỏi chính xác có bao nhiêu cặp dấu ngoặc này phải được sử dụng để làm cho Brainfuck Turing hoàn thành?

Đơn giản hơn, số lượng dấu ngoặc ít nhất bạn cần để mô phỏng Máy Turing trạng thái n (Cung cấp số lượng dấu ngoặc cho 1, 2 và ba Máy Turing trạng thái) là bao nhiêu?

Ghi chú:

Chúng tôi đang giả sử một băng vô hạn và không có giới hạn tính toán.

Nó là một máy Turing 2 ký hiệu


1
"có bao nhiêu cặp dấu ngoặc phải được sử dụng?" Bạn có thể làm rõ "phải được sử dụng". Ví dụ: nếu tôi yêu cầu BrainF đếm đến thì sao? 21000000
John L.

@ Apass.Jack số lượng dấu ngoặc tối thiểu
MilkyWay90

1
Ồ, ý bạn là số lượng dấu ngoặc tối thiểu để mô phỏng máy Turing -state là một chức năng của ? Dù sao, bạn có thể đưa ra một ví dụ không đơn giản mà đơn giản nhất có thể? nn
John L.

1
@ Apass.Jack Được rồi, tôi đang đến với một chương trình BF lỗi hoạt động cho Máy Turing một trạng thái
MilkyWay90

@ Apass.Jack Nevermind, nó quá khó đối với tôi. Về cơ bản hãy tạo một trình thông dịch BF cho ngôn ngữ lập trình của tôi, Turing Machine But Way Worse , khi nó chỉ sử dụng hai ký hiệu có thể (0 và 1) và loại bỏ hoàn toàn khía cạnh I / O và tạm dừng
MilkyWay90

Câu trả lời:


9

Đây là một sự phát triển hơn nữa của câu trả lời của @ ais523 , giảm nó xuống chỉ còn hai bộ dấu ngoặc và cũng sử dụng vị trí ô nhỏ gọn hơn dựa trên lý thuyết thước kẻ Golomb. ais523 đã tạo một trình biên dịch cho cấu trúc này , cũng như phiên TIO này hiển thị một chương trình mẫu kết quả BF đang chạy với theo dõi gỡ lỗi của các bộ đếm TWM.

Giống như bản gốc, điều này bắt đầu với một chương trình trong Mô hình thác nước , với một số hạn chế không làm mất tính tổng quát:

  1. Tất cả các bộ đếm có cùng giá trị tự đặt lại R ; nghĩa là, bản đồ kích hoạt TWM f có thuộc tính f(x,x)=R với mọi x .
  2. Có một bộ đếm tạm dừng h .
  3. Số c của bộ đếm là (p1)/2 cho một số số nguyên tố p .

Thước kẻ Golomb

Chúng tôi kết hợp cấu trúc Erdős Gian Turán với chức năng hoán vị của một mảng Welas của Costas để có được một thước kẻ Golomb với các thuộc tính cần thiết.

(Tôi chắc chắn rằng việc xây dựng kết hợp này không thể là một ý tưởng mới nhưng chúng tôi chỉ tìm thấy và kết hợp hai phần này từ Wikipedia.)

Đặt r là gốc nguyên thủy của p=2c+1 . Xác định hàm

g(k)=4ck((rk1)mod(2c+1)),k=0,,2c1.

  1. g là mộtngười cai trị Golombtheo thứ tự2c . Nghĩa là, sự khác biệtg(i)g(j) là duy nhất cho mỗi cặp số riêng biệti,j{0,,2c1} .
  2. g(k)mod(2c) nhận mọi giá trị0,,2c1 chính xác một lần.

Cấu trúc băng

Với mỗi bộ đếm TWM x{0,,c1} , chúng tôi gán hai vị trí ô băng BF, một ô dự phòng u(x) và một ô giá trị v(x) :

u(x)=g(k1)<v(x)=g(k2) with u(x)v(x)x(modc)

Theo thuộc tính thứ hai của có chính xác hai giá trị riêng biệt để chọn.gk1,k2

Nội dung của một tế bào dự phòng hầu hết thời gian sẽ được giữ ở mức , ngoại trừ khi bộ đếm của nó vừa được truy cập, khi đó nó sẽ ở mức , gấp đôi giá trị tự đặt lại của bộ đếm. Một ô giá trị sẽ được giữ ở mức gấp đôi giá trị của bộ đếm TWM tương ứng.02R

Tất cả các ô khác có thể đạt được bằng cách thực hiện chương trình BF (một số hữu hạn) sẽ được giữ ở các giá trị lẻ, để chúng luôn kiểm tra là khác không. Sau khi khởi tạo, điều này là tự động vì tất cả các điều chỉnh ô đều bằng số lượng chẵn.

Nếu muốn, tất cả các vị trí ô có thể được dịch chuyển sang phải bởi một hằng số để tránh di chuyển sang bên trái của vị trí băng BF ban đầu.

Cấu trúc chương trình BF

Đặt là khoảng cách giữa giá trị của bộ đếm tạm dừng và các ô dự phòng và để là một số đủ lớn để cho tất cả các quầy x . Sau đó, cấu trúc chương trình BF cơ bản làH=v(h)u(h)NcN+1v((x+1)modc)u(x)x

khởi tạo [ >×(H+cN+1) [ <×c ] điều chỉnh <×H ]

Khởi tạo

Các khởi giai đoạn tập hợp tất cả các tế bào có thể truy cập bởi các chương trình với các giá trị ban đầu của họ, trong một trạng thái như thể truy cập cuối cùng vừa được truy cập và các tế bào chỉ hoạt động là tế bào dự phòng của nó u(c1) :

  1. Các ô giá trị được khởi tạo thành hai lần nội dung ban đầu của bộ đếm TWM tương ứng, ngoại trừ bộ đếm 0 được giảm trước.
  2. Tế bào dự phòng được thiết lập để 0 , ngoại trừ tế bào u(c1) , được thiết lập để 2R .
  3. Tất cả các ô khác có thể truy cập theo chương trình (một số hữu hạn) được đặt thành 1 .

Sau đó, con trỏ băng được di chuyển đến vị trí u(c1)H (một ô luôn luôn khác không) trước khi chúng ta đến chương trình đầu tiên [.

Bắt đầu vòng lặp bên ngoài

Khi bắt đầu một vòng lặp của vòng lặp bên ngoài, con trỏ băng sẽ ở một trong hai u(x)H hoặc v(x)H cho một bộ đếm x .

Đặt y=((x+1)modc) làm bộ đếm tiếp theo ghé thăm.

Chuyển động >×(H+cN+1) đặt con trỏ băng lên vị trí y(modc) và không ở bên trái củav(y) .

Vòng lặp bên trong [ <×c ] bây giờ tìm kiếm bên trái theo các bước của c cho một ô không. Nếu bộ đếm y bằng 0, thì nó sẽ dừng ở ô giá trị (không) v(y) ; nếu không nó sẽ tìm thấy ô dự phòng u(y) .

Bất kỳ ô nào được tìm thấy sẽ trở thành ô hoạt động mới .

Điều chỉnh

Các điều chỉnh giai đoạn điều chỉnh tế bào khác nhau trên băng dựa trên vị trí của họ so với các tế bào hoạt động. Phần này chỉ chứa +-><các lệnh và vì vậy những điều chỉnh này xảy ra vô điều kiện. Tuy nhiên, vì tất cả các ô liên quan đến bộ đếm đều nằm trong mẫu thước kẻ Golomb, nên mọi điều chỉnh không phù hợp với ô hiện hoạt sẽ bỏ lỡ tất cả các ô quan trọng và thay vào đó điều chỉnh một số ô không liên quan (trong khi vẫn giữ nguyên số lẻ).

Do đó, mã riêng biệt phải được đưa vào chương trình cho từng cặp ô hoạt động và điều chỉnh cần thiết có thể, ngoại trừ việc tự điều chỉnh của một ô đang hoạt động, bởi vì điều chỉnh chỉ dựa trên vị trí tương đối, phải được chia sẻ giữa tất cả chúng.

Các điều chỉnh cần thiết là:

  1. Điều chỉnh tế bào fallback quầy trước u(x) bởi 2R .
  2. Điều chỉnh ô dự phòng của bộ đếm hiện tại u(y) bằng 2R , trừ khi ô hiện hoạt là v(h) và vì vậy chúng ta nên tạm dừng.
  3. Điều chỉnh ô giá trị của bộ đếm tiếp theo v((y+1)modc) bằng 2 (giảm bộ đếm).
  4. Khi ô hiện hoạt là ô giá trị v(y) (vì vậy bộ đếm y đã đạt đến 0), điều chỉnh tất cả các ô giá trị v(z) bằng 2f(y,z) từ bản đồ kích hoạt TWM. v(y) bản thân trở nên điều chỉnh bằng 2R .

Các điều chỉnh thứ nhất và thứ hai ở trên được thực hiện cần thiết bởi thực tế là tất cả các ô đang hoạt động phải tự điều chỉnh theo cùng một giá trị, đó là 2R cho các ô giá trị và do đó cũng cho các ô dự phòng. Điều này đòi hỏi phải chuẩn bị và dọn sạch các ô dự phòng để đảm bảo chúng trở về 0 trong cả hai nhánh giá trị và dự phòng.

Kết thúc vòng ngoài

Chuyển động <×H biểu thị rằng ở cuối giai đoạn điều chỉnh, con trỏ băng được di chuyển H sang bên trái của ô đang hoạt động.

Đối với tất cả các ô hoạt động khác với ô giá trị của bộ đếm tạm dừng v(h) , đây là một ô không liên quan, do đó, lẻ và khác không, và vòng lặp bên ngoài tiếp tục cho một lần lặp khác.

Đối với v(h) , con trỏ thay vào đó được đặt trên ô dự phòng tương ứng u(h) , mà chúng ta đã tạo một ngoại lệ ở trên để giữ cho nó bằng không, và do đó chương trình thoát qua cuối cùng ]và dừng lại.


12

Tôi không chắc chắn 100% rằng không thể làm điều này với hai bộ dấu ngoặc. Tuy nhiên, nếu các ô của băng BF cho phép các giá trị không giới hạn, ba bộ dấu ngoặc là đủ. (Để đơn giản, tôi cũng cho rằng chúng ta có thể di chuyển đầu băng qua điểm bắt đầu của nó, mặc dù vì cấu trúc này chỉ sử dụng một vùng hữu hạn của băng, chúng ta có thể gỡ bỏ hạn chế đó bằng cách thêm đủ nhiều >lệnh khi bắt đầu chương trình.) Việc xây dựng dưới đây đòi hỏi phải có giả định của Artinđể có thể biên dịch các chương trình lớn tùy ý; tuy nhiên, ngay cả khi phỏng đoán của Artin là sai, vẫn có thể hiển thị gián tiếp tính đầy đủ của Turing thông qua việc dịch một trình thông dịch cho ngôn ngữ hoàn chỉnh Turing sang BF bằng cách sử dụng cấu trúc bên dưới và chạy các chương trình tùy ý thông qua việc đưa chúng làm đầu vào cho trình thông dịch đó.

Ngôn ngữ hoàn chỉnh Turing mà chúng tôi biên dịch thành BF không giới hạn là Mô hình thác nước , đây là một trong những mô hình tính toán đơn giản nhất được biết đến. Đối với những người chưa biết về nó, nó bao gồm một số bộ đếm (và các giá trị ban đầu cho chúng) và một hàm f từ các cặp bộ đếm đến số nguyên; thực hiện chương trình bao gồm nhiều lần trừ 1 từ mỗi bộ đếm, sau đó nếu bất kỳ bộ đếm x 0, thêm f(x,y) vào mỗi bộ đếm y(chương trình được viết theo cách mà điều này không bao giờ xảy ra với nhiều bộ đếm đồng thời). Có bằng chứng Turing-đầy đủ cho ngôn ngữ này đằng sau liên kết của tôi. Không mất tính tổng quát, chúng tôi sẽ giả sử rằng tất cả các bộ đếm có cùng giá trị tự đặt lại (ví dụ f(x,x) là giống nhau cho tất cả x ); đây là một giả định an toàn vì với bất kỳ x cụ thể nào , việc thêm cùng một hằng số cho mỗi f(x,y) sẽ không thay đổi hành vi của chương trình.

Gọi p là số lượng quầy; không mất tính tổng quát (giả sử Artin phỏng đoán), giả sử rằng pgốc nguyên thủy 2. Gọi qp(1+s+s2) , trong đó s là công suất thấp nhất bằng 2 lớn hơn p . Nếu không mất tính tổng quát, 2q sẽ nhỏ hơn 2p ( 2q bị giới hạn đa thức, 2p tăng theo cấp số nhân, do đó, bất kỳ p đủ lớn nào cũng sẽ hoạt động).

Việc bố trí băng là như sau: chúng tôi đánh số từng truy cập với một số nguyên 0i<p (và không mất tính tổng quát, chúng ta giả định rằng có một ngưng truy cập duy nhất và số nó 2 ). Giá trị của hầu hết các bộ đếm được lưu trữ trên ô băng 2i , ngoại trừ bộ đếm 0, được lưu trữ trên ô băng 2q . Đối với mỗi ô băng được đánh số lẻ từ ô -1 trở lên và bao gồm 2p+1+2p+1, ô băng đó luôn giữ 1, trừ khi nó nằm ngay bên trái của bộ đếm, trong trường hợp đó, nó luôn giữ 0. Các ô băng được đánh số chẵn không được sử dụng làm bộ đếm có các giá trị không liên quan (có thể có hoặc không bằng 0 ); và các ô băng được đánh số lẻ ngoài phạm vi đã nêu cũng có các giá trị không liên quan. Lưu ý rằng việc đặt băng vào trạng thái ban đầu thích hợp chỉ yêu cầu khởi tạo nhiều phần tử băng thành giá trị không đổi, nghĩa là chúng ta có thể thực hiện với một chuỗi <>+-hướng dẫn (thực tế là chỉ >+cần thiết), do đó không cần dấu ngoặc. Khi kết thúc việc khởi tạo này, chúng tôi di chuyển con trỏ băng đến ô -1.

Hình dạng chung của chương trình của chúng tôi sẽ như thế này:

Không khởi [>>>[ >×(2p1) [ <×(2p) ]>-] điều chỉnh <<<]

Việc khởi tạo đặt băng vào hình dạng dự kiến ​​và con trỏ trên ô -1. Đây không phải là ô bên trái của bộ đếm (0 không phải là lũy thừa 2), vì vậy nó có giá trị 1 và chúng ta nhập vào vòng lặp. Bất biến vòng lặp cho vòng lặp ngoài cùng này là con trỏ băng là (ở đầu và cuối của mỗi lần lặp vòng lặp) ba ô ở bên trái của bộ đếm; Do đó, có thể thấy rằng vòng lặp sẽ chỉ thoát nếu chúng ta có ba ô ở bên trái của bộ đếm 2 (mỗi bộ đếm khác có 1 ba ô ở bên trái của nó, vì có 0 có nghĩa là hai vị trí băng của bộ đếm cách nhau 2 ô, hai lũy thừa 2 chỉ khác nhau 2 là 2122 và biểu diễn nhị phân của q thay đổi từ chuỗi 0 s sang chuỗi1 s hoặc ngược lại ít nhất bốn lần và do đó không thể cách xa 1).

Vòng lặp thứ hai lặp đi lặp lại trên các quầy, giảm dần chúng. Bất biến vòng lặp là con trỏ băng luôn luôn trỏ đến một bộ đếm; do đó vòng lặp sẽ thoát khi một số bộ đếm trở thành 0. Độ giảm chỉ là -; cách chúng ta đi từ quầy này sang quầy khác phức tạp hơn. Ý tưởng cơ bản là việc di chuyển 2p1 khoảng trắng sang phải từ 2x sẽ đặt chúng ta vào một ô số lẻ 2p+2x1 , nằm ở bên phải của bất kỳ bộ đếm nào ( 2p là bộ đếm cuối cùng, 2x1 là dương vì xtích cực); modulo 2p , giá trị này phù hợp với (theo Định lý nhỏ của Fermat) 2x+1 . Vòng lặp trong cùng liên tục di chuyển sang trái bởi 2p khoảng trắng, cũng không thay đổi chỉ số của ô băng modulo 2p và cuối cùng phải tìm ô tương ứng với 2x+1 modulo 2p có giá trị (sẽ là ô bên trái của một số quầy); do yêu cầu gốc nguyên thủy của chúng tôi có chính xác một ô như vậy ( 2q1 phù hợp với 1 modulo 2p , và2log2,p(r)+11 đồng dạng với2r1 cho bất kỳr nào khác, trong đólog2,p là logarit rời rạc cho cơ sở 2 modulop ). Ngoài ra, có thể thấy rằng vị trí của con trỏ băng modulo2p tăng2 lần mỗi vòng quanh vòng giữa. Do đó, con trỏ băng phải quay vòng giữa tất cả cácbộ đếmp (theo thứ tự các giá trị modulo2p ). Như vậy, mỗip lặp đi lặp lại, chúng tôi giảm mỗi bộ đếm (theo yêu cầu). Nếu vòng lặp bị hỏng giữa chừng trong một lần lặp, chúng ta sẽ tiếp tục giảm khi chúng ta nhập lại vòng lặp (vì phần còn lại của vòng ngoài cùng không làm thay đổi mạng đối với vị trí con trỏ băng).

Khi bộ đếm chạm 0, vòng lặp giữa sẽ ngắt, đưa chúng ta đến mã "điều chỉnh". Đây về cơ bản chỉ là một mã hóa của f ; cho mỗi cặp (x,y) , nó cho biết thêm f(x,y) để các yếu tố băng đó là cùng một khoảng cách trái / phải của con trỏ băng hiện nay là đồng xèng y 's vị trí băng được trái / phải của quầy x ' s vị trí băng (và sau đó loại bỏ con trỏ băng trở lại nơi nó bắt đầu). Bất cứ khi nào xy , khoảng cách này hóa ra là duy nhất:

  • Sự khác biệt giữa hai lũy thừa 2 là một số nhị phân bao gồm một chuỗi từ 1 trở lên 1 s theo sau là một chuỗi 0 hoặc nhiều hơn 0 s (với các giá trị vị trí của đầu số và bắt đầu của chuỗi 0 , tùy thuộc vào lớn hơn và nhỏ hơn tương ứng của xy ); do đó tất cả những khác biệt là khác biệt. * Đối với sự khác biệt của công suất 2 và q , nó phải chứa ít nhất hai lần chuyển đổi giữa các chuỗi 1 s và 0 s ( q chứa ít nhất bốn lần chuyển tiếp như vậy, phép trừ chỉ có thể loại bỏ 2), do đó khác biệt với tất cả các khác biệt của hai lũy thừa và hai sự khác biệt này rõ ràng cũng khác biệt với nhau.

Với x=y , rõ ràng chúng ta thấy rằng khoảng cách di chuyển là 0. Nhưng vì tất cả f(x,y) đều bằng nhau, chúng ta chỉ có thể sử dụng điều này làm điều chỉnh cho ô hiện tại. Và có thể thấy rằng mã điều chỉnh do đó thực hiện hiệu ứng "khi bộ đếm chạm 0" cho mọi bộ đếm; tất cả các ô thực sự đại diện cho bộ đếm sẽ được điều chỉnh theo số lượng chính xác và tất cả các điều chỉnh khác sẽ ảnh hưởng đến các ô không có số chẵn (số khác nhau giữa hai số chẵn), không ảnh hưởng đến hành vi của chương trình.

Do đó, giờ đây chúng tôi có một bản tổng hợp hoạt động của bất kỳ chương trình nào trong Mô hình thác nước đến BF (bao gồm cả hành vi tạm dừng, nhưng không bao gồm I / O, không cần thiết cho Turing-đầy đủ) chỉ sử dụng ba cặp dấu ngoặc, và do đó ba cặp của dấu ngoặc là đủ cho Turing-đầy đủ.


Công việc tốt! Tôi thấy bạn đã làm việc này trong TNB!
MilkyWay90

Tôi nghĩ bạn cần s ít nhất là p + 2. Khi s = p + 1, q nhỏ hơn 1 so với
lũy thừa

Tôi nghĩ rằng tôi đã tìm thấy một vị trí đơn giản hơn nhiều (như không yêu cầu lý thuyết số nguyên tố) : 2p*2^i+2i.
Ørjan Johansen

@ RjanJohansen: Phải, tôi nghĩ rằng tôi đã đề cập đến việc xây dựng đó trong #esoteric (một thời gian sau khi tôi viết bài đăng này)? Tất cả những gì bạn thực sự cần là một thước đo Golomb, trong đó mỗi phần tử là số lượng phần tử riêng biệt, và có nhiều cách khác nhau để xây dựng các phần tử đó (mặc dù việc tìm ra phần tử tối ưu là khó khăn, lâu nhất tôi đã tìm thấy (thông qua lực lượng vũ phu) là [0, 1, 3, 7, 20, 32, 42, 53, 58]dành cho p = 9).
ais523

Ồ, vậy là bạn đã làm (ngay trước khi tôi nói bộ não của tôi đã từ chối ở chế độ toán học, vì vậy có lý do của tôi: P). Tôi đoán tôi đã tìm ra k = 0 là đủ, sau đó. Tôi nghĩ rằng Erdős Nhận Turan_conloyment của Wikipedia mang lại sự phát triển đa thức (và có lẽ là O () - tối ưu?) Nếu bạn chỉ sử dụng nửa phần tử đầu tiên (nửa còn lại lặp lại (mod p)).
Ørjan Johansen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.