Mercurial > hg > Members > kono > Proof > automaton
changeset 104:fba1cd54581d
use exists in cond, nfa example
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Thu, 14 Nov 2019 05:13:49 +0900 |
parents | a46e0a2a3543 |
children | a61ad3344754 |
files | a02/lecture.ind a04/lecture.ind agda/finiteSet.agda agda/nfa136.agda agda/regular-language.agda |
diffstat | 5 files changed, 310 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/a02/lecture.ind Wed Nov 13 09:04:48 2019 +0900 +++ b/a02/lecture.ind Thu Nov 14 05:13:49 2019 +0900 @@ -266,6 +266,8 @@ 以下の agda の ? の部分を埋めよ。対応する証明図をコメントで書くこと。 +最低限5題をまとめてレポートで提出せよ + <a href="agda/practice-logic.agda"> practice-logic</a> <!--- Exercise 2.2 --->
--- a/a04/lecture.ind Wed Nov 13 09:04:48 2019 +0900 +++ b/a04/lecture.ind Thu Nov 14 05:13:49 2019 +0900 @@ -4,7 +4,16 @@ 例えば、ドアの鍵がテンキーだったら、次に何を入れるかには自由度がある。 -この拡張は容易で、状態遷移関数が状態の代わりに状態のリストを返せば良い。部分集合を使っても良いが、ここではリストを使おう。 +この拡張は容易で、状態遷移関数が状態の代わりに状態のリストを返せば良い。しかし、リストを使うとかなり煩雑になる。 + +Regular Language は Concatについて閉じている。これは オートマトン A と B があった時に、z を前半 x ++ y +にわけて x を A が受理し、y を B で受理するものを、単一ののオートマトンで実現できると言う意味である。 +しかい、 これを決定性オートマトンで示すのは難しい。A ++ B の 境目がどこかを前もって予測することができないからである。 + +--Agda での非決定性オートマトン + +ここでは、部分集合を写像を使って表す。集合 Q から Bool (true または false) への写像を使う。true になる要素が +部分集合になる。すると、遷移関数は入力Σと状態から Bool への写像となる。終了条件は変わらない。 record NAutomaton ( Q : Set ) ( Σ : Set ) : Set where @@ -12,69 +21,208 @@ Nδ : Q → Σ → Q → Bool Nend : Q → Bool -これを非決定性オートマトンという。Agda では同じ名前を使いまわしすることはできない(monomorpphism)ので、nを付けた。 +これを非決定性オートマトンという。Agda では同じ名前を使いまわしすることはできない(monomorpphism)ので、Nを付けた。 <a href="../agda/nfa.agda"> nfa.agda </a> -状態の受理と遷移は以下のようになる。 +--NAutomatonの受理と遷移 + +非決定性オートマトンでは、一つの入力に対して、複数の状態が行き先になる。複数の状態を経由した経路のどれかが +入力を読み終わった後に、終了状態になれば受理されることになる。 + +このためには、状態の集合Qから条件 P : Q → Bool で true になるものを見つけ出す必要がある。 + +true になるものは複数あるので、やはり部分集合で表される。つまり、 + + exists : ( P : Q → Bool ) → Q → Bool + +このような関数を実現する必要がある。 + +もし、Q が有限集合なら、P を順々に調べていけばよい。やはり List で良いのだが、ここでは Agda の Data.Fin を使ってみよう。 + +--finiteSet + +Data.Fin だけを使って記述することもできるが、数字だけというのも味気ない。 + + record FiniteSet ( Q : Set ) { n : ℕ } : Set where + field + Q←F : Fin n → Q + F←Q : Q → Fin n + finiso→ : (q : Q) → Q←F ( F←Q q ) ≡ q + finiso← : (f : Fin n ) → F←Q ( Q←F f ) ≡ f + +という感じで、Data.Fin と 状態を対応させる。そうすると、 + + lt0 : (n : ℕ) → n Data.Nat.≤ n + lt0 zero = z≤n + lt0 (suc n) = s≤s (lt0 n) + + exists1 : (m : ℕ ) → m Data.Nat.≤ n → (Q → Bool) → Bool + exists1 zero _ _ = false + exists1 ( suc m ) m<n p = p (Q←F (fromℕ≤ {m} {n} m<n)) \/ exists1 m (lt2 m<n) p + + exists : ( Q → Bool ) → Bool + exists p = exists1 n (lt0 n) p + +という形で、 exists を記述することができる。 + +<a href="../agda/finiteSet.agda"> finiteSet.agda </a> + + +--NAutomatonの受理と遷移 + +状態の受理と遷移は exists を使って以下のようになる。 Nmoves : { Q : Set } { Σ : Set } → NAutomaton Q Σ → {n : ℕ } → FiniteSet Q {n} - → ( Q → Bool ) → Σ → Q → Bool + → ( Qs : Q → Bool ) → (s : Σ ) → Q → Bool Nmoves {Q} { Σ} M fin Qs s q = - exists fin ( λ qn → (Qs qn ∧ ( Nδ M qn s q ) )) + exists fin ( λ qn → (Qs qn /\ ( Nδ M qn s q ) )) - Naccept : { Q : Set } { Σ : Set } +Qs は Q → Bool の型を持っているので、Qs qn は true または false である。今の状態集合 Qs に含まれていて、 +Nδ M qn s q つまり、非決定オートマトン M の遷移関数 Nδ : Q → Σ → Q → Bool で true を返すものが存在すれば +遷移可能になる。 + + Naccept : { Q : Set } { Σ : Set } → NAutomaton Q Σ → {n : ℕ } → FiniteSet Q {n} → (Nstart : Q → Bool) → List Σ → Bool - Naccept M fin sb [] = exists fin ( λ q → sb q ∧ Nend M q ) + Naccept M fin sb [] = exists fin ( λ q → sb q /\ Nend M q ) Naccept M fin sb (i ∷ t ) = Naccept M fin ( Nmoves M fin sb i ) t -次の状態は状態の集合(List)になる。次の次の状態は、可能な状態の次の状態の集合を合わせた(union)ものになる。 -しかし、List で定義すると少し複雑になる。 - -部分集合を使うと簡単になる。Q の部分集合は Q → Bool で true になるものであるとする。 +Naccept では終了条件を調べる。状態の集合 sb で Nend を満たすものがあることを exists を使って調べればよい。 --例題 - transition3 : States1 → In2 → States1 → Bool - transition3 sr i0 sr = true - transition3 sr i1 ss = true - transition3 sr i1 sr = true - transition3 ss i0 sr = true - transition3 ss i1 st = true - transition3 st i0 sr = true - transition3 st i1 st = true - transition3 _ _ _ = false +例題1.36 を考えよう。状態遷移関数は以下のようになる。 + + transition136 : StatesQ → A2 → StatesQ → Bool + transition136 q1 b0 q2 = true + transition136 q1 a0 q1 = true -- q1 → ep → q3 + transition136 q2 a0 q2 = true + transition136 q2 a0 q3 = true + transition136 q2 b0 q3 = true + transition136 q3 a0 q1 = true + transition136 _ _ _ = false + +教科書にはε遷移(入力がなくても遷移できる)があるが、ここでは、ε遷移先の矢印を全部手元に持ってきてしまうという +ことしてしまう。 + + end136 : StatesQ → Bool + end136 q1 = true + end136 _ = false + + start136 : StatesQ → Bool + start136 q1 = true + start136 _ = false + + nfa136 : NAutomaton StatesQ A2 + nfa136 = record { Nδ = transition136; Nend = end136 } + +<a href=" ../agda/nfa136.agda"> 1.36 の例題 </a> + + example136-1 = Naccept nfa136 finStateQ start136( a0 ∷ b0 ∷ a0 ∷ [] ) + +最初の状態 q1 から a0 ∷ b0 ∷ a0 ∷ [] の入力を受けとる場合を考える。 - fin1 : States1 → Bool - fin1 st = true - fin1 ss = false - fin1 sr = false +a0 を受けとると、q1 にしか行けない。q1 で b0 を受けとると、q2 に移動する。q2 で a0 を受けとると、q3 か、または、 +q2 に行ける。どちらも終了状態ではないので、不受理となる。ここで、もう一つ a0 が来れば q3 から q1 に行ける。q2 +から行けないが、どれかの経路が成功すれば良いので受理となる。 + + example136-2 = Naccept nfa136 finStateQ start136( a0 ∷ b0 ∷ a0 ∷ a0 ∷ [] ) + + +--問題 + +... 作成中... + + +--非決定性オートマトンと決定性オートマトン - start1 : States1 → Bool - start1 sr = true - start1 _ = false + record Automaton ( Q : Set ) ( Σ : Set ) + : Set where + field + δ : Q → Σ → Q + aend : Q → Bool + +の Q に Q → Bool を入れてみる。 + + δ : (Q → Bool ) → Σ → Q → Bool + aend : (Q → Bool ) → Bool + +これを、 + + record NAutomaton ( Q : Set ) ( Σ : Set ) + : Set where + field + Nδ : Q → Σ → Q → Bool + Nend : Q → Bool - am2 : NAutomaton States1 In2 - am2 = record { Nδ = transition3 ; Nend = fin1} +これの Nδ と Nend から作れれば、NFA から DFA を作れることになる。 + +NFAの受理を考えると、状態の集合を持ち歩いて受理を判断している。つまり、状態の集合を状態とする Automaton を考えることになる。 + +遷移条件は、状態の集合を受けとって、条件を満たす状態の集合を返せば良い。条件は + + Nδ : Q → Σ → Q → Bool + +だった。つまり、入力の状態集合を選別する関数 f と、 Nδ との /\ を取ってやればよい。q は何かの状態、iは入力、nq は次の状態である。 + + f q /\ Nδ NFA q i nq - example2-1 = Naccept am2 finState1 start1 ( i0 ∷ i1 ∷ i0 ∷ [] ) - example2-2 = Naccept am2 finState1 start1 ( i1 ∷ i1 ∷ i1 ∷ [] ) +これが true になるものを exists を使って探し出す。 + + δconv : { Q : Set } { Σ : Set } { n : ℕ } → FiniteSet Q {n} → ( nδ : Q → Σ → Q → Bool ) → (f : Q → Bool) → (i : Σ) → (Q → Bool) + δconv {Q} { Σ} { n} N nδ f i q = exists N ( λ r → f r /\ nδ r i q ) + +ここで、( nδ : Q → Σ → Q → Bool ) は NFAの状態遷移関数を受けとる部分である。 + +終了条件は + + f q /\ Nend NFA q ) +' +で良い。 これが true になるものを exists を使って探し出す。 + +Q が FiniteSet Q {n} であれば - fin0 : States1 → Bool - fin0 st = false - fin0 ss = false - fin0 sr = false + subset-construction : { Q : Set } { Σ : Set } { n : ℕ } → FiniteSet Q {n} → + (NAutomaton Q Σ ) → (astart : Q ) → (Automaton (Q → Bool) Σ ) + subset-construction {Q} { Σ} {n} fin NFA astart = record { + δ = λ f i → δconv fin ( Nδ NFA ) f i + ; aend = λ f → exists fin ( λ q → f q /\ Nend NFA q ) + } + +という形で書くことができる。状態の部分集合を作っていくので、subset construction と呼ばれる。 + + λ f i → δconv fin ( Nδ NFA ) f i +は + λ f i q → δconv fin ( Nδ NFA ) f i q + +であることに注意しよう。これは、Curry 化の省略になっている。省略があるので、δ : (Q → Bool ) → Σ → Q → Bool という形に見える。 + +<a href=" ../agda/sbconst2.agda"> subset construction </a> + +--subset constructionの状態数 - test0 : Bool - test0 = exists finState1 fin0 +実際にこれを計算すると、状態数 n のNFAから、最大、2^n の状態を持つDFAが生成される。しかし、この論理式からそれを +自明に理解することは難しい。しかし、f は Q → Bool なので、例えば、3状態でも、 - test1 : Bool - test1 = exists finState1 fin1 + q1 q2 q3 + false false false + false false true + false true false + false true true + true false false + true false true + true true false + true true true - test2 = Nmoves am2 finState1 start1 +という8個の状態を持つ。exists は、このすべての場合を尽くすように働いている。 +アルゴリズムとしてこのまま実装すると、 exists が必要な分だけ計算するようになっている。これは結構遅い。 +前もって、可能な状態を Automaton として探し出そうとすると、 指数関数的な爆発になってしまう。 + +実際に、指数関数的な状態を作る NFA が存在するので、これを避けることはできない。 +
--- a/agda/finiteSet.agda Wed Nov 13 09:04:48 2019 +0900 +++ b/agda/finiteSet.agda Thu Nov 14 05:13:49 2019 +0900 @@ -10,6 +10,7 @@ open import logic open import nat open import Data.Nat.Properties hiding ( _≟_ ) +open import Data.List open import Relation.Binary.HeterogeneousEquality as HE using (_≅_ ) @@ -38,6 +39,15 @@ exists1 ( suc m ) m<n p = p (Q←F (fromℕ≤ {m} {n} m<n)) \/ exists1 m (lt2 m<n) p exists : ( Q → Bool ) → Bool exists p = exists1 n (lt0 n) p + + list1 : (m : ℕ ) → m Data.Nat.≤ n → (Q → Bool) → List Q + list1 zero _ _ = [] + list1 ( suc m ) m<n p with bool-≡-? (p (Q←F (fromℕ≤ {m} {n} m<n))) true + ... | yes _ = Q←F (fromℕ≤ {m} {n} m<n) ∷ list1 m (lt2 m<n) p + ... | no _ = list1 m (lt2 m<n) p + to-list : ( Q → Bool ) → List Q + to-list p = list1 n (lt0 n) p + equal? : Q → Q → Bool equal? q0 q1 with F←Q q0 ≟ F←Q q1 ... | yes p = true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agda/nfa136.agda Thu Nov 14 05:13:49 2019 +0900 @@ -0,0 +1,93 @@ +module nfa136 where + +open import logic +open import nfa +open import automaton hiding ( StatesQ ) +open import Data.List +open import finiteSet +open import Data.Fin +open import Relation.Binary.PropositionalEquality hiding ( [_] ) + +data StatesQ : Set where + q1 : StatesQ + q2 : StatesQ + q3 : StatesQ + +data A2 : Set where + a0 : A2 + b0 : A2 + +finStateQ : FiniteSet StatesQ +finStateQ = record { + Q←F = Q←F + ; F←Q = F←Q + ; finiso→ = finiso→ + ; finiso← = finiso← + } where + Q←F : Fin 3 → StatesQ + Q←F zero = q1 + Q←F (suc zero) = q2 + Q←F (suc (suc zero)) = q3 + F←Q : StatesQ → Fin 3 + F←Q q1 = zero + F←Q q2 = suc zero + F←Q q3 = suc (suc zero) + finiso→ : (q : StatesQ) → Q←F (F←Q q) ≡ q + finiso→ q1 = refl + finiso→ q2 = refl + finiso→ q3 = refl + finiso← : (f : Fin 3) → F←Q (Q←F f) ≡ f + finiso← zero = refl + finiso← (suc zero) = refl + finiso← (suc (suc zero)) = refl + finiso← (suc (suc (suc ()))) + +transition136 : StatesQ → A2 → StatesQ → Bool +transition136 q1 b0 q2 = true +transition136 q1 a0 q1 = true -- q1 → ep → q3 +transition136 q2 a0 q2 = true +transition136 q2 a0 q3 = true +transition136 q2 b0 q3 = true +transition136 q3 a0 q1 = true +transition136 _ _ _ = false + +end136 : StatesQ → Bool +end136 q1 = true +end136 _ = false + +start136 : StatesQ → Bool +start136 q1 = true +start136 _ = false + +nfa136 : NAutomaton StatesQ A2 +nfa136 = record { Nδ = transition136; Nend = end136 } + +example136-1 = Naccept nfa136 finStateQ start136( a0 ∷ b0 ∷ a0 ∷ a0 ∷ [] ) + +example136-0 = Naccept nfa136 finStateQ start136( a0 ∷ [] ) + +example136-2 = Naccept nfa136 finStateQ start136( b0 ∷ a0 ∷ b0 ∷ a0 ∷ b0 ∷ [] ) + +open FiniteSet + +nx : (StatesQ → Bool) → (List A2 ) → StatesQ → Bool +nx now [] = now +nx now ( i ∷ ni ) = (Nmoves nfa136 finStateQ (nx now ni) i ) + +example136-3 = to-list finStateQ start136 +example136-4 = to-list finStateQ (nx start136 ( a0 ∷ b0 ∷ a0 ∷ [] )) + +open import sbconst2 + +fm136 : Automaton ( StatesQ → Bool ) A2 +-- fm136 = record { δ = λ qs q → transition136 {!!} {!!} ; aend = λ qs → exists finStateQ end136 } +fm136 = subset-construction finStateQ nfa136 q1 + +open NAutomaton + +lemma136 : ( x : List A2 ) → Naccept nfa136 finStateQ start136 x ≡ accept fm136 start136 x +lemma136 x = lemma136-1 x start136 where + lemma136-1 : ( x : List A2 ) → ( states : StatesQ → Bool ) + → Naccept nfa136 finStateQ states x ≡ accept fm136 states x + lemma136-1 [] _ = refl + lemma136-1 (h ∷ t) states = lemma136-1 t (δconv finStateQ (Nδ nfa136) states h)
--- a/agda/regular-language.agda Wed Nov 13 09:04:48 2019 +0900 +++ b/agda/regular-language.agda Thu Nov 14 05:13:49 2019 +0900 @@ -282,32 +282,34 @@ open Found - data AB-state (nq : states A ∨ states B → Bool ) (qa : states A) (x : List Σ) : Set (Level.suc Level.zero) where - state-A : ((q : states A ∨ states B ) → nq q ≡ true → q ≡ case1 qa ) → AB-state nq qa x - state-AB : ((q : states A ∨ states B ) → ( nq q ≡ true ) → - ( (q ≡ case1 qa) ∨ - ( ({ qa' : states A} → (¬ (q ≡ case1 qa'))) ∧ ({qb : states B} → nq (case2 qb) ≡ true → ( accept (automaton B) qb x ≡ false ) )))) - → AB-state nq qa x + data AB-state (nq : states A ∨ states B → Bool ) (x : List Σ) : Set (Level.suc Level.zero) where + state-A : ((q : states A ∨ states B ) → nq q ≡ true → (exists (afin A) (λ qa → equal? finab q (case1 qa) ) ≡ true )) → AB-state nq x + state-AB : ((q : states A ∨ states B ) → nq q ≡ true → (exists (afin B) (λ qb → equal? finab q (case2 qb) /\ accept (automaton B) qb x ) ≡ true )) + → AB-state nq x open AB-state + + start-eq : (q : states A ∨ states B) → Concat-NFA-start A B q ≡ true → exists (afin A) (λ qa → equal? finab q (case1 qa)) ≡ true + start-eq q eq with equal→refl finab eq + ... | refl = found (afin A) (astart A) eq + contain-A : (x : List Σ) → (nq : states A ∨ states B → Bool ) → (fn : Naccept NFA finab nq x ≡ true ) - → (qa : states A ) → AB-state nq qa x + → (qa : states A ) → AB-state nq x → split (accept (automaton A) qa ) (contain B) x ≡ true contain-A [] nq fn qa cond with found← finab fn | found-q (found← finab fn) | cond | inspect found-q (found← finab fn) - contain-A [] nq fn qa cond | S | s | state-A nq=t | record { eq = refl } with nq=t (found-q S) (bool-∧→tt-0 (found-p S)) - ... | refl = bool-∧→tt-1 (found-p S) + contain-A [] nq fn qa cond | S | s | state-A q=qa | record { eq = refl } = {!!} + -- ... | refl = bool-∧→tt-1 (found-p S) contain-A [] nq fn qa cond | S | s | state-AB cond-b | _ with cond-b (found-q S) (bool-∧→tt-0 (found-p S)) - contain-A [] nq fn qa cond | S | s | state-AB cond-b | _ | case1 refl = bool-∧→tt-1 (found-p S) - contain-A [] nq fn qa cond | S | case2 qb | state-AB cond-b | record { eq = refl } | case2 accept-B = ⊥-elim ( lemma11 (proj2 accept-B) ) where - lemma11 : ( nq (case2 qb ) ≡ true → aend (automaton B) qb ≡ false ) → ⊥ - lemma11 accept-B = ¬-bool ( accept-B (bool-∧→tt-0 (found-p S))) (bool-∧→tt-1 (found-p S )) - contain-A [] nq fn qa cond | S | case1 qa' | state-AB cond-b | record { eq = refl } | case2 accept-B = ⊥-elim ( (proj1 accept-B ) refl ) + contain-A [] nq fn qa cond | S | case2 qb | state-AB cond-b | record { eq = refl } | q=qb = ⊥-elim (lemma11 {!!}) where + lemma11 : ( {qb : states B } → ((found-q S) ≡ case2 qb) ∧ ((aend (automaton B) qb ) ≡ false)) → ⊥ + lemma11 q=qb = ¬-bool (proj2 q=qb ) (bool-∧→tt-1 (found-p S )) + contain-A [] nq fn qa cond | S | (case1 qa') | state-AB cond-b | record { eq = refl } | q=qb = {!!} contain-A (h ∷ t) nq fn qa cond with bool-≡-? ((aend (automaton A) qa) /\ accept (automaton B) (δ (automaton B) (astart B) h) t ) true ... | yes eq = bool-or-41 eq ... | no ne = bool-or-31 (contain-A t (Nmoves NFA finab nq h) fn (δ (automaton A) qa h) {!!} ) where lemma10 : Naccept NFA finab (equal? finab (case1 (astart A))) x ≡ true → split (contain A) (contain B) x ≡ true - lemma10 CC = contain-A x (Concat-NFA-start A B ) CC (astart A) {!!} where + lemma10 CC = contain-A x (Concat-NFA-start A B ) CC (astart A) (state-A start-eq ) closed-in-concat← : contain (M-Concat A B) x ≡ true → Concat (contain A) (contain B) x ≡ true closed-in-concat← C with subset-construction-lemma← finab NFA (case1 (astart A)) x C