NFAをシミュレートする


15

非決定性有限オートマトンは、タプル有限状態機械である複数の状態にマッピングされます。すなわち。DFAの通常のδ Q × Σ Q遷移関数を別の関数Δ Q × Σ PQ に置き換えます。(state,symbol)δ:Q×ΣQ Δ:Q×ΣP(Q)

NFAが何であるかがわかっている場合は、次のセクションをスキップできます。

正式な定義

NFAは、

  • 状態の有限集合Q
  • 記号の有限集合Σ
  • 遷移関数Δ:Q×ΣP(Q)
  • は初期状態q0Q
  • 最終状態の集合FQ

マシンは中から始まりと記号の有限列読み込みのw Σ *を、各シンボルのために、それは同時に、現在の状態を遷移関数機能を適用すると、現在の状態の集合に状態のそれぞれの新しいセットを追加します。q0wΣ

チャレンジ

この課題のために、我々は無視するまたアルファベットは、常に文字(小文字)になり、それを簡単にするために、Z及び状態の集合となり、{ 0 ... N }整数いくつかの非負のためのN。初期状態は常に0です。F a z {0N}N0

単語を考えるとNFAの説明、あなたのタスクは、すべての最終状態を決定することです。w{az}

文字列と次の説明を考慮してください。abaab

state, symbol, new-states
0, 'a', [1]
1, 'a', [0]
1, 'b', [1,2]

マシンは起動しますq0=0

  1. 読む:新しい状態{ 1 }a{1}
  2. 読み取り新しい状態{ 1 2 }b{1,2}
  3. 読む:新しい状態{ 0 }a{0}
  4. 読む:新しい状態{ 1 }a{1}
  5. 読み取り新しい状態{ 1 2 }b{1,2}

最終状態したがって、出力は次のようになりので{1,2}

注:ステップ(2)の状態の遷移にマッピング説明は唯一の非空集合への遷移を含んでいます。2

ルール

入力は、文字列とNFAの何らかの種類の説明で構成されます(遷移なし):ϵ

  • 入力文字列は常に{ az } ∗の要素になります{az}
  • 有効な入力(に限定されません):
    • タプル/リストのリスト/配列
    • 改行で区切られた入力
  • NFAの説明には、結果として空でないセットを持つ遷移のみが含まれます
    • 結果が同じ場合、同じ文字を使用してルールを省略できます(例:ルール0,'a',[1,2]および0,'b',[1,2]0,"ab",[1,2]
    • 各ルールを個別に取る0,'a',[1,2]ことができます(例:ルールは0,'a',[1]and 0,'a',[2]
  • 必要に応じて大文字を選択できます
  • 入力として状態の数を取ることができます
  • 入力のある種の順序付けを想定することができます(例:状態またはシンボルによる順序付け)

出力は、最終状態のリスト/セット/改行で区切られた出力などになります

  • 順序は関係ありません
  • 重複なし(セットなので)

テストケース

これらの例は、形式になりますタプルのリストです:description word -> statesdescription(state,symbol,new-states)

[]  "x" -> []
[]  "" -> [0]
[(0,'a',[1]),(1,'a',[0]),(1,'b',[1,2])]  "abaab" -> [1,2]
[(0,'a',[1]),(1,'a',[0]),(1,'b',[1,2])]  "abc" -> []
[(0,'p',[0,1]),(0,'g',[2]),(1,'c',[1]),(1,'g',[4]),(1,'p',[2]),(2,'c',[0])]  "ppcg" -> [2,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "foobar" -> [0,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "fooooooobar" -> [0,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "fobarfo" -> [1,2]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "foobarrf" -> [1]
[(0,'d',[1,2]),(1,'u',[2]),(2,'u',[2,3]),(2,'p',[3]),(3,'p',[3])]  "dup" -> [3]
[(0,'a',[0,2]),(0,'b',[3]),(1,'a',[1]),(1,'b',[1]),(2,'b',[1,4]),(4,'b',[2])]  "aab" -> [3,1,4]
[(0,'a',[0,2]),(0,'b',[3]),(1,'a',[1]),(1,'b',[1]),(2,'b',[1,4]),(4,'b',[2])]  "abb" -> [1,2]


3
これは、私のオートマトンコースから怖い思い出を呼び戻します。
ドンサウザンド

我々は、例えば、それぞれの新しい状態のための個々の行で入力を取ることができ、これは加工さ例えば?
-ovs

@ovs:どうぞ!
ბიმო

回答:


7

Haskell、66バイト

import Data.List
f d=foldl(\s c->nub[r|(y,r)<-d,g<-s,(g,c)==y])[0]

オンラインでお試しください!


以下のためにあなたは、インポートを取り除くことができnubますがする状態を想定した場合[Int]、その後、あなたはそれぞれのチェックに使用できる[0..]:有限である60バイト
ბიმო

@BWOこれは、すべてIntのs および現在のすべての状態を反復処理するため、依然として重複した状態を生成します。(テスト目的に変更さ[0..][0..3]ましたが、違いはありませんよね?)
ovs

ええ、私は考えていたではないことを確認何..ネヴァーマインド...
ბიმო

4

Brachylog、42バイト

,0{hẸ&t|∋₁B∋IhJ&tJ&hhC∧I∋₁C∧It∋S&hb;B,S↰}ᵘ

[string、nfa]として入力します。nfaは状態遷移のリストです[初期状態、文字、リストとしての新しい状態]

説明

,0                                              # Append 0 to the input (initial state)
  {                                      }ᵘ     # Find all unique outputs
   h                                            # if first element (string)
    Ẹ                                           #   is empty
     &t                                         #   then: return last element (current state)
       |                                        #   else:
        ∋₁B                                     #       save the state transitions in "B"
           ∋I                                   #       take one of these transitions, save in "I"
             hJ                                 #       take the initial state requirement, store in "J"
               &tJ                              #       make sure "J" is actually the current state
                  &hhC                          #       Save first char of string in C
                      ∧I∋₁C                     #       make sure the char requirement for the state transition is the current char
                           ∧It∋S                #       Make "S" equal to one of the new states
                                &hb             #       Behead the string (remove first char)
                                   ;B,S         #       Add B (the state transitions) and S (the new state)
                                       ↰        #       recur this function

オンラインでお試しください!


4

Brachylog v2、31バイト

{b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz{∋ᵈ}ᵐtt}ᵘ

オンラインでお試しください!またはより複雑な例で

Brachylogは、この種の問題に非常に優れており、2つの独立した入力と1つの出力を必要とする問題に非常に不利です。このプログラムのほとんどすべては配管工事です。

入力形式は、2つの要素を含むリストです。最初の要素は状態遷移のリスト([oldState, symbol, newState])、2番目の要素はシンボルのリストです。私はもともと、このプログラムをシンボルの文字コードで動作するように計画していました(Brachylogの文字列処理が時々少し奇妙になる可能性があるため)が、文字も動作することがわかりました(入力文字列を文字列)。状態とシンボルのペアが複数の異なる状態に遷移できる場合、それに対処するために複数の遷移を記述します。

説明

{b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz{∋ᵈ}ᵐtt}ᵘ
{                            }ᵘ   Find all distinct outputs that can result from:
 b                                  taking the input minus its first element,
  ,Ȯ                                appending a singleton list (i.e. an element)
    ,Ȯ                              then appending that same element again
      \                             and transposing;
       c                            then concatenating the resulting lists,
        ↔,0↔                        prepending a 0,
            ġ₃                      grouping into blocks of 3 elements
              k                       (and discarding the last, incomplete, block),
               H&                   storing that while we
                 h                  take the first input element,
                  g  z              pair a copy of it with each element of
                   ;H                 the stored value,
                      {  }ᵐ         assert that for each resulting element
                       ∋ᵈ             its first element contains the second,
                        ᵈ ᵐ           returning the list of second elements,
                            t       then taking the last element of
                           t          the last element.

プログラムの一部のバージョンが生成するものを確認することで、おそらくこれに従う方が簡単でしょう。毎回次の入力を使用します。

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]

このプログラムのいくつかのプレフィックスの出力を確認できます。

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ
[[97,98,97,97,98],L,L]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\
[[97,A,A],[98,B,B],[97,C,C],[97,D,D],[98,E,E]]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔
[0,97,A,A,98,B,B,97,C,C,97,D,D,98,E,E]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔ġ₃k
[[0,97,A],[A,98,B],[B,97,C],[C,97,D],[D,98,E]]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz
[[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[0,97,A]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[A,98,B]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[B,97,C]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[C,97,D]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[D,98,E]]]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz{∋ᵈ}ᵐ
e.g. [[0,97,1],[1,98,1],[1,97,0],[0,97,1],[1,98,1]]

ここでの最初の例では、L最初は未知の要素ですが、を介して転置すると\、Brachylogは、入力と同じ長さのリストのみであると認識します。最後の例は非決定的です。Brachylog自体の非決定性を使用して、NFAの非決定性をモデリングしています。

可能な改善

ここでの構文の一部↔,0↔、特にの混乱はH&hg;Hz{…ᵈ}ᵐ、かなり不格好です。これを簡潔に表現する方法があったとしても、私は驚かないでしょう。

{∋ᵈ}ᵐそれ自体はかなり疑わしい構造です-あなたはただ書くことができると期待しています∋ᵈᵐ-しかし、それは何らかの理由で解析しません。


∋ᵈᵐ理論的には複数文字のメタ述語名を使用できるように実装されているため、解析されません(単一シンボルの可能性がなくなった場合)。実際には、現在使用されていません。
18

3

Python 3、103 80バイト

@BWOに感謝

w=lambda n,f,a={0}:w(n,f[1:],{y for(x,c,y)in n if c==f[0]and{x}&a})if''<f else a

TIO

前の「エレガントな」リストの内包表記(103バイト):

def w(a,b):
    q=[0]
    for c in b:q=[j for s in q for i in a if s in i if i[1]==c for j in i[2]]
    return q

Python 3に欠けているのは残念reduceですが、再帰と実際のセットを使用すると、80バイトになります
ბიმო

@BWOの素敵は、おかげで、笑ところで上記示すために私の新しいお気に入りの例のPythonのコードです...巨大なリストの内包表記は、道より多くの彼らが必要以上に私を楽しませる一行
Quintec

私はあなたが交換することにより2つのバイトを保存することができると思いますif''<fif f
チャスブラウン

fは、このような空の文字列としてfalsy値である場合には失敗した@Chasブラウン
Quintec

実際、私が言っていることは、それを無視してください
-Quintec


3

R、81バイト

function(a,b,e,s)Reduce(function(A,x)unique(e[a%in%A&b==x]),el(strsplit(s,"")),0)

オンラインでお試しください!

を使用しReduceた簡単な答え。ルールを3つのベクトルとして取りますstate, symbol, new-statesと呼ばれますa,b,e

ルールは別です(たとえば、ルール0,'a',[1,2]0,'a',1andです0,'a',2)。



2

掃除、68バイト

これはovsのHaskellソリューションに基づいており、最初のアプローチよりも少し短くなっています。

テストハーネスが含まれるようになりました

import StdEnv
?d=foldl(\s c=removeDup[r\\(y,r)<-d,g<-s|(g,c)==y])[0]

オンラインでお試しください!


1
@BWOテストハーネスを追加
18

1

、44バイト

⊞υ⁰Fη«≔υζ≔⟦⟧υFζFθ¿∧⁼§λ⁰κ⁼§λ¹ιF§λ²¿¬№υμ⊞υμ»Iυ

オンラインでお試しください!リンクは、コードの詳細バージョンです。説明:

⊞υ⁰

0事前定義された空のリストにプッシュして、初期状態を{0}

Fη«

入力をループします。

≔υζ

状態をコピーします。

≔⟦⟧υ

状態をリセットします。

Fζ

状態のコピーをループします。

Fθ

NFAエントリをループします。

¿∧⁼§λ⁰κ⁼§λ¹ι

エントリが一致する場合、...

F§λ²

...新しい状態をループします...

¿¬№υμ

....まだリストにない場合...

⊞υμ»

...リストに追加します。

Iυ

状態のリストを文字列にキャストして、個別の行に暗黙的に出力します。



1

Japt、31バイト

W=[W]c;Ê?ßUÅVVf!øW føUg)mÌc):Wâ

それを試してみてください!

いくつかの入力から関数を暗黙的に形成するJaptの機能をよりよく使用して2バイトを節約しました

説明:

W=[W]c;                            Initialize the state set to [0] on the first run
       Ê?                   :Wâ    If the input is empty return the unique states; else...
             Vf!øW                 Get the transitions valid for one of the current states
                   føUg)           Of those, get the ones valid for the current character
                        mÌc)       Merge the states of the remaining transitions
         ßUÅV                      Repeat with the remaining characters as input

新しい「状態の初期化」コードでは、もう少し詳細を使用できます。W入力が3つ未満の場合、Japt は0に初期化されるため、最初の実行で[W]はが[0]c配列を「フラット化」します。[0]既にフラットになっているため、変更されません。以降の実行でWは、異なる値があります(例:)[1,2]。その場合に[W]なる[[1,2]]、その要素が配列の単一要素アレイ。今回はcそれを解き、に戻り[1,2]ます。したがって、最初の実行ではでW=[0]あり、後続の実行ではW=Wです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.