Turing Machine

Menu

Turing Machine は無限長のテープを持つAutomatonである。これは、stack を二つ持つ Automaton として構成できる。

turing.agda テープへの操作は、書き込みと移動である。

    data Write   (  Σ : Set  ) : Set  where
       write   : Σ → Write  Σ
       wnone   : Write  Σ
    data Move : Set  where
       left   : Move  
       right  : Move  
       mnone  : Move  

Turing machineは状態と入力で、このコマンド二つを選択する。

    record TM ( Q : Set ) ( Σ : Set  ) 
           : Set  where
        field
            automaton : Automaton  Q Σ
            tδ : Q → Σ → Write  Σ  ×  Move 
            tnone :  Σ
        taccept : Q → List  Σ → ( Q × List  Σ × List  Σ )
        taccept q L = move1 (aend automaton) tnone (δ automaton) tδ q L []

書き込みと移動を二つのstack( List Σ)に対する関数として定義する。

    {-# TERMINATING #-}
    move : (q : Q ) ( L : List  Σ ) ( L : List   Σ ) → ( Q × List  Σ × List  Σ )
    move q L [] = move q  L  ( tnone  ∷ [] ) 
    move q [] R = move q  ( tnone  ∷ [] )  R 
    move q ( LH  ∷ LT ) ( RH ∷ RT ) with  tδ q LH  
    ... | nq , write x , left  = ( nq , ( RH ∷ x  ∷ LT ) , RT )
    ... | nq , write x , right = ( nq , LT , ( x  ∷ RH  ∷ RT ) )
    ... | nq , write x , mnone = ( nq , ( x  ∷ LT ) , (  RH ∷ RT ) )
    ... | nq , wnone , left    = ( nq , ( RH  ∷ LH  ∷ LT ) , RT  )
    ... | nq , wnone , right   = ( nq ,  LT , ( LH  ∷ RH  ∷ RT ) )
    ... | nq , wnone , mnone   = ( nq , ( LH  ∷ LT ) , (  RH ∷ RT )  )
    {-# TERMINATING #-}
    move-loop : (q : Q ) ( L : List  Σ ) ( L : List   Σ ) → ( Q × List  Σ × List  Σ )
    move-loop  q L R with tend q
    ... | true = ( q , L , R )
    ... | flase = move-loop ( proj₁ next ) ( proj₁ ( proj₂ next ) )  ( proj₂  ( proj₂ next ) )
      where
        next = move  q  L  R 
    {-# TERMINATING #-}
    move0 : (q : Q ) ( L : List  Σ ) ( L : List   Σ ) → ( Q × List  Σ × List  Σ )
    move0  q L R with tend q
    ... | true = ( q , L , R )
    move0 q L [] | false = move0 q  L  ( tnone  ∷ [] ) 
    move0 q [] R | false = move0 q  ( tnone  ∷ [] )  R 
    move0 q ( LH  ∷ LT ) ( RH ∷ RT ) | false with  tδ q LH  
    ... | nq , write x , left  = move0 nq ( RH ∷ x  ∷ LT ) RT 
    ... | nq , write x , right = move0 nq LT ( x  ∷ RH  ∷ RT ) 
    ... | nq , write x , mnone = move0 nq ( x  ∷ LT ) (  RH ∷ RT ) 
    ... | nq , wnone , left    = move0 nq ( RH  ∷ LH  ∷ LT ) RT  
    ... | nq , wnone , right   = move0 nq  LT ( LH  ∷ RH  ∷ RT ) 
    ... | nq , wnone , mnone   = move0 nq ( LH  ∷ LT ) (  RH ∷ RT )  
    {-# TERMINATING #-}
    taccept : List  Σ → ( Q × List  Σ × List  Σ )
    taccept L = move0 tstart L []


Turing Machine の例題

    data CopyStates : Set where
       s1 : CopyStates
       s2 : CopyStates
       s3 : CopyStates
       s4 : CopyStates
       s5 : CopyStates
       H  : CopyStates
    Copyδ :  CopyStates →  ℕ  → CopyStates × ( Write  ℕ ) × Move 
    Copyδ s1 0  = (H    , wnone       , mnone )
    Copyδ s1 1  = (s2   , write 0 , right )
    Copyδ s2 0  = (s3   , write 0 , right )
    Copyδ s2 1  = (s2   , write 1 , right )
    Copyδ s3 0  = (s4   , write 1 , left )
    Copyδ s3 1  = (s3   , write 1 , right )
    Copyδ s4 0  = (s5   , write 0 , left )
    Copyδ s4 1  = (s4   , write 1 , left )
    Copyδ s5 0  = (s1   , write 1 , right )
    Copyδ s5 1  = (s5   , write 1 , left )
    Copyδ H  _  = (H    , wnone   , mnone )
    Copyδ _  (suc (suc _))      = (H    , wnone       , mnone )
    copyTM : TM CopyStates ℕ
    copyTM = record {
            automaton = record { δ = λ q i → proj₁ (Copyδ q i) ; aend = tend }
         ;  tδ = λ q i → proj₂ (Copyδ q i )
         ;  tnone =  0
      } where
          tend : CopyStates →  Bool
          tend H = true
          tend _ = false

Automaton と違って入力文字列はテープ(stack)上に置かれている。

終了状態に遷移すると計算は終了する。

つまり入力と同時に計算が終了するとは限らない。


Turing machine の停止問題


Universal Turing Machine

文字列 x を判定する Turinging machine tm(x) があるとする。

    record TM : Set where
       field
          tm : List Bool → Maybe Bool

tm はプログラムなので、文字列である。tm をその文字列とする。tm が Turing machine として x を受け入れるかどうかを判定するTuring machine

    record UTM : Set where
       field
          utm : TM
          encode : TM → List Bool
          is-tm : (t : TM) → (x : List Bool) → tm utm (encode t ++ x ) ≡ tm t x

を構成することができる。utm は引数をtとxの二つ持つが、encode t ++ x と結合した単一の文字列だと思えば単一引数になる。

utm は interpreter だと思えば良い。tm, utm は、停止してT/Fを返すか、停止しないかである。

             just true  受け入れない
             ust false  受け入れる
             nothing  止まらない

実際に utm を構成した例がある。

utm.agda これには足りないものが結構ある。実際に utm は正しく動くのか? ( record UTM を構成できるのか?)


Turinng Machine の停止性の判定

halt(tm,x) は、以下のように定義される。これはまだ、Turing machine であるとは限らない。

    record Halt : Set where
       field
          halt :  (t : TM ) → (x : List Bool ) → Bool
          is-halt :     (t : TM ) → (x : List Bool ) → (halt t x ≡ true )  ⇔ ( (just true ≡ tm t x ) ∨ (just false ≡ tm t x ) )
          is-not-halt : (t : TM ) → (x : List Bool ) → (halt t x ≡ false ) ⇔ ( nothing ≡ tm t x )

つまり、

  halt(tm,x) = 0  tm(x) が止まらない (halt が停止しない)    (1)
  halt(tm,x) = 1  tm(x) が止まる                            (2)

halt(tm+x) 自体は Bool 、つまり停止しないことはないとする。こういう Turing machine があったらどうなるだろうか?


対角線論法

0,1 からなる無限長の文字列を考えよう。これを順に拾っていく。どんな順序で拾っても、自然数の範囲では拾い切れないことをしまそう。

拾った順に、文字列を並べる。

    00000000000000000000000000100000....
    01000000000000000000000000001000....
    01100000000000000000000000000100....
    01110000000000000000000000000010....
    01111000000000000000000000000000....
    01111100000000000000000000000000....
    01011100000000000000000000000000....
            ...
            ...
            ...

行y列xの文字を v(x,y) とする。これは 0 か 1 である。上の文字列の対角線の要素は v(x,x) となる。以下の . が対角線要素になる。

    .0000000000000000000000000100000....
    0.000000000000000000000000001000....
    01.00000000000000000000000000100....
    011.0000000000000000000000000010....
    0111.000000000000000000000000000....
    01111.00000000000000000000000000....
    010111.0000000000000000000000000....
            ...
            ...
            ...

1-v(x,x) を考えると、

    1000001 ...

となる。この文字列は、最初に拾った文字列のどれとも、v(x,x)のところで異なる。つまり拾った文字列とは異なる文字列が必ず存在する。

これは、順に取ってくるという方法では、無限長の文字列は尽くせないということを意味する。可算回と呼ぶ。


2^N

この無限長の文字列は、自然数Nから{0,1} の写像と考えられる。あるいは、自然数Nの部分集合に1、それ以外に0を割り振ったものである。これを 2^N と書く。

    自然数の部分集合全体
    自然数から{0,1}への写像の全体

である。自然数に1対1対応する集合を可算集合という。これらの集合は可算集合ではないことが対角線論法からわかる。

この文字列の先頭に 0. を付けると、0から1 の実数を表す。実数の集合は可算集合でないことがわかる。

また、可算集合でなくても順序は持つこともわかる。実数などは非可算集合と呼ぶ。


Agda による対角線論法

    record HBijection {n m : Level} (R : Set n) (S : Set m) : Set (n Level.⊔ m)  where
       field
           fun←  :  S → R
           fun→  :  R → S
           fiso← : (x : R)  → fun← ( fun→ x )  ≡ x 

fiso→ : (x : S ) → fun→ ( fun← x ) ≡ x もあるのだが、ここでは使わない。

    diag : {S : Set }  (b : HBijection  ( S → Bool ) S) → S → Bool
    diag b n = not (fun← b n n)

これで対角線部分の否定を采関数を定義する。

    diagonal : { S : Set } → ¬ HBijection  ( S → Bool ) S
    diagonal {S} b = diagn1 (fun→ b (diag b) ) refl where
        diagn1 : (n : S ) → ¬ (fun→ b (diag b) ≡ n ) 
        diagn1 n dn = ¬t=f (diag b n ) ( begin
               not (diag b n)
            ≡⟨⟩
               not (not fun← b n n)
            ≡⟨ cong (λ k → not (k  n) ) (sym (fiso← b _)) ⟩
               not (fun← b (fun→ b (diag b))  n)
            ≡⟨ cong (λ k → not (fun← b k n) ) dn ⟩
               not (fun← b n n)
            ≡⟨⟩
               diag b n 
            ∎ ) where open ≡-Reasoning

それに対して、HBijection ( S → Bool ) S があるとすると、

        not (diag b n) ≡ diag b n

となっている。証明の各段階を追ってみよ。


halt が tm ではあり得ないこの証明

halt の否定を考えよう。

  neg(tm) = 1  halt(tm,tm) が0                     (3)
  neg(tm) = ⊥  halt(tm,tm) が1                     (4)

つまり、halt(tm,tm) が1 の時、つまり、tm(tm) が停止する時には、neg(tm) は停止しない。neg 自体は halt があればtmとして簡単に作れる。

  neg(neg) = 1

かどうか調べよう。ここで 引数の neg は Turing machine neg を表す文字列である。

まず、neg(neg) =1 と仮定する。(3) から、

  halt(neg,neg) が 0

なことがわかる。つまり、neg(neg) は停止しない。neg(neg) = ⊥ 。これは最初の仮定 neg(neg)=1に矛盾する。

逆に、

  neg(neg) = ⊥

とすると、(4) から、

  halt(neg,neg) = 1

つまり、neg(neg) は止まる。つまり、neg(neg)=1。これも矛盾。

つまり、halt(tm,x) が⊥にならないようなものは存在しない。

つまり、Turinng machine が停止するかどうかを、必ず判定できる停止する Turing machine は存在しない。


Agda での構成

Halt は languageなので、存在すれば UTM で simulation できることに注意しよう。

Halt と UTM から HBijection (List Bool → Bool) (List Bool) を示す。

    TNL : (halt : Halt ) → (utm : UTM) → HBijection (List Bool → Bool) (List Bool)

すると、

    TNL1 : UTM → ¬ Halt 
    TNL1 utm halt = diagonal ( TNL halt utm )

となる。TNL は以下のように構成する。

    λ tm x → Halt.halt halt (UTM.utm utm) (tm ++ x)

は (List Bool → Bool) → List Bool になっている。

     h1 : (h : List Bool → Bool) → (x : List Bool ) → Maybe Bool
     h1 h x with h x
     ... | true =  just true
     ... | false = nothing 
     λ h  → encode utm record { tm = h1 h }

は、List Bool → (List Bool → Bool である。

これから、fiso← を導けば良い。

    TNL : (halt : Halt ) → (utm : UTM) → HBijection (List Bool → Bool) (List Bool)
    TNL halt utm = record {
           fun←  = λ tm x → Halt.halt halt (UTM.utm utm) (tm ++ x)
         ; fun→  = λ h  → encode utm record { tm = h1 h } 
         ; fiso← = λ h →  f-extensionality (λ y → TN1 h y )
      } where
         open ≡-Reasoning
         h1 : (h : List Bool → Bool) → (x : List Bool ) → Maybe Bool
         h1 h x with h x
         ... | true =  just true
         ... | false = nothing
         tenc : (h : List Bool → Bool) → (y : List Bool) → List Bool
         tenc h y = encode utm (record { tm = λ x → h1 h x }) ++ y
         h-nothing : (h : List Bool → Bool) → (y : List Bool) → h y ≡ false → h1 h y ≡ nothing
         h-nothing h y eq with h y
         h-nothing h y refl | false = refl
         h-just : (h : List Bool → Bool) → (y : List Bool) → h y ≡ true → h1 h y ≡ just true
         h-just h y eq with h y
         h-just h y refl | true = refl
         TN1 :  (h : List Bool → Bool) → (y : List Bool ) → Halt.halt halt (UTM.utm utm) (tenc h y) ≡ h y
         TN1 h y with h y | inspect h y
         ... | true  | record { eq = eq1 } = begin
            Halt.halt halt (UTM.utm utm)  (tenc h y) ≡⟨ proj2 (is-halt halt (UTM.utm utm) (tenc h y) ) (case1 (sym tm-tenc)) ⟩
            true ∎  where
              tm-tenc :  tm (UTM.utm utm) (tenc h y) ≡ just true
              tm-tenc = begin
                  tm (UTM.utm utm) (tenc h y)  ≡⟨  is-tm utm _ y ⟩
                  h1 h y ≡⟨ h-just h y eq1  ⟩
                  just true  ∎  
         ... | false | record { eq = eq1 } = begin
            Halt.halt halt (UTM.utm utm)  (tenc h y) ≡⟨ proj2 (is-not-halt halt (UTM.utm utm) (tenc h y) ) (sym tm-tenc) ⟩
            false ∎  where
              tm-tenc :  tm (UTM.utm utm) (tenc h y) ≡ nothing
              tm-tenc = begin
                  tm (UTM.utm utm) (tenc h y)  ≡⟨  is-tm utm _ y ⟩
                  h1 h y ≡⟨  h-nothing h y eq1 ⟩
                  nothing  ∎  
         -- the rest of bijection means encoding is unique
         -- fiso→ :  (y : List Bool ) → encode utm record { tm = λ x →  h1 (λ tm → Halt.halt halt (UTM.utm utm) tm  ) x } ≡ y

f-extensionality は関数の入出力がすべて一致すれば関数自体が等しいという仮定である。これは Agda では証明できない。

Turing machine が停止するかどうかではなく、論理の真か偽か限定しても同じ問題がある。ただし、入力に自分自身を記述できる能力がある論理の場合である。自然数を使って論理自体を記述することができるので、自然数論を論理が含んでいるかどうかが、決定不能問題を含んでいるかどうかの鍵となる。

HBijection を使わずに diag1 を直接つかって証明することもできる。この場合は halt が UTM で simulation できることから矛盾がでる。


さまざまな決定不能問題

多くの問題は Turing machine の停止性に帰着できる。

    ディオファントス方程式
    文脈依存文法の判定
    Automaton を含む方程式

Shinji KONO / Mon Jan 17 17:28:03 2022