Làm thế nào để chuyển đổi automata hữu hạn thành biểu thức thông thường?


115

Chuyển đổi các biểu thức chính quy thành NFA (tối thiểu) chấp nhận cùng một ngôn ngữ là dễ dàng với các thuật toán tiêu chuẩn, ví dụ thuật toán của Thompson . Tuy nhiên, hướng khác có vẻ tẻ nhạt hơn, và đôi khi các biểu thức kết quả là lộn xộn.

Có những thuật toán nào để chuyển đổi NFA thành các biểu thức chính quy tương đương? Có những lợi thế về độ phức tạp thời gian hoặc kích thước kết quả?

Đây được cho là một câu hỏi tham khảo. Vui lòng bao gồm một phân đoạn chung về phương pháp của bạn cũng như một ví dụ không tầm thường.


2
Lưu ý một câu hỏi tương tự tại cstheory.SE có lẽ không phù hợp với khán giả của chúng tôi.
Raphael

tất cả các câu trả lời sử dụng kỹ thuật chính thức để viết RE từ DFA. Tôi tin rằng kỹ thuật của tôi bằng cách phân tích là tương đối dễ dàng và khách quan Tôi chứng minh trong câu trả lời của mình: ngôn ngữ của automata hữu hạn xác định này là gì? Tôi cảm thấy nó sẽ hữu ích đôi khi. Vâng, tất nhiên đôi khi bản thân tôi sử dụng phương pháp chính thức (định lý Arden) để viết RE là câu hỏi rất phức tạp như được đưa ra trong ví dụ này: Cách viết biểu thức chính quy cho DFA
Grijesh Chauhan

Câu trả lời:


94

Có một số phương pháp để thực hiện chuyển đổi từ automata hữu hạn sang biểu thức thông thường. Ở đây tôi sẽ mô tả một người thường được dạy ở trường rất trực quan. Tôi tin rằng nó được sử dụng nhiều nhất trong thực tế. Tuy nhiên, viết thuật toán không phải là một ý tưởng tốt.

Phương pháp loại bỏ nhà nước

Thuật toán này là về việc xử lý đồ thị của máy tự động và do đó không phù hợp lắm với các thuật toán vì nó cần các nguyên hàm đồ thị như ... loại bỏ trạng thái. Tôi sẽ mô tả nó bằng cách sử dụng nguyên thủy cấp cao hơn.

Ý tưởng chính

Ý tưởng là xem xét các biểu thức chính quy trên các cạnh và sau đó loại bỏ các trạng thái trung gian trong khi vẫn giữ các nhãn cạnh nhất quán.

Các mô hình chính có thể được nhìn thấy trong các hình sau đây. Đầu tiên có nhãn giữa là các biểu thức chính quy e , f , g , h , i và chúng tôi muốn xóa q .p,q,re,f,g,h,iq

tự động pqr

Sau khi xóa, chúng ta kết hợp lại với nhau (trong khi bảo tồn các cạnh khác giữa pr nhưng điều này không được hiển thị trên này):e,f,g,h,ipr

nhập mô tả hình ảnh ở đây

Thí dụ

Sử dụng ví dụ tương tự như trong câu trả lời của Raphael :

Máy tự động 1-2-3

chúng tôi liên tiếp xóa :q2

Máy tự động 1-3

và sau đó :q3

1 máy tự động

sau đó chúng ta vẫn phải áp dụng một ngôi sao trên biểu thức từ đến q 1 . Trong trường hợp này, trạng thái cuối cùng cũng là ban đầu, vì vậy chúng tôi thực sự chỉ cần thêm một ngôi sao:q1q1

(ab+(b+aa)(ba)(a+bb))

Thuật toán

L[i,j]là biểu thức chính của ngôn ngữ từ đến q j . Đầu tiên, chúng tôi loại bỏ tất cả các cạnh:qiqj

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

Bây giờ, nhà nước loại bỏ. Giả sử chúng ta muốn xóa trạng thái :qk

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]

star(ε)=εe.ε=e∅+e=e∅.e=∅εq k q j q kqiqkqjqk

Bây giờ, sử dụng như thế nào remove(k)? Bạn không nên loại bỏ các trạng thái cuối cùng hoặc ban đầu một cách nhẹ nhàng, nếu không bạn sẽ bỏ lỡ các phần của ngôn ngữ.

for i = 1 to n:
  if not(final(i)) and not(initial(i)):
    remove(i)

Nếu bạn chỉ có một trạng thái cuối cùng và một trạng thái ban đầu thì biểu thức cuối cùng là:q sqfqs

e := star(L[s,s]) . L[s,f] . star(L[f,s] . star(L[s,s]) . L[s,f] + L[f,f])

Nếu bạn có một vài trạng thái cuối cùng (hoặc thậm chí là trạng thái ban đầu) thì không có cách đơn giản nào để hợp nhất những trạng thái này, ngoài việc áp dụng phương pháp đóng bắc cầu. Thông thường đây không phải là vấn đề bằng tay nhưng điều này thật bất tiện khi viết thuật toán. Một cách giải quyết đơn giản hơn nhiều là liệt kê tất cả các cặp và chạy thuật toán trên biểu đồ (đã loại bỏ trạng thái) để có được tất cả các biểu thức giả sử là trạng thái ban đầu duy nhất và là trạng thái cuối cùng duy nhất trạng thái, sau đó thực hiện liên kết của tất cả .e s , f s f e s , f(s,f)es,fsfes,f

Điều này và thực tế là điều này đang sửa đổi các ngôn ngữ linh hoạt hơn phương thức đầu tiên làm cho nó dễ bị lỗi hơn khi lập trình. Tôi đề nghị sử dụng bất kỳ phương pháp khác.

Nhược điểm

Có rất nhiều trường hợp trong thuật toán này, ví dụ để chọn nút nào chúng ta nên loại bỏ, số trạng thái cuối cùng ở cuối, thực tế là trạng thái cuối cùng cũng có thể là ban đầu, v.v.

Lưu ý rằng bây giờ thuật toán được viết, nó rất giống với phương thức đóng bắc cầu. Chỉ có bối cảnh của việc sử dụng là khác nhau. Tôi không khuyên bạn nên thực hiện thuật toán, nhưng sử dụng phương pháp để làm điều đó bằng tay là một ý tưởng tốt.


1
Trong ví dụ, hình ảnh thứ 2, sau khi loại bỏ nút "2", có một cạnh bị thiếu - cạnh vòng lặp (ab) trong nút A.
Panos Kal.

@Kabamaru: Đã sửa. Nhưng bây giờ tôi nghĩ trong hình ảnh thứ 3 cũng nên , và tương tự có lẽ trong biểu thức chính quy cuối cùng. εab
Logic lang thang

Bạn có thể làm cho thuật toán hoạt động cho bất kỳ số lượng trạng thái ban đầu và cuối cùng nào bằng cách thêm một trạng thái ban đầu mới và trạng thái cuối cùng mới và kết nối chúng với trạng thái ban đầu và trạng thái ban đầu bằng -edges. Bây giờ loại bỏ tất cả các trạng thái ban đầu. Biểu thức sau đó được tìm thấy ở cạnh duy nhất còn lại từ đến . Việc xây dựng sẽ không tạo ra các vòng lặp tại hoặc vì các trạng thái này không có sự tôn trọng. các cạnh đi. Hoặc nếu bạn nghiêm khắc, họ sẽ có nhãn đại diện cho bộ trống. q+qεq+qq+q
Hendrik

1
Vẫn còn một vấn đề với ví dụ thứ hai: trước khi đơn giản hóa, automata chấp nhận "ba", (1, 3, 1) nhưng sau khi đơn giản hóa thì không.
wvxvw

50

phương pháp

Phương pháp đẹp nhất mà tôi đã thấy là một phương pháp biểu thị hệ thống tự động như hệ phương trình của các ngôn ngữ (thông thường) có thể được giải. Nó đặc biệt tốt vì nó dường như mang lại nhiều biểu thức ngắn gọn hơn các phương thức khác.

Đặt một NFA mà không có -transitions. Với mọi trạng thái , hãy tạo phương trìnhA=(Q,Σ,δ,q0,F)εqi

Qi=qiaqjaQj{{ε}, qiF, else

Trong đó là tập hợp các trạng thái cuối cùng và có nghĩa là có sự chuyển đổi từ sang được gắn nhãn . Nếu bạn đọc as hoặc (tùy thuộc vào định nghĩa biểu thức chính quy của bạn), bạn sẽ thấy rằng đây là một phương trình của biểu thức chính quy.Fqiaqjqiqja+

Để giải quyết hệ thống, bạn cần tính kết hợp và phân phối của và (nối chuỗi), tính giao hoán của và Bổ đề Arden ¹:

Hãy ngôn ngữ thường xuyên với . Sau đó,L,U,VΣεU

L=ULVL=UV

Giải pháp là một tập hợp các biểu thức chính quy , một biểu thức cho mọi trạng thái . mô tả chính xác những từ có thể được chấp nhận khi bắt đầu bằng ; do đó (nếu là trạng thái ban đầu) là biểu thức mong muốn.QiqiQiAqiQ0q0


Thí dụ

Để rõ ràng, chúng tôi biểu thị các tập hợp đơn theo yếu tố của chúng, tức là . Ví dụ là do Georg Zetzsche.a={a}

Hãy xem xét NFA này:

ví dụ nfa
[ nguồn ]

Hệ phương trình tương ứng là:

Q0=aQ1bQ2εQ1=bQ0aQ2Q2=aQ0bQ1

Bây giờ cắm phương trình thứ ba vào thứ hai:

Q1=bQ0a(aQ0bQ1)=abQ1(baa)Q0=(ab)(baa)Q0

Bước cuối cùng, chúng tôi áp dụng Bổ đề của Arden với , và . Lưu ý rằng cả ba ngôn ngữ đều thông thường và , cho phép chúng tôi áp dụng bổ đề. Bây giờ chúng ta cắm kết quả này vào phương trình đầu tiên:L=Q1U=abV=(baa)Q0εU={ab}

Q0=a(ab)(baa)Q0baQ0bb(ab)(baa)Q0ε=((abb)(ab)(baa)ba)Q0ε=((abb)(ab)(baa)ba)(by Arden's Lemma)

Vì vậy, chúng tôi đã tìm thấy một biểu thức chính quy cho ngôn ngữ được chấp nhận bởi automaton ở trên, cụ thể là

((a+bb)(ab)(b+aa)+ba).

Lưu ý rằng nó khá ngắn gọn (so sánh với kết quả của các phương pháp khác) nhưng không được xác định duy nhất; giải hệ phương trình với một chuỗi các thao tác khác nhau dẫn đến khác - tương đương! -- biểu thức.


  1. Để biết bằng chứng về Bổ đề của Arden, xem tại đây .

1
Độ phức tạp thời gian của thuật toán này là gì? Có một ràng buộc về kích thước của biểu thức sản xuất?
jmite

@jmite: Mình không có ý kiến. Tôi không nghĩ rằng tôi sẽ cố gắng thực hiện điều này (các phương pháp khác có vẻ khả thi hơn trong vấn đề này) nhưng sử dụng nó như một phương pháp giấy bút.
Raphael

1
Đây là một triển khai Prolog của thuật toán này: github.com/wvxvw/intro-to-automata-theory/blob/master/automata/, nhưng maybe_union/2vị ngữ của nó có thể sử dụng nhiều công việc hơn (đặc biệt là loại bỏ tiền tố phổ biến) để tạo ra các biểu thức chính quy gọn gàng hơn. Một cách khác để xem phương pháp này là hiểu nó là dịch từ regex sang ngữ pháp tuyến tính phải, trong đó các ngôn ngữ có khớp mẫu giống như Prolog hoặc ML giống nhau tạo ra một bộ chuyển đổi rất tốt, vì vậy nó không chỉ là một cây bút thuật toán :)
wvxvw

Chỉ một câu hỏi. Trong phương trình đầu tiên là vì Qo là trạng thái bắt đầu hay vì nó là trạng thái cuối cùng? Cách tương tự nếu tôi có hai trạng thái cuối cùng áp dụng?
Georgio3

@PAOK Kiểm tra định nghĩa của ở trên (dòng); đó là vì là trạng thái cuối cùng. Qiq0
Raphael

28

Phương pháp đại số Brzozowski

Đây là phương pháp tương tự như phương pháp được mô tả trong câu trả lời của Raphael , nhưng từ quan điểm của một thuật toán có hệ thống, và sau đó, thực sự, thuật toán. Nó trở nên dễ dàng và tự nhiên để thực hiện một khi bạn biết bắt đầu từ đâu. Ngoài ra, có thể dễ dàng hơn bằng tay nếu vẽ tất cả các automata là không thực tế vì một số lý do.

Khi viết một thuật toán bạn phải nhớ rằng các phương trình phải luôn luôn tuyến tính để bạn có một biểu diễn trừu tượng tốt của các phương trình, điều mà bạn có thể quên khi bạn giải bằng tay.

Ý tưởng của thuật toán

Tôi sẽ không mô tả cách thức hoạt động vì nó được thực hiện tốt trong câu trả lời của Raphael mà tôi đề nghị đọc trước đó. Thay vào đó, tôi tập trung vào thứ tự bạn nên giải các phương trình mà không cần thực hiện quá nhiều tính toán bổ sung hoặc các trường hợp phụ.

Bắt đầu từ giải pháp khéo léo của quy tắc Arden đến phương trình ngôn ngữ chúng ta có thể coi máy tự động như một tập hợp các phương trình có dạng:X=ABX=AXB

Xi=Bi+Ai,1X1++Ai,nXn

chúng ta có thể giải quyết điều này bằng cách cảm ứng trên bằng cách cập nhật các mảng và tương ứng. Ở bước , chúng ta có:nAi,jBi,jn

Xn=Bn+An,1X1++An,nXn

và quy tắc của Arden cho chúng ta:

Xn=An,n(Bn+An,1X1++An,n1Xn1)

và bằng cách đặt và chúng tôi nhận được:Bn=An,nBnAn,i=An,nAn,i

Xn=Bn+An,1X1++An,n1Xn1

và sau đó chúng tôi có thể xóa tất cả các nhu cầu của trong hệ thống bằng cách đặt, cho :Xni,j<n

Bi=Bi+Ai,nBn
Ai,j=Ai,j+Ai,nAn,j

Khi chúng ta đã giải được khi , chúng ta có được một phương trình như thế này:Xnn=1

X1=B1

không có . Vì vậy, chúng tôi đã có biểu hiện thường xuyên của chúng tôi.A1,i

Thuật toán

Nhờ vậy, chúng ta có thể xây dựng thuật toán. Để có cùng quy ước so với quy nạp ở trên, chúng ta sẽ nói rằng trạng thái ban đầu là và số trạng thái là . Đầu tiên, việc khởi tạo để điền :q1mB

for i = 1 to m:
  if final(i):
    B[i] := ε
  else:
    B[i] := ∅

và :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] := ∅

và sau đó là giải quyết:

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]

biểu thức cuối cùng là:

e := B[1]

Thực hiện

Ngay cả khi nó có vẻ như là một hệ phương trình có vẻ quá tượng trưng cho một thuật toán, thì phương trình này rất phù hợp để thực hiện. Đây là một triển khai của thuật toán này trong Ocaml (liên kết bị hỏng) . Lưu ý rằng ngoài chức năng brzozowski, mọi thứ đều được in hoặc sử dụng cho ví dụ của Raphael. Lưu ý rằng có một chức năng hiệu quả đáng ngạc nhiên là đơn giản hóa các biểu thức chính quy simple_re.


4
Liên kết đã chết ...
Columbo


24

Phương pháp đóng cửa bắc cầu

Phương pháp này dễ viết dưới dạng thuật toán, nhưng tạo ra các biểu thức chính quy lớn vô lý và không thực tế nếu bạn làm bằng tay, chủ yếu là vì điều này quá hệ thống. Đó là một giải pháp tốt và đơn giản cho một thuật toán mặc dù.

Ý tưởng chính

Đặt biểu thị biểu thức chính quy cho các chuỗi đi từ đến bằng cách sử dụng các trạng thái . Gọi là số trạng thái của máy tự động.Ri,jkqiqj{q1,,qk}n

Giả sử rằng bạn đã biết biểu thức chính quy từ đến mà không có trạng thái trung gian (ngoại trừ các cực trị), cho tất cả . Sau đó, bạn có thể đoán việc thêm một trạng thái khác sẽ ảnh hưởng đến biểu thức chính quy mới : nó chỉ thay đổi nếu bạn có chuyển đổi trực tiếp sang và nó có thể được biểu thị như sau:Ri,jqiqjqki,jRi,jqk

Ri,j=Ri,j+Ri,k.Rk,k.Rk,j

( là và là .)RRk1RRk

Thí dụ

Chúng tôi sẽ sử dụng ví dụ tương tự như trong câu trả lời của Raphael . Lúc đầu, bạn chỉ có thể sử dụng các chuyển tiếp trực tiếp.

Đây là bước đầu tiên (lưu ý rằng một tự vòng lặp với một nhãn sẽ chuyển đầu tiên vào .aε(ε+a)

R0=[εabbεaabε]

Ở bước thứ hai, chúng tôi có thể sử dụng (được đổi tên thành cho chúng tôi, vì đã được sử dụng cho mục đích trên). Chúng ta sẽ thấy hoạt động như thế nào .q0q1R0R1

Từ đến : .q2q2R2,21=R2,20+R2,10R1,10R1,20=ε+bεa=ε+ba

Tại sao vậy? Đó là bởi vì đi từ đến chỉ sử dụng làm trạng thái trung gian có thể được thực hiện bằng cách ở đây ( ) hoặc đến ( ), lặp ở đó ( ) và quay lại ( ).q2q2q1εq1aεb

R1=[εabbε+baa+bbab+aaε+ab]

Bạn cũng có thể tính như vậy và , và sẽ cung cấp cho bạn biểu thức cuối cùng vì là cả ban đầu và cuối cùng. Lưu ý rằng rất nhiều đơn giản hóa các biểu thức đã được thực hiện ở đây. Nếu không, đầu tiên của sẽ là và đầu tiên của sẽ là .R2R3R1,131aR0(+a)aR1((+a)+ε(ε)a)

Thuật toán

Khởi tạo:

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

Sự đóng kín:

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)

Sau đó, biểu thức cuối cùng là (giả sử là trạng thái ban đầu):qs

e := ∅
for i = 1 to n:
  if final(i):
    e := e + R[s,i,n]

Nhưng bạn có thể tưởng tượng nó tạo ra các biểu thức chính quy xấu xí. Bạn thực sự có thể mong đợi những thứ như đại diện cho cùng ngôn ngữ với . Lưu ý rằng đơn giản hóa một biểu thức chính quy là hữu ích trong thực tế.a a()+(a+())(ε)(a+)aa

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.