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
turing-completeness
MilkyWay90
sumber
sumber
Jawaban:
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:
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.)
Biarkanr menjadi akar primitif p=2c+1 . Tentukan fungsinya
Struktur pita
Untuk setiap penghitung TWM , kami menetapkan dua posisi sel pita BF, sel fallback dan sel nilai :x∈{0,…,c−1} u ( x ) v ( x ) u(x) v(x)
Dengan properti kedua ada dua berbeda dapat dipilih.g k1,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.0 2R
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) N cN+1≥v((x+1)modc)−u(x) x
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(c−1)
Kemudian pita penunjuk dipindahkan ke posisi (sel yang selalu bukan nol) sebelum kita mencapai program yang pertama .u(c−1)−H
[
Awal dari lingkaran luar
Pada awal iterasi dari loop luar, penunjuk pita akan berada di atau untuk penghitung .u(x)−H v(x)−H x
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 c y v(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:
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.2R 0
Akhir dari lingkaran luar
Gerakan menyatakan bahwa pada akhir fase penyesuaian, penunjuk kaset dipindahkan ke tempat di sebelah kiri sel aktif.×H H
<
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)
]
sumber
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 (misf x f(x,y) y f(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.x x f(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).p p q p(1+s+s2) s p 2q 2p 2q 2p p
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 termasuk0≤i<p 2 2i 2q 2p+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 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 string21 22 q 0 1 s 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 hanya2p−1 2x 2p+2x−1 2p 2x−1 x 2p 2x+1 2p 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 modulo2p 2x+1 2p 2q−1 −1 2p 2log2,p(r)+1−1 2r−1 r log2,p p 2p meningkat 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).2 p 2p p
-
; 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 kiriKetika 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) y x x≠y
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=y f(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.
sumber
2p*2^i+2i
.[0, 1, 3, 7, 20, 32, 42, 53, 58]
untuk p = 9).