NFA 시뮬레이션


15

결정적 유한 오토 마톤 튜플 유한 상태 기계 다중 상태에 매핑된다. 즉. DFA 의 일반적인 δ : Q × Σ Q 전환 기능을 다른 기능 Δ : Q × Σ P ( Q )로 대체합니다 .(에스이자형,에스와이미디엄영형)δ:×Σ Δ:×Σ()

NFA가 무엇인지 아는 경우 다음 섹션을 건너 뛰어도됩니다.

공식적인 정의

NFA는 다음과 같이 고유하게 설명됩니다.

  • 유한 한 상태 집합
  • 유한 한 기호 세트Σ
  • 전환 기능Δ:×Σ()
  • 초기 상태0
  • 최종 상태 세트에프

기계는 에서 시작 하여 유한 문자 스트링 w Σ ∗를 읽습니다. 각 심볼에 대해 현재 상태와 함께 전이 기능 기능을 동시에 적용하고 새로운 각 상태 세트를 현재 상태 세트에 추가합니다.0Σ

도전

이 문제를 해결 하기 위해 를 무시 하고 알파벳은 항상 (소문자) a ~ z 문자 이며 음수가 아닌 정수 N 의 경우 상태 세트는 { 0 N } 입니다 . 초기 상태는 항상 0 입니다.에프   {0}0

단어 와 NFA에 대한 설명이 주어지면 모든 최종 상태를 결정해야합니다.{}

문자열 과 다음 설명을 고려하십시오 .아 바브

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

기계는 에서 시작합니다 .0=0

  1. : 새로운 상태 { 1 }을 읽으십시오{1}
  2. 읽기 a : 새로운 상태 { 1 , 2 }{1,2}
  3. 읽기 : 새로운 상태 { 0 }{0}
  4. : 새로운 상태 { 1 }을 읽으십시오{1}
  5. 읽기 a : 새로운 상태 { 1 , 2 }{1,2}

따라서 최종 상태 및 결과는 입니다.{1,2}

주의 : 단계 (2) 의 상태의 변화가 지도가 설명이 단지 비어 세트로 천이를 포함한다.2

규칙

입력은 문자열과 NFA에 대한 일종의 설명으로 구성됩니다 ( 전환 없음).ϵ

  • 입력 문자열은 항상 { az }의 요소입니다. {}
  • 유효한 입력 (제한되지 않음) :
    • 튜플 /리스트의 목록 / 배열
    • 개행으로 분리 된 입력
  • NFA에 대한 설명에는 결과로 비어 있지 않은 세트가있는 전환 만 포함됩니다.
    • 결과가 동일한 경우 동일한 문자로 규칙을 축약 할 수 있습니다 (예 : 규칙 0,'a',[1,2]및 다음과 0,'b',[1,2]같이 축약 될 수 있음)0,"ab",[1,2]
    • 각 규칙을 따로 따를 0,'a',[1,2]수 있습니다 (예 : 규칙 은 0,'a',[1]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
이것은 나의 오토 마톤 코스에서 무서운 추억을 되찾아줍니다.
Don Thousand

우리는 예를 들어 각각의 새로운 상태에 대한 개별 라인 입력을 할 수 일을 예를 들어?
ovs

@ovs : 물론가요!
ბიმო

답변:


7

하스켈 , 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 모든 Ints 모든 현재 상태를 반복 하므로 여전히 중복 상태를 생성합니다. (변경 [0..][0..3]테스트 목적 만이 바로 차이를 만들지해야합니까?)
OVS

그래, 내가 무슨 생각을했는지 모르겠어 .. 신경
쓰지 마

4

Brachylog , 42 바이트

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

[문자열, 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는 이런 종류의 문제에 정말 좋고 두 개의 별도 입력과 출력이 필요한 문제에는 정말 좋지 않습니다. 이 프로그램의 거의 대부분은 배관 작업입니다.

입력 형식은 두 가지 요소를 포함하는 목록입니다. 첫 번째는 상태 전이 목록 ( [oldState, symbol, newState])이고 두 번째는 기호 목록입니다. 원래이 프로그램은 기호에 대한 문자 코드로 작동하도록 계획했지만 (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는 인식합니다. 마지막 예제는 비 결정적입니다. 우리는 Brachylog 자체의 비결정론을 사용하여 NFA에서 비결정론을 모델링하고 있습니다.

가능한 개선

여기의 구문 중 일부 ↔,0↔, 특히 와 같은 혼란 H&hg;Hz{…ᵈ}ᵐ은 상당히 어수선 합니다. 이것을 말로 표현할 수있는 더 터무니없는 방법이 있다면 놀라지 않을 것입니다.

{∋ᵈ}ᵐ그 자체로는 상당히 의심스러운 구조입니다 – 당신은 단지 글을 쓸 수있을 것으로 기대 ∋ᵈᵐ하지만 – 어떤 이유로 든 파싱하지는 않습니다.


∋ᵈᵐ다중 문자 메타 술어 이름을 이론적으로 사용할 수 있도록 구현되었으므로 구문 분석하지 않습니다 (단일 기호 가능성이 부족한 경우). 실제로는 현재 사용되지 않습니다.
페이탈 라이즈

3

파이썬 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

파이썬 3에는 부족하다는 것은 부끄러운 일입니다 reduce. 그러나 재귀와 실제 집합을 사용하면 여전히 80 바이트 로 줄어 듭니다 .
ბიმო

@BWO 좋은, 감사합니다, 하하 btw 위의 내가 보여주는 가장 좋아하는 예제 파이썬 코드입니다 ... 한 줄 거대한 목록 이해가 나보다 훨씬 더
재미있게

로 교체 if''<f하여 2 바이트를 절약 할 수 있다고 생각합니다 if f.
Chas Brown

f가 빈 문자열과 같은 잘못된 값이면 @Chas Brown
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. state, symbol, new-states이라는 규칙을 세 개의 벡터로 사용 합니다 a,b,e.

규칙은 별개입니다 (예 : 규칙 0,'a',[1,2]0,'a',10,'a',2).




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

새로운 "상태 초기화"코드는 좀 더 자세하게 사용할 수 있습니다. JAPT는 초기화 W가 제 런 등, 3 개 미만의 입력 인 경우 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.