Google ClassroomGoogle Classroom
GeoGebraGeoGebra Classroom

計算言語3(チューリングマシン)

このページはマス旅の一部です。 前回スタック付きのオートマトン(PDA)をやりました。 今回はチューリングマシンをやろう。 PDAのスタックの代わりに無限に長いテープを使うのがチューリングマシンだ。
スタックではStackStrというスタック自体と、最上位topSを用意した。読み取れるのは いつもtopSだけなので、PushとPopという2つの動作と使ったね。 では、チューリングマシンの場合はどうだろうか。 長い固定テープをマス目に区切り、ヘッドがマス目を1マスずつ前進後退の動きをすることでデータの読み書きができる。ヘッダ付近以外では左右に無限に続くデータ空白があるとする。 Γにはテープの読み書き用の文字[0,1,+,x,"Λ"]が入る。 遷移関数は(Q,Γ)⇒(Q,Γ,{L,R}) スタックに比べるとテープとヘッドの使い方は単純ですね。 <テープとヘッドの使い方> 両側に無限の空白があるとするのではなく、右だけ無限の空白があるとしても チューリングマシンは実現できる。 入力文字列があると右の端に空白("Λ")とくっつけます。 スタートは左はしの1文字目です。いきなり読み込みを開始します。 ヘッドの動きは{L,R}がありますが、原則はRと思って大丈夫。 Σ={0,1,+,x}について、N,M.P∊[0,1],C,D∊[+,x]とラベルを貼って、実験してみよう。 1演算記号式"NMC"の計算は ①Nを読んで、ヘッドはRへ。 ②Mを読んで、ヘッドはRへ。 ➂Cを読んで、NとMとCの情報を状態遷移をうまく使って2*2*2=8通りの経路に 対して、答えが出るように仕組んでおきます。その答えA∊[0,1]でCを上書きして ヘッドはRへ。 ④Cの右は""なのでヘッドはLへ。 ⑤L方向に戻った状態でAを読むとそれが答えで、ヘッドは停止します。 2演算記号式"NMCPD"の計算はどうなるだろうか。 "NMC"まで済んでいるとしたら、 NMCの次 ④Cの右がPなので、Pを読んでヘッドはRへ。 ⑤は➂と同様にDを読んで、Dを(A,P,D)の組み合わせから答えBに書き換えて ヘッドはRへ。 ⑥は④と同様、Dの右は""なのでヘッドはLへ。 ⑦はL方向に戻った状態でAを読むとそれが答えで、ヘッドは停止します。 ヘッドが停止の反対はヘッドが動き続ける。 エラーがあると2つの状態をヘッドが行き来する。 つまり、停止できるループからエラーループにワープすると永遠に止まらない。 <推移関数を作る> 状態Q={q1,q2,q3,q4,q5,q6,q7,q8,q9} 状態の意味づけは次の通り、この通りコード化する必要はない。 q1="",q2="0",q3="1",q4="00",q5="01|10",q6="11",q7="stop", q8="err",q9="err" δ関数は、 2要素⇒2要素のしくみになる。 ヘッドの動く方向dir={R,L},書き換え文字rewrite={0,1,_} (現在状態、入力記号)=>(次の状態、rewrite、dir) エラーにならない対応表を作ってみよう。 状態q1は書き換えなしにRへ移動。行先は入力記号が0ならq2,1ならq3。 状態q2は書き換えなしにRへ移動。行先は入力記号が0ならq4(00),1ならq5(01)。  ただし、入力記号が""なら書き換えなしでLで戻り、状態をq7へ。 状態q3は書き換えなしにRへ移動。行先は入力記号が0ならq5(10),1ならq6(11)。  ただし、入力記号が""なら書き換えなしでLで戻る、状態をq7へ。 状態q4(00)は入力記号が+なら0+0=0だから、「0」に書き換えてRへ移動,状態はq2へ。 状態q4(00)は入力記号がxなら0x0=0だから、「0」に書き換えてRへ移動,状態はq2へ。 状態q5(01|10)は入力記号が+なら0+1=1だから、「1」に書き換えてRへ移動,状態はq3へ。 状態q5(01|10)は入力記号がxなら0x1=0だから、「0」に書き換えてRへ移動,状態はq2へ。 状態q6(11)は入力記号が+なら1+1=0(mod 2)だから、「0」に書き換えてRへ移動,状態はq3へ。 状態q6(11)は入力記号がxなら1x1=1だから、「1」に書き換えてRへ移動,状態はq3へ。 状態q7(stop)は入力記号を答えとして表示して、停止。 これらの状態でこれ以外の入力があると、エラーループに飛ぶ。 状態q8(err)は入力記号が何でも書き換えなしでLへ移動。 状態q9(err)は入力記号が何でも書き換えなしでRへ移動。 課題:以上の以上のM=(Q,Σ、Γ、δ、q1,F)で、F={q7}すると、"01+1x"はチューリングマシンが停止することを確かめよう。 <手動デバッグ> ヘッド位置:[現在状態、現在記号列s] 更新(現在状態、入力記号)=>(次の状態、rewrite、dir) 参考に読み取り履歴をつけました。 1:[q1,"0 1 + 1 xΛ"] 更新 (q1,0)=>(q2,_,R) 読み取り履歴0 2:[q2,"0 1 + 1 xΛ"] 更新 (q2,1)=>(q5,_,R) 読み取り履歴01 3:[q5,"0 1 + 1 xΛ"] 更新 (q5,+)=>(q3,1,R) 読み取り履歴01+ 4:[q3,"0 1 1 1 xΛ"] 更新 (q3,1)=>(q6,_,R) 読み取り履歴01+1 5:[q6,"0 1 1 1 xΛ"] 更新 (q6,x)=>(q3,1,R) 読み取り履歴01+1x 6:[q3,"0 1 1 1 1Λ"] 更新 (q3,Λ)=>(q7,_,L) 読み取り履歴01+1x"" 5:[q7,"0 1 1 1 1Λ"] 更新 (q7,1)=>停止、答え1。 読み取り履歴01+1x""1 予想通り、スタックを使わずに連続演算ができましたね。 <geogebraでコード化> 「作成」ボタン #必要な変数を用意します。クリック時のスクリプトに貼り付けてください。 pos = 1 nextPos = 1 InputStr = "01+1x" Len = Length(InputStr) Input = InputStr+"Λ" q1 = "q1" q2 = "q2" q3 = "q3" q4 = "q4" q5 = "q5" q6 = "q6" q7 = "q7" q8 = "err" q9 = "err" curQ = q1 nextState = q1 charIn = "" di = 1 dir = "R" tapeStr = Input overwrite = "_" result = "result" Process = pos + ":<q1, " + tapeStr + "> ==> q1,_.R" 「リセット」ボタン SetValue(pos, 1) SetValue(nextPos, 1) SetValue(curQ, "q1") SetValue(nextState, "q1") SetValue(charIn, "") SetValue(di, 1) SetValue(dir, "R") SetValue(tapeStr, Input) SetValue(overwrite, "_") SetValue(result, "") Process = pos + ":<q1, " + tapeStr + "> ==> q1,_.R" 「更新」ボタン #geogebraのif文はswitch文のようにかいてもよい。(マニュアルから) #L,Rの代わりに最後に行先のposを更新する。 SetValue(curQ, nextState) SetValue(pos, nextPos) SetValue(charIn, Element(tapeStr, pos)) di = If(curQ == "q1", 1, curQ == "q2", 2, curQ == "q3", 3, curQ == "q4", 4, curQ == "q5", 5,curQ == "q6", 6,curQ == "q7", 7,curQ == "q8", 8,curQ == "q9", 9) calcNext = If(di == 1,If(charIn == "0","q2",charIn == "1", "q3", "q8"), di == 2,If(charIn == "0","q4",charIn == "1", "q5",charIn=="Λ","q7","q8"), di == 3,If(charIn == "0" ,"q5",charIn=="1","q6",charIn=="Λ","q7","q8"),di==4,If((charIn == "+" || charIn=="x"),"q2","q8"),di==5,If(charIn == "+","q3",charIn=="x","q2","q8"),di==6,If((charIn == "+" || charIn=="x"),"q3","q8"),di==7,"stop",di==8,"q9",di==9,"q8") SetValue(overwrite,If(di==4,"0",di==5,If(charIn == "+","1",charIn=="x","0"),di==6,If(charIn == "+","0", charIn=="x","1"),"_")) SetValue(nextState, calcNext) SetValue(nextPos,If((curQ == "q2"||curQ == "q3") && charIn=="Λ", pos-1, pos+1)) SetValue(dir,If(nextPos > pos,"R","L")) SetValue(tapeStr,If(overwrite=="_",tapeStr,Take(tapeStr,1,pos-1) + overwrite +Take(tapeStr,pos+1,Length(tapeStr))) ) SetValue(Process, pos + ":[" + curQ + ", " + tapeStr + "] 更新==> " + nextState +","+ overwrite+","+ dir + ")" ) SetValue(result, If(curQ == "q7", "受理 (ANSWER = " + charIn + ")", result)) タイトルは「チューリングマシンのテープのようすを確かめよう」

チューリングマシンのテープのようすを確かめよう