유한 오토마타를 정규 표현식으로 변환하는 방법은 무엇입니까?
On 2월 16, 2021 by admin정규식을 동일한 언어를 허용하는 (최소) NFA로 변환하는 것은 표준 알고리즘을 사용하면 쉽습니다. Thompson의 알고리즘 . 다른 방향은 더 지루한 것처럼 보이며 때로는 결과 표현이 지저분합니다.
알고리즘이란 무엇입니까? NFA를 동등한 정규 표현식으로 변환 할 수 있습니까? 시간 복잡성이나 결과 크기와 관련하여 이점이 있습니까?
참고 질문입니다. 방법에 대한 일반적인 설명과 사소하지 않은 예입니다.
댓글
- 유사한 질문을 cstheory.SE 는 아마도 우리 청중에게 적합하지 않을 것입니다.
- 모든 답변은 DFA에서 RE를 작성하기 위해 형식적인 기술을 사용합니다. 분석에 의한 기술이 비교적 쉽고 객관적이라고 생각합니다. : 이 결정 론적 유한 오토마타의 언어는 무엇입니까? 언젠가는 도움이 될 것 같습니다. 예, 당연히 나 자신이 공식적인 방법 (Arden theorem)을 사용합니다. RE를 쓰는 것은 질문은 다음 예와 같이 복잡합니다. DFA 용 정규 표현식 작성 방법
답변
유한 오토마타에서 정규 표현식으로 변환하는 방법에는 여러 가지가 있습니다. 여기에서는 학교에서 일반적으로 가르치는 매우 시각적 인 것을 설명하겠습니다. 나는 그것이 실제로 가장 많이 사용된다고 생각합니다. 그러나 알고리즘을 작성하는 것은 좋은 생각이 아닙니다.
상태 제거 방법
이 알고리즘은 자동 장치의 그래프를 처리하는 것이므로 필요하므로 알고리즘에 적합하지 않습니다. … 상태 제거와 같은 그래프 프리미티브. 더 높은 수준의 프리미티브를 사용하여 설명하겠습니다.
핵심 아이디어
이념은 가장자리에 대한 정규 표현식을 고려한 다음 가장자리 레이블을 일관되게 유지하면서 중간 상태를 제거하는 것입니다.
p>
주요 패턴은 다음 그림에서 볼 수 있습니다. 첫 번째는 정규 표현식 $ e, f, g, h, i $ 인 $ p, q, r $ 사이에 레이블이 있으며 $ q $를 제거하려고합니다.
제거되면 $ e, f, g, h, i $를 함께 구성합니다 ($ p $와 $ r $ 사이의 다른 가장자리는 유지하지만 표시되지 않음). on this) :
예
Raphael의 답변 :
$ q_2 $ :
그리고 $ q_3 $ :
그러면 $ q_1 $에서 $ q_1 $까지 표현식에 별표를 적용해야합니다.이 경우 최종 상태는 다음과 같습니다. 이니셜도 있으므로 별표를 추가하면됩니다.
$$ (ab + (b + aa) (ba) ^ * (a + bb)) ^ * $$
Algorithm
L[i,j]
는 $ q_i $에서 $ q_j $까지의 언어 정규식입니다. 먼저 모든 mul을 제거합니다. ti-edges :
for i = 1 to n: for j = 1 to n: if i == j then: L[i,j] := ε else: L[i,j] := ∅ for a in Σ: if trans(i, a, j): L[i,j] := L[i,j] + a
이제 상태 제거입니다. $ q_k $ 상태를 제거한다고 가정합니다.
remove(k): for i = 1 to n: for j = 1 to n: L[i,i] += L[i,k] . star(L[k,k]) . L[k,i] L[j,j] += L[j,k] . star(L[k,k]) . L[k,j] L[i,j] += L[i,k] . star(L[k,k]) . L[k,j] L[j,i] += L[j,k] . star(L[k,k]) . L[k,i]
종이 연필과 알고리즘을 사용하여
, e.ε=e
, ∅+e=e
, ∅.e=∅
( $ ∅ $ 또는 자체 루프의 경우 $ ε $가 아닐 때 가장자리를 작성하지 않고 $ q_i $와 $ q_k $ 또는 $ q_j $와 $ 사이에 전환이 없을 때 무시합니다. q_k $)
이제 remove(k)
를 사용하는 방법은 무엇입니까? 최종 또는 초기 상태를 가볍게 제거해서는 안됩니다. 그렇지 않으면 언어의 일부가 누락됩니다.
for i = 1 to n: if not(final(i)) and not(initial(i)): remove(i)
최종 상태 $ q_f $와 하나만있는 경우 초기 상태 $ q_s $ 그러면 최종 표현식은 다음과 같습니다.
e := star(L[s,s]) . L[s,f] . star(L[f,s] . star(L[s,s]) . L[s,f] + L[f,f])
여러 최종 상태 (또는 초기 상태)가있는 경우 병합하는 간단한 방법이 없습니다. 이러한 것들은 전 이적 폐쇄 방법을 적용하는 것 외에는 다릅니다. 일반적으로 이것은 수작업으로 문제가되지 않지만 알고리즘을 작성할 때 어색합니다. 훨씬 간단한 해결 방법은 $ (s, f) $ 쌍을 모두 열거하고 (이미 상태 제거됨) 그래프에서 알고리즘을 실행하여 $ s $가 유일한 초기 상태라고 가정하고 모든 표현식 $ e_ {s, f} $를 가져 오는 것입니다. 그리고 $ f $는 유일한 최종 상태이고, 모든 $ e_ {s, f} $의 합집합을 수행합니다.
이것은 첫 번째 방법보다 더 동적으로 언어를 수정한다는 사실로 인해 프로그래밍시 오류가 발생하기 쉽습니다. 다른 방법을 사용하는 것이 좋습니다.
단점
이 알고리즘에는 많은 경우가 있습니다. 예를 들어 제거해야 할 노드, 마지막 상태의 수를 선택하는 경우가 있습니다. , 최종 상태도 초기 상태가 될 수 있다는 사실 등입니다.
알고리즘이 작성되었으므로 이것은 전 이적 폐쇄 방법과 매우 유사합니다.사용법의 컨텍스트 만 다릅니다. 알고리즘 구현을 권장하지 않지만 수동으로 수행하는 방법을 사용하는 것이 좋습니다.
댓글
- 예제에서 두 번째 이미지, 노드 제거 후 ” 2 “, 노드 A에 가장자리 누락-루프 가장자리 (ab)가 있습니다.
- @Kabamaru : 고정. 하지만 이제는 세 번째 이미지의 $ \ varepsilon $도
ab
여야한다고 생각합니다. 마찬가지로 최종 정규 표현식에서도 마찬가지입니다. - 알고리즘을 만들 수 있습니다. 새로운 초기 $ q ^ + $ 및 새로운 최종 상태 $ q ^-$를 추가하고이를 $ \ varepsilon $ -edges로 원래 초기 및 최종 상태에 연결하여 여러 초기 및 최종 상태에 대해 작업합니다. 이제 원래 상태를 모두 제거하십시오. 표현식은 $ q ^ + $에서 $ q _- $까지 남은 단일 가장자리에서 발견됩니다. $ q ^ + $ 또는 $ q _- $에 루프를 제공하지 않습니다. 이러한 상태에는 수신 응답이 없습니다. 나가는 가장자리. 또는 엄격하다면 빈 세트를 나타내는 레이블이 있습니다.
- 두 번째 예제에는 여전히 문제가 있습니다. 단순화하기 전에 자동 장치는 ” ba를 허용합니다. “, (1, 3, 1) 그러나 단순화 후에는 ‘ t
Answer
Method
내가 본 가장 좋은 방법은 자동화를 (일반) 언어의 방정식 시스템으로 표현하는 것입니다. 해결되다. 다른 방법보다 더 간결한 표현을 만들어내는 것 같아 특히 좋습니다.
Let $ A = (Q, \ Sigma, \ delta, q_0, F) $ $ \ varepsilon $-없는 NFA 전환. 모든 주 $ q_i $에 대해 방정식을 만듭니다.
$ \ qquad \ displaystyle Q_i = \ bigcup \ limits_ {q_i \ overset {a} {\ to} q_j} aQ_j \ cup \ begin {cases} \ {\ varepsilon \} &, \ q_i \ in F \\ \ emptyset &, \ text {else} \ end {cases} $
여기서 $ F $는 최종 상태 집합이고 $ q_i \ overset {a} {\ to} q_j $는 $ a $ 레이블이 붙은 $ q_i $에서 $ q_j $ 로의 전환이 있음을 의미합니다. . $ \ cup $를 $ + $ 또는 $ \ mid $ (정규식 정의에 따라)로 읽으면 이것이 정규식의 방정식임을 알 수 있습니다.
시스템을 해결하려면 연관성이 필요합니다. 및 $ \ cup $ 및 $ \ cdot $의 분포 (문자열 연결), $ \ cup $ 및 Arden s Lemma ¹ :
$ L, U, V \ subseteq \ Sigma ^ * $ 정규 언어를 $ \ varepsilon \ notin U $로 설정합니다. 그런 다음
$ \ qquad \ displaystyle L = UL \ cup V \ quad \ Longleftrightarrow \ quad L = U ^ * V $
정규 표현식 집합입니다. $ Q_i $, $ q_i $마다 하나씩 $ Q_i $는 $ q_i $에서 시작할 때 $ A $가 받아 들일 수있는 단어를 정확히 설명합니다. 따라서 $ Q_0 $ ($ q_0 $가 초기 상태 인 경우)는 원하는 표현.
예
명확성을 위해 단일 세트를 해당 요소 (예 : $ a = \ {a \} $)로 표시합니다. 예는 Georg Zetzsche 때문입니다.
Consider t 그의 NFA :
[ 출처 ]
해당 방정식 시스템은 다음과 같습니다.
$ \ qquad \ begin {align} Q_0 & = aQ_1 \ cup bQ_2 \ 컵 \ varepsilon \\ Q_1 & = bQ_0 \ cup aQ_2 \\ Q_2 & = aQ_0 \ cup bQ_1 \ end {align} $
이제 세 번째 방정식을 두 번째 방정식에 연결합니다.
$ \ qquad \ begin {align} Q_1 & = bQ_0 \ cup a (aQ_0 \ cup bQ_1) \\ & = abQ_1 \ cup (b \ cup aa) Q_0 \\ & = (ab) ^ * ( b \ cup aa) Q_0 \ end {align} $
마지막 단계에서는 $ L = Q_1 $, $ U = ab $ 및 $ V = (b \ cup aa) \ cdot Q_0 $. 세 가지 언어는 모두 일반이고 $ \ varepsilon \ notin U = \ {ab \} $이므로 기본형을 적용 할 수 있습니다. 이제이 결과를 첫 번째 방정식에 연결합니다.
$ \ qquad \ begin {align} Q_0 & = a (ab) ^ * (b \ cup aa ) Q_0 \ cup baQ_0 \ cup bb (ab) ^ * (b \ cup aa) Q_0 \ cup \ varepsilon \\ & = ((a \ cup bb) (ab) ^ * (b \ cup aa) \ cup ba) Q_0 \ cup \ varepsilon \\ & = ((a \ cup bb) (ab) ^ * (b \ cup aa) \ cup ba) ^ * \ qquad \ text {(by Arden “s Lemma)} \ end {align} $
따라서 우리는 위의 자동 장치에서 허용하는 언어에 대한 정규 표현식을 찾았습니다. 즉
$ \ qquad \ displaystyle ((a + bb) (ab) ^ * (b + aa) + ba) ^ *. $
아주 간결합니다 ( 다른 방법의 결과) 그러나 고유하게 결정되지는 않습니다. 다른 조작 순서로 방정식 시스템을 풀면 다른-동등한!-표현식이 생성됩니다.
- For a proof of Arden ” s Lemma, 여기 를 참조하십시오.
댓글
- 무엇을 이 알고리즘의 시간 복잡성은 무엇입니까? 생성 된 표현의 크기에 제한이 있습니까?
- @jmite : 모르겠어요. 저는 ‘ ‘이를 구현하려고하지 않는다고 생각합니다 (이 점에서 다른 방법이 더 실행 가능해 보임). 이 알고리즘의 프롤로그 구현은 다음과 같습니다. github.com은 펜과 종이로 된 방법입니다.
- 여기 ‘ / wvxvw / intro-to-automata-theory / blob / master / automata / … 그러나
maybe_union/2
조건자는 다음을 사용할 수 있습니다. 더 깔끔한 정규 표현식을 만들기 위해 더 많은 작업 (특히 공통 접두사 제거 wrt). 이 방법을 확인하는 또 다른 방법은 정규식에서 올바른 선형 문법으로의 번역으로 이해하는 것입니다. 여기서 Prolog와 같은 통합 또는 ML과 같은 패턴 일치를 사용하는 언어는 매우 우수한 변환기를 만들 수 있습니다. ‘는 펜과 종이 알고리즘 일뿐만 아니라 🙂 - 단지 질문 하나입니다. 첫 번째 방정식의 ε은 Qo가 시작 상태이기 때문입니까? 아니면 ‘ 최종 상태이기 때문입니까? 두 가지 최종 상태가 적용되는 경우에도 마찬가지입니까?
- @PAOK 위의 $ Q_i $ 정의를 확인하십시오 (줄). $ q_0 $가 최종 상태이므로 ‘입니다.
답변
Brzozowski 대수적 방법
이것은 Raphael의 답변 에 설명 된 것과 동일한 방법이지만 체계적인 알고리즘, 그리고 실제로 알고리즘을 볼 수 있습니다. 어디서부터 시작해야하는지 알면 구현하는 것이 쉽고 자연 스럽습니다. 또한 모든 자동 장치를 그리는 것이 어떤 이유로 비현실적인 경우 손으로 더 쉽게 구현할 수 있습니다.
알고리즘을 작성할 때 방정식이 항상 선형이어야한다는 점을 기억해야합니다. 그래야 방정식을 추상적으로 잘 표현할 수 있습니다. 손으로 풀 때 잊어 버릴 수 있습니다.
알고리즘의 아이디어
Raphael의 답변 에서 잘 수행되었으므로 작동 방식을 설명하지 않겠습니다. 대신에 너무 많은 추가 작업을하지 않고 방정식을 풀어야하는 순서에 초점을 맞 춥니 다. mputations 또는 추가 사례.
Arden의 규칙 “의 독창적 인 솔루션 $ X = A ^ * B $에서 시작하여 언어 방정식으로 $ X = AX∪B $ 우리는 오토 마톤을 다음 형식의 방정식 세트로 간주 할 수 있습니다.
$$ X_i = B_i + A_ {i, 1} X_1 +… + A_ {i, n} X_n $$
$ A_ {i, j} $ 및 $ B_ {i, j} $ 배열을 적절하게 업데이트하여 $ n $를 유도하여이 문제를 해결할 수 있습니다. $ n $ 단계에는 다음이 있습니다.
$$ X_n = B_n + A_ {n, 1} X_1 +… + A_ {n, n} X_n $$
및 Arden의 규칙은 다음과 같습니다.
$$ X_n = A_ {n, n} ^ * (B_n + A_ {n, 1} X_1 +… + A_ {n, n-1} X_ {n -1}) $$
$ B “_n = A_ {n, n} ^ * B_n $ 및 $ A”_ {n, i} = A_ {n, n} ^ * 설정 A_ {n, i} $ :
$$ X_n = B “_n + A”_ {n, 1} X_1 +… + A “_ {n, n-1} X_ {n -1} $$
그런 다음 $ i, j < n $ :
$$ B “_i = B_i + A_ {i, n} B”_n $$ $$ A “_ {i, j} = A_ {i, j} + A_ {i, n} A “_ {n, j} $$
$ n = 1 $ 일 때 $ X_n $를 풀면 다음과 같은 방정식을 얻습니다.
$$ X_1 = B” _1 $$
$ A “_ {1, i} $ 없음. 따라서 정규 표현식을 얻었습니다.
알고리즘
이 덕분에 알고리즘을 구축 할 수 있습니다. 위의 유도에서와 동일한 규칙을 갖기 위해 초기 상태는 $ q_1 $이고 상태의 수는 $ m $라고 말할 것입니다. 먼저 $ B $ :
for i = 1 to m: if final(i): B[i] := ε else: B[i] := ∅
및 $ A $ :
for i = 1 to m: for j = 1 to m: for a in Σ: if trans(i, a, j): A[i,j] := a else: A[i,j] := ∅
를 채우기위한 초기화입니다.
그리고 해결 :
for n = m decreasing to 1: B[n] := star(A[n,n]) . B[n] for j = 1 to n: A[n,j] := star(A[n,n]) . A[n,j]; for i = 1 to n: B[i] += A[i,n] . B[n] for j = 1 to n: A[i,j] += A[i,n] . A[n,j]
그러면 최종 표현식은 다음과 같습니다.
e := B[1]
구현
알고리즘에 너무 상징적으로 보이는 방정식 시스템처럼 보일지라도 이것은 구현에 적합합니다. 다음은 Ocaml에서이 알고리즘을 구현 한 것입니다 (연결 끊김) . 함수 brzozowski
를 제외하고 모든 것은 인쇄하거나 Raphael의 예제에 사용하는 것입니다. 놀랍도록 효율적인 정규식 단순화 기능이 있습니다. simple_re
.
댓글
- 링크가 끊어졌습니다 …
- 자바 스크립트로 구현 : github.com/devongovett/regexgen/blob/master/src/regex.js
- 이 훌륭한 설명에 감사드립니다. 올바르게 이해했다면 초기화 의사 코드는 주어진 i와 j에 대해 (i, a, j)가 전환 인 a가 최대 하나라고 가정합니다.이 전환을 모든 문자와 일치하는 정규 표현식으로 레이블을 지정하는 데 동의하면 맞습니다. Σ 그 레이블은 문자 자동 장치에서 i에서 j로 전환되지만 Σ의 표기법 a는 실제로 문자가 아니기 때문에 약간 이상합니다. 문자 단위로 이동하면 i에서 j로 여러 번 전환 할 수 있습니다. 루프 본문에서 레이블을 결합하십시오.
답변
전 이적 폐쇄 방법
이 방법은 양식으로 작성하기 쉽습니다. 하지만 너무 체계적이기 때문에 엄청나게 큰 정규 표현식을 생성하고 손으로하는 경우 비실용적입니다. 하지만 알고리즘에 대한 좋고 간단한 솔루션입니다.
핵심 아이디어
Let $ R ^ k_ {i, j} $는 $에서 오는 문자열에 대한 정규 표현식을 나타냅니다. $ \ {q_1,…, q_k \} $ 상태를 사용하여 q_i $에서 $ q_j $까지. $ n $를 자동 장치의 상태 수라고합니다.
중간 상태 $ q_k없이 $ q_i $에서 $ q_j $까지 정규식 $ R_ {i, j} $를 이미 알고 있다고 가정합니다. $ (사지 제외), 모든 $ i, j $. 그런 다음 다른 상태를 추가하면 새로운 정규식 $ R “_ {i, j} $에 어떤 영향을 미칠지 추측 할 수 있습니다. $ q_k $로 직접 전환하는 경우에만 변경되며 다음과 같이 표현 될 수 있습니다.
$$ R “_ {i, j} = R_ {i, j} + R_ {i, k} R_ {k, k} ^ *. R_ {k, j} $$
($ R $은 $ R ^ {k-1} $이고 $ R “$는 $ R ^ k $입니다.)
예
Raphael의 답변 과 동일한 예를 사용합니다. 처음에는 직접 전환 만 사용할 수 있습니다.
다음은 첫 번째 단계입니다 ($ a $ 레이블이있는 자체 루프는 첫 번째 $ ε $를 $ (ε + a)로 변환했을 것입니다.) $.
$$ R ^ 0 = \ begin {bmatrix} ε & a & b \\ b & ε & a \\ a & b & ε \ end {bmatrix} $$
두 번째 단계에서는 $ q_0 $를 사용할 수 있습니다 ($ R ^ 0 $이 이미 사용 되었기 때문에 $ q_1 $로 이름이 변경되었습니다. 위의 목적). $ R ^ 1 $의 작동 방식을 살펴 보겠습니다.
$ q_2 $에서 $ q_2 $까지 : $ R ^ 1_ {2,2} = R ^ 0_ {2,2} + R ^ 0_ {2,1} {R ^ 0_ {1,1}} ^ * R ^ 0_ {1,2} = ε + b ε ^ * a = ε + ba $.
그 이유는 $ q_1 $만을 중간 상태로 사용하여 $ q_2 $에서 $ q_2 $로 이동하는 것은 여기 ($ ε $)에 머물거나 $ q_1 $ ($ a $)로 이동하여 거기에서 반복하여 수행 할 수 있기 때문입니다. ($ ε ^ * $) 그리고 다시 돌아옵니다 ($ b $).
$$ R ^ 1 = \ begin {bmatrix} ε & a & b \\ b & ε + ba & a + bb \\ a & b + aa & ε + ab \ end {bmatrix} $$
$ R ^ 2 $, $ R ^ 3 $, $ R ^ 3_ {1,1처럼 계산할 수 있습니다. } $는 $ 1 $가 초기 및 최종이므로 최종 표현식을 제공합니다. 여기에서 많은 표현 단순화가 수행되었습니다. 그렇지 않으면 $ R ^ 0 $의 첫 $ a $는 $ (∅ + a) $가되고 $ R ^ 1 $의 첫 $ a $는 $ ((∅ + a) + ε (ε) ^ * a가됩니다. ) $.
알고리즘
초기화 :
for i = 1 to n: for j = 1 to n: if i == j: R[i,j,0] := ε else: R[i,j,0] := ∅ for a in Σ: if trans(i, a, j): R[i,j,0] := R[i,j,0] + a
일시적 폐쇄 :
for k = 1 to n: for i = 1 to n: for j = 1 to n: R[i,j,k] := R[i,j,k-1] + R[i,k,k-1] . star(R[k,k,k-1]) . R(k,j,k-1)
그런 다음 최종 표현식은 다음과 같습니다 ($ q_s $가 초기 상태라고 가정).
e := ∅ for i = 1 to n: if final(i): e := e + R[s,i,n]
하지만 상상할 수 있습니다. 추악한 정규 표현식을 생성합니다. $ aa $와 동일한 언어를 나타내는 $ (∅) ^ * + (a + (∅) ^ *) (ε) ^ * (a + ∅) $와 같은 것을 실제로 기대할 수 있습니다. 정규 표현식을 단순화하면 실제로 유용합니다.
답글 남기기