Berapa banyak pasangan kurung yang cukup untuk membuat Brainfuck Turing lengkap?

12

Brainfuck adalah bahasa pemrograman lengkap Turing yang hanya menggunakan 8 simbol (6 jika Anda mengabaikan I / O).

Dua yang paling terkenal yang mendorongnya ke kelengkapan Turing adalah [dan ], pada dasarnya, label dan goto Brainfuck.

Biasanya, program di Brainfuck menggunakan beberapa set [], tapi saya bertanya-tanya berapa banyak pasang tanda kurung ini harus digunakan untuk membuat Brainfuck Turing lengkap?

Lebih sederhana lagi, berapakah jumlah kurung yang paling kecil yang Anda perlukan untuk mensimulasikan mesin Turing n-state (Berikan jumlah braket untuk 1, 2, dan tiga Mesin Turing keadaan)?

Catatan:

Kami mengasumsikan rekaman tak terbatas dan tidak ada batasan komputasi.

Ini adalah Mesin Turing 2-simbol

MilkyWay90
sumber
1
"Berapa banyak pasang kurung ini yang harus digunakan?" Bisakah Anda mengklarifikasi "harus digunakan". Misalnya, bagaimana jika saya meminta BrainF untuk menghitung hingga 21000000 ?
John L.
@ Apass.Jack jumlah minimum kurung
MilkyWay90
1
Oh, maksud Anda jumlah kurung minimum untuk mensimulasikan mesin Turing status sebagai fungsi dari n ? Lagi pula, dapatkah Anda memberikan contoh nontrivial yang sesederhana mungkin? nn
John L.
1
@ Apass.Jack Oke, saya datang dengan program BF buggy yang bekerja untuk Mesin Turing satu negara
MilkyWay90
@ Apass.Jack Nevermind, itu terlalu sulit bagi saya. Pada dasarnya buatlah juru bahasa BF untuk bahasa pemrograman saya, Turing Machine But Way Worse , ketika itu hanya menggunakan dua simbol yang mungkin (0 dan 1) dan hapus aspek I / O dan halting sepenuhnya
MilkyWay90

Jawaban:

9

Ini adalah pengembangan lebih lanjut dari jawaban @ ais523 , menguranginya menjadi hanya dua set kurung, dan juga menggunakan penempatan sel yang lebih kompak berdasarkan pada teori penguasa Golomb. ais523 telah membuat kompiler untuk konstruksi ini , serta sesi TIO ini menunjukkan sampel yang menghasilkan program BF berjalan dengan pelacakan debug dari penghitung TWM.

Seperti aslinya, ini dimulai dengan program di The Waterfall Model , dengan beberapa batasan yang tidak kehilangan sifat umum:

  1. Semua penghitung memiliki nilai pengaturan-ulang R ; yaitu, peta pemicu TWM f memiliki properti yang f(x,x)=R untuk semua x .
  2. Ada penghitung penghentian tunggal h .
  3. Jumlah c penghitung adalah (p1)/2 untuk beberapa bilangan prima p .

Penguasa Golomb

Kami menggabungkan konstruksi Erd-Turán dengan fungsi permutasi dari array Welch-Costas untuk mendapatkan penguasa Golomb dengan properti yang diperlukan.

(Saya yakin konstruksi gabungan ini bukan ide baru, tetapi kami baru saja menemukan dan menyatukan kedua potongan ini dari Wikipedia.)

Biarkan r menjadi akar primitif p=2c+1 . Tentukan fungsinya

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

  1. g2 c g ( i ) - g ( j ) i , j { 0 , , 2 c - 1 } adalah penguasa Golomb orde . Yaitu, perbedaan adalah unik untuk setiap pasangan nomor berbeda .2cg(i)g(j)i,j{0,,2c1}
  2. g(k)mod(2c) mengambil setiap nilai tepat sekali.0,,2c1

Struktur pita

Untuk setiap penghitung TWM , kami menetapkan dua posisi sel pita BF, sel fallback dan sel nilai :x{0,,c1}u ( x ) v ( x ) u(x) v(x)

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

Dengan properti kedua ada dua berbeda dapat dipilih.gk1,k2

Konten sel fallback sebagian besar waktu akan disimpan pada , kecuali ketika penghitungnya baru saja dikunjungi, ketika akan berada di , dua kali nilai penghitung ulang otomatis counter. Sel nilai akan disimpan dua kali lipat dari nilai penghitung TWM yang sesuai.02R

Semua sel lain yang dapat dijangkau oleh eksekusi program BF (angka terbatas) akan disimpan pada nilai ganjil, sehingga mereka selalu diuji sebagai bukan nol. Setelah inisialisasi ini otomatis karena semua penyesuaian sel adalah dengan jumlah genap.

Jika diinginkan, semua posisi sel dapat digeser ke kanan oleh konstanta untuk menghindari bergerak ke kiri dari posisi rekaman BF awal.

Struktur program BF

Misalkan menjadi jarak antara nilai penghitung penghentian dan sel fallback, dan misalkan menjadi angka yang cukup besar sehingga untuk semua penghitung . Maka struktur program BF dasar adalahH=v(h)u(h)NcN+1v((x+1)modc)u(x)x

inisialisasi penyesuaian[ >×(H+cN+1) [ <×c ] <×H ]

Inisialisasi

The inisialisasi fase set semua sel dapat dijangkau oleh program untuk nilai awal mereka, dalam keadaan seperti counter terakhir baru saja dikunjungi dan sel hanya aktif adalah sel mundur nya :u(c1)

  1. Nilai sel diinisialisasi menjadi dua kali konten awal dari penghitung TWM yang sesuai, kecuali bahwa penghitung adalah pre-decremented.0
  2. Sel fallback diatur ke , kecuali sel , yang diatur ke .0u(c1)2R
  3. Semua sel lain yang dapat dijangkau oleh program (angka terbatas) diatur ke .1

Kemudian pita penunjuk dipindahkan ke posisi (sel yang selalu bukan nol) sebelum kita mencapai program yang pertama .u(c1)H[

Awal dari lingkaran luar

Pada awal iterasi dari loop luar, penunjuk pita akan berada di atau untuk penghitung .u(x)Hv(x)Hx

Biarkan menjadi penghitung berikutnya untuk dikunjungi.y=((x+1)modc)

Gerakan menempatkan penunjuk kaset pada posisi yang dan tidak di sebelah kiri .>×(H+cN+1)y(modc)v(y)

Loop dalam sekarang mencari ke kiri dalam langkah-langkah untuk sel nol. Jika counter adalah nol, maka ia akan berhenti pada sel nilai (nol) ; selain itu akan menemukan sel fallback .[ <×c ]cyv(y)u(y)

Sel mana pun yang ditemukan menjadi sel aktif baru .

Penyesuaian

The penyesuaian fase menyesuaikan berbagai sel pada pita berdasarkan posisi mereka relatif terhadap sel aktif. Bagian ini hanya berisi +-><perintah dan penyesuaian ini terjadi tanpa syarat. Namun, karena semua sel yang berhubungan dengan counter berada dalam pola penguasa Golomb, setiap penyesuaian yang tidak sesuai untuk sel aktif saat ini akan kehilangan semua sel penting dan menyesuaikan beberapa sel yang tidak relevan sebagai gantinya (sambil tetap membuatnya aneh).

Karenanya, kode terpisah harus dimasukkan dalam program untuk setiap pasangan sel aktif dan sel yang mungkin diperlukan, kecuali untuk penyesuaian diri sel aktif, yang, karena penyesuaian hanya didasarkan pada posisi relatif, harus dibagi di antara mereka semua.

Penyesuaian yang diperlukan adalah:

  1. Sesuaikan sel fallback counter sebelumnya dengan .u(x)2R
  2. Sesuaikan sel fallback penghitung saat ini dengan , kecuali jika sel aktif saat ini adalah dan jadi kita harus berhenti.u(y)2Rv(h)
  3. Sesuaikan sel nilai penghitung berikutnya dengan (menurunkan penghitung).v((y+1)modc)2
  4. Ketika sel aktif adalah sel nilai (sehingga penghitung telah mencapai nol), sesuaikan semua sel nilai dengan dari peta pemicu TWM. itu sendiri menjadi disesuaikan dengan .v(y)yv(z)2f(y,z)v(y)2R

Penyesuaian pertama dan kedua di atas diperlukan oleh fakta bahwa semua sel aktif harus menyesuaikan diri dengan nilai yang sama, yaitu untuk sel nilai, dan dengan demikian juga untuk sel fallback. Ini membutuhkan persiapan dan pembersihan sel fallback untuk memastikan mereka kembali ke di cabang value dan fallback.2R0

Akhir dari lingkaran luar

Gerakan menyatakan bahwa pada akhir fase penyesuaian, penunjuk kaset dipindahkan ke tempat di sebelah kiri sel aktif.<×HH

Untuk semua sel aktif selain dari sel penghenti nilai sel , ini adalah sel yang tidak relevan, dan sangat aneh dan tidak nol, dan loop luar berlanjut untuk iterasi lain.v(h)

Untuk , penunjuk ditempatkan pada sel fallback yang sesuai , di mana kami telah membuat pengecualian di atas agar tetap nol, sehingga program keluar melalui final dan berhenti.v(h)u(h)]

Ørjan Johansen
sumber
12

Saya tidak 100% yakin bahwa ini tidak mungkin dilakukan dengan dua set tanda kurung. Namun, jika sel-sel pita BF memungkinkan nilai yang tidak terbatas, tiga set kurung sudah cukup. (Untuk kesederhanaan, saya juga akan berasumsi bahwa kita dapat memindahkan kepala kaset melewati titik awal, meskipun karena konstruksi ini hanya menggunakan daerah terbatas rekaman, kita dapat mengangkat batasan itu dengan menambahkan cukup banyak >perintah pada awal program.) Konstruksi di bawah ini membutuhkan asumsi dugaan Artinuntuk dapat mengkompilasi program besar secara sewenang-wenang; namun, meskipun dugaan Artin salah, masih mungkin untuk menunjukkan kelengkapan Turing secara tidak langsung melalui menerjemahkan juru bahasa Turing ke dalam bahasa BF menggunakan konstruksi di bawah ini, dan menjalankan program sewenang-wenang dengan memberikannya sebagai masukan untuk penerjemah itu.

Bahasa lengkap Turing yang kami kompilasi menjadi BF tanpa batas adalah The Waterfall Model , yang merupakan salah satu model komputasi paling sederhana yang diketahui. Untuk orang yang belum mengetahuinya, ini terdiri dari sejumlah penghitung (dan nilai awal untuk mereka), dan fungsi dari pasangan penghitung ke bilangan bulat; eksekusi program terdiri dari berulang kali mengurangi 1 dari setiap penghitung, maka jika ada penghitung adalah 0, menambahkan ke setiap penghitung (program ditulis sedemikian rupa sehingga ini tidak pernah terjadi pada banyak penghitung secara bersamaan). Ada bukti kelengkapan Turing untuk bahasa ini di belakang tautan saya. Tanpa kehilangan sifat umum, kami akan menganggap bahwa semua penghitung memiliki nilai pengaturan ulang yang sama (misfxf(x,y)yf(x,x) adalah sama untuk semua ); ini adalah asumsi yang aman karena untuk setiap spesifik , menambahkan konstanta yang sama untuk setiap tidak akan mengubah perilaku program.xxf(x,y)

Biarkan menjadi jumlah penghitung; tanpa kehilangan sifat umum (dengan asumsi dugaan Artin), asumsikan bahwa memiliki akar primitif 2. Misalkan menjadi , di mana adalah kekuatan terendah 2 lebih besar dari . Tanpa kehilangan generalitas, akan kurang dari ( dibatasi secara polinomi, tumbuh secara eksponensial, sehingga cukup besar akan bekerja).ppqp(1+s+s2)sp2q2p2q2pp

Susunan pita adalah sebagai berikut: kami menomori setiap penghitung dengan bilangan bulat (dan tanpa kehilangan sifat umum, kami menganggap bahwa ada penghitung penghenti tunggal dan nomor ). Nilai dari sebagian besar penghitung disimpan pada sel pita , dengan pengecualian penghitung 0, yang disimpan pada sel pita . Untuk setiap sel tape bernomor ganjil dari sel -1 hingga dan termasuk0i<p22i2q2p+1+2p+1, bahwa sel tape selalu memegang 1, kecuali itu langsung di sebelah kiri counter, dalam hal ini selalu memegang 0. Sel tape bernomor yang tidak digunakan sebagai penghitung memiliki nilai yang tidak relevan (yang mungkin atau mungkin tidak 0 ); dan sel kaset bernomor ganjil di luar rentang yang dinyatakan juga memiliki nilai yang tidak relevan. Perhatikan bahwa pengaturan pita ke dalam kondisi awal yang sesuai hanya membutuhkan inisialisasi banyak elemen tape hingga nilai konstan, artinya kita dapat melakukannya dengan urutan <>+-instruksi (pada kenyataannya, hanya >+diperlukan), sehingga tidak ada tanda kurung. Di akhir inisialisasi ini, kami memindahkan pita penunjuk ke sel -1.

Bentuk umum dari program kami akan terlihat seperti ini:

inisialisasi penyesuaian[>>>[ >×(2p1) [ <×(2p) ]>-] <<<]

Inisialisasi menempatkan pita ke dalam bentuk yang diharapkan dan penunjuk pada sel -1. Ini bukan sel di sebelah kiri penghitung (0 bukan kekuatan 2), jadi ini memiliki nilai 1, dan kami memasukkan loop. Loop invarian untuk loop terluar ini adalah bahwa penunjuk pita adalah (pada awal dan akhir setiap iterasi loop) tiga sel di sebelah kiri penghitung; dapat dilihat bahwa loop hanya akan keluar jika kita tiga sel di sebelah kiri penghitung 2 (masing-masing penghitung lainnya memiliki 1 tiga sel di sebelah kirinya, karena memiliki 0 di sana akan menyiratkan bahwa posisi pita dua penghitung ' terpisah 2 sel, hanya dua kekuatan 2 yang berbeda 2 adalah dan , dan representasi biner berubah dari string s ke string2122q01s atau sebaliknya setidaknya empat kali dan dengan demikian tidak dapat 1 jauh dari kekuatan 2).

Loop kedua berulang kali berulang-ulang di atas counter, menurunkannya. Loop invarian adalah bahwa penunjuk pita selalu menunjuk ke penghitung; dengan demikian loop akan keluar ketika beberapa penghitung menjadi 0. Penurunan itu hanya -; cara yang kita dapatkan dari satu konter ke konter berikutnya lebih kompleks. Ide dasarnya adalah bahwa memindahkan spasi ke kanan dari akan menempatkan kita pada sel bernomor ganjil , yang berada di sebelah kanan penghitung mana pun ( adalah penghitung terakhir, bernilai positif karena adalah positif); modulo , nilai ini sebangun dengan (oleh Fermat's Little Theorem) . Loop terdalam berulang kali bergerak ke kiri2p12x2p+2x12p2x1x2p2x+12p spasi, juga tidak mengubah indeks modulo sel , dan akhirnya harus menemukan sel kongruen menjadi modulo yang memiliki nilai (yang akan menjadi sel di sebelah kiri beberapa counter); karena persyaratan root primitif kami ada satu sel seperti itu ( kongruen dengan modulo , dan kongruen dengan untuk setiap lain , di mana adalah logaritma diskrit ke basis 2 modulo ). Selain itu, dapat dilihat bahwa posisi tape pointer modulo2p2x+12p2q112p2log2,p(r)+112r1rlog2,pp2pmeningkat setiap kali putaran lingkaran tengah. Dengan demikian, pita penunjuk harus berputar di antara semua penghitung (dalam urutan nilai modulo ). Jadi, setiap iterasi, kami mengurangi setiap penghitung (sesuai kebutuhan). Jika loop terputus di tengah jalan melalui iterasi, kami akan melanjutkan penurunan ketika kami memasukkan kembali loop (karena sisa loop terluar tidak membuat perubahan bersih ke posisi penunjuk pita).2p2pp

Ketika penghitung mencapai 0, loop tengah putus, membawa kita ke kode "penyesuaian". Ini pada dasarnya hanya sebuah pengkodean dari ; untuk setiap pasangan , itu menambah ke elemen pita yang merupakan jarak yang sama kiri / kanan pita pointer saat ini sebagai counter 's lokasi tape kiri / kanan kontra ' s lokasi pita (dan kemudian lepaskan penunjuk pita kembali ke tempat awalnya). Setiap kali , jarak ini menjadi unik:f(x,y)f(x,y)yxxy

  • Perbedaan antara dua kekuatan 2 adalah bilangan biner yang terdiri dari string 1 atau lebih s diikuti oleh string 0 atau lebih s (dengan nilai tempat dari awal angka, dan awal dari string , tergantung masing-masing lebih besar dan lebih kecil dari dan ); jadi semua perbedaan itu berbeda. * Adapun perbedaan kekuatan 2 dan , harus mengandung setidaknya dua transisi antara string detik dan detik (100xyq10q mengandung setidaknya empat transisi seperti itu, pengurangan hanya dapat menghapus 2), dengan demikian berbeda dari semua perbedaan dua kekuatan dua, dan perbedaan ini jelas juga berbeda satu sama lain.

Untuk , kami jelas menemukan bahwa jarak yang dipindahkan adalah 0. Tetapi karena semua sama, kita bisa menggunakan ini sebagai penyesuaian untuk sel saat ini. Dan dapat dilihat bahwa kode penyesuaian dengan demikian mengimplementasikan efek "ketika penghitung menyentuh 0" untuk setiap penghitung; semua sel yang benar-benar mewakili penghitung akan disesuaikan dengan jumlah yang benar, dan semua penyesuaian lainnya akan memengaruhi sel genap tanpa-nomor (perbedaan antara dua angka genap genap), yang tidak memiliki efek pada perilaku program.x=yf(x,y)

Dengan demikian, kami sekarang memiliki kompilasi yang berfungsi dari setiap program dalam The Waterfall Model ke BF (termasuk perilaku berhenti, tetapi tidak termasuk I / O, yang tidak diperlukan untuk kelengkapan Turing) hanya menggunakan tiga pasang kurung, dan dengan demikian tiga pasang kurung sudah cukup untuk kelengkapan Turing.

ais523
sumber
Pekerjaan yang baik! Saya melihat Anda mengerjakan ini di TNB!
MilkyWay90
Saya pikir Anda harus setidaknya p + 2. Ketika s = p + 1, q adalah 1 kurang dari kekuatan 2.
Ørjan Johansen
Saya rasa saya menemukan lebih sederhana (seperti dalam tidak memerlukan prima nomor teori) penempatan counter: 2p*2^i+2i.
Ørjan Johansen
@ ØrjanJohansen: Benar, saya pikir saya sebutkan konstruksi dalam #esoteric (beberapa waktu setelah saya menulis posting ini)? Yang Anda butuhkan hanyalah penguasa Golomb yang setiap elemennya berbeda modulo jumlah elemennya, dan ada berbagai cara untuk membangunnya (walaupun menemukan yang optimal itu sulit; yang terlama yang saya temukan (via brute force) adalah [0, 1, 3, 7, 20, 32, 42, 53, 58]untuk p = 9).
ais523
Oh begitu Anda melakukannya (tepat sebelum saya mengatakan otak saya menolak berada dalam mode matematika, jadi ada alasan saya: P). Kurasa aku tahu k = 0 sudah cukup, kalau begitu. Saya pikir Wikipedia Erd's-Turan_construction memberikan yang tumbuh secara polinomi (dan mungkin O () - optimal?) Satu jika Anda menggunakan hanya bagian pertama dari elemen (setengah lainnya mengulangi (mod p)).
Ørjan Johansen