Sonlu otomatlar normal ifadelere nasıl dönüştürülür?


115

Düzenli ifadeleri aynı dili kabul eden (en az) NFA'ya dönüştürmek standart algoritmalar ile kolaydır, örneğin Thompson algoritması . Diğer yön daha sıkıcı görünüyor, ancak bazen ortaya çıkan ifadeler dağınık.

NFA'yı eşdeğer normal ifadelere dönüştürmek için hangi algoritmalar var? Zaman karmaşıklığı veya sonuç büyüklüğü ile ilgili avantajlar var mı?

Bunun bir referans sorusu olması gerekiyordu. Lütfen yönteminizin genel bir tanımını ve önemsiz olmayan bir örneği ekleyin.


2
Bir Not üzerinde cstheory.SE benzer soru muhtemelen izleyicilerimize uygun değildir.
Raphael

Tüm cevaplar DFA'dan RE yazmak için resmi bir teknik kullanır. Tekniğimin analiz yoluyla nispeten kolay ve objektif bir cevap verdiğime inanıyorum: Bu deterministik sonlu otomataların dili nedir? Bazen yardımcı olacağını hissediyorum. Evet, elbette bazen kendim de resmi bir yöntem (Arden teoremi) kullanıyorum, RE yazmak için soru bu örnekte verildiği gibi karmaşıktır: DFA için düzenli ifadeler nasıl yazılır
Grijesh Chauhan

Yanıtlar:


94

Sonlu otomatlardan normal ifadelere dönüşüm yapmak için birkaç yöntem vardır. Burada genelde okulda öğretilen, çok görsel olanı anlatacağım. Uygulamada en çok kullanılan olduğuna inanıyorum. Ancak, algoritmayı yazmak o kadar da iyi bir fikir değil.

Devlet kaldırma yöntemi

Bu algoritma, otomatın grafiğini kullanmakla ilgilidir ve bu nedenle ... durum kaldırma gibi grafik ilkellerine ihtiyaç duyduğundan algoritmalar için çok uygun değildir. Bunu daha yüksek seviyeli ilkel kullanarak tarif edeceğim.

Anahtar fikir

Buradaki fikir, kenarlardaki etiketleri tutarlı tutarken, kenarlarda düzenli ifadeleri düşünmek ve ardından ara durumları kaldırmaktır.

Ana desen, aşağıdaki şekillerde görülebilir. İlki arasında normal ifadeler olan e , f , g , h , i etiketlerine sahip ve q ' yu kaldırmak istiyoruz .p,q,re,f,g,h,iq

pqr otomat

Kaldırıldıktan sonra, birlikte oluştururuz ( p ve r arasındaki diğer kenarları korurken ancak bu gösterilmez):e,f,g,h,ipr

görüntü tanımını buraya girin

Örnek

Raphael'in cevabındakiyle aynı örneği kullanarak :

1-2-3 otomat

art arda kaldırıyoruz :q2

1-3 otomat

ve :q3

1 otomat

Sonra biz hala gelen ifadeye Yıldız eklemek zorunda ile q 1 . Bu durumda, son durum da başlangıçta olduğundan gerçekten bir yıldız eklememiz gerekiyor:q1q1

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

Algoritma

L[i,j], dilin düzenli ifadesi olan için q, j . İlk önce tüm çoklu kenarları kaldırıyoruz: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

Şimdi, devlet kaldırma. Biz devlet kaldırmak istediğinizi varsayalım :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=∅εqiqkqjqk

Şimdi nasıl kullanılır remove(k)? Son halleri veya ilk halleri hafifçe silmemelisiniz, aksi halde dilin bölümlerini özleyeceksiniz.

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

Yalnızca bir son durum ve bir başlangıç ​​durum o zaman son ifade şöyledir:qfqs

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

Birkaç son durumunuz (veya hatta ilk durumlarınız) varsa, geçişli kapatma yöntemini uygulamaktan başka, bunları birleştirmenin basit bir yolu yoktur. Genellikle bu elle elde edilen bir problem değildir ancak algoritmayı yazarken bu oldukça zordur. Daha basit bir çözüm tüm çiftleri numaralandırmak için ve tüm ifadeler, elde etmek için (daha önce devlet kaldırıldı) grafikte algoritması çalıştırmak varsayılarak , sadece ilk durumu ve nihai sadece Devlet, sonra tüm yapıyorum .(s,f)es,fsfes,f

Bu, ve bunun dilleri ilk yöntemden daha dinamik olarak değiştirmesi, programlama sırasında hataya daha yatkın hale getirir. Başka bir yöntem kullanmanızı öneririm.

Eksileri

Bu algoritmada, örneğin hangi düğümü kaldırmamız gerektiğinin seçilmesi, sondaki son durumların sayısı, son bir durumun da başlangıç ​​olabileceği gerçeği gibi birçok durum vardır.

Şimdi algoritmanın yazıldığına dikkat edin, bu geçişli kapatma yöntemine çok benziyor. Sadece kullanımın içeriği farklı. Algoritmanın uygulanmasını önermiyorum, ancak bunu elle yapmak için yöntemi kullanmak iyi bir fikirdir.


1
Örnekte, 2. görüntüde, "2" düğümü çıkarıldıktan sonra, düğüm A'da bir kenar eksik - ilmek kenarı (ab) vardır.
Panos Kal.

@ Kabamaru: Sabit. Fakat şimdi , 3. görüntüdeki da ve benzer şekilde belki de son normal ifadede olması gerektiğini düşünüyorum . εab
Wandering Logic

Yeni bir başlangıç ve yeni bir son durum ekleyerek ve bunları -edges ile orijinal başlangıç ​​ve son durumlara bağlayarak , algoritmayı istediğiniz sayıda başlangıç ​​ve son durum için çalıştırabilirsiniz. Şimdi tüm orijinal durumları kaldırın . İfade daha sonra kalan tek kenarda ile . İnşaat, ya da da döngüler çünkü bu durumların yoktur. giden kenarlar. Veya katıysanız, boş kümeyi temsil eden etiketleri olacaktır. q+qεq+qq+q
Hendrik Jan

1
İkinci örnekte hala bir sorun var: basitleştirmeden önce otomata "ba", (1, 3, 1) kabul eder, ancak basitleştirmeden sonra kabul etmez.
wvxvw

50

Yöntem

Gördüğüm en güzel yöntem, otomatonu çözülebilecek (normal) dillerin denklem sistemi olarak ifade eden yöntem. Diğer yöntemlerden daha özlü ifadeler vermiş gibi göründüğü için özellikle güzel.

Let olmayan bir NFA -transitions. Her durumu için denklemi yaratınA=(Q,Σ,δ,q0,F)εqi

Qi=qiaqjaQj{{ε}, qiF, else

burada bir son halin ve setidir bir geçiş olduğu anlamına gelir için ile etiketlenmiş . veya olarak okursanız (normal ifade tanımınıza bağlı olarak), bunun normal ifadelerin bir denklemi olduğunu görürsünüz.Fqiaqjqiqja+

Sistemi çözmek için, ve (string bitiştirme), ve Arden's Lemma ¹ nın birleşimine ve dağıtıcılığına ihtiyacınız var :

Let düzenli diller . Sonra,L,U,VΣεU

L=ULVL=UV

Solüsyon düzenli ifadeler kümesidir , her devlet için bir tane . , başlatıldığında tarafından kabul edilebilecek sözcükleri tam olarak ; bu nedenle (eğer başlangıç ​​durumu ise) istenen ifadedir.q i Q i A q i Q 0 q 0QiqiQiAqiQ0q0


Örnek

Netlik açısından, singleton setlerini elementleri ile ifade ederiz, yani . Örnek Georg Zetzsche'den kaynaklanmaktadır.a={a}

Bu NFA'yı düşünün:

örnek nfa
[ kaynak ]

İlgili denklem sistemi:

Q0=aQ1bQ2εQ1=bQ0aQ2Q2=aQ0bQ1

Şimdi üçüncü denklemi ikinciye takın:

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

Son adım için, , ve . Üç dilin de normal olduğunu ve lemma uygulayabilmemizi sağlayan olduğunu unutmayın. Şimdi bu sonucu ilk denklemde gösteriyoruz: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)

Böylece, yukarıdaki otomat tarafından kabul edilen dil için, yani

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

Oldukça özelsin (diğer yöntemlerin sonuçlarıyla karşılaştırın), ancak benzersiz bir şekilde belirlenemediğine dikkat edin; denklem sistemini farklı manipülasyon dizileriyle çözmek diğerine eşdeğerdir! -- ifade.


  1. Arden'in Lemması'nın bir kanıtı için buraya bakın .

1
Bu algoritmanın zaman karmaşıklığı nedir? Üretilen ifadenin boyutuna bir sınır var mı?
jmite

@jmite: Hiçbir fikrim yok. Bunu uygulamaya çalışacağımı sanmıyorum (diğer yöntemler bu konuda daha elverişli görünüyor) ancak bir kalem-kağıt yöntemi olarak kullanıyorum.
Raphael

1
İşte bu algoritmanın bir Prolog uygulaması: github.com/wvxvw/intro-to-automata-theory/blob/master/automata/… ancak öngörüsümaybe_union/2 , düzenli düzenli ifadeler yapmak için daha fazla iş kullanabilir (özellikle ortak öneki ortadan kaldırarak). Bu yöntemi görmenin bir başka yolu, Prolog benzeri birleştirme veya ML benzeri desen eşleştirmeli dillerin çok iyi bir transdüser için yaptıkları, regex'ten sağa doğrusal gramerciye çeviri olarak anlamaktır. algoritma :)
wvxvw 23:15

Sadece bir soru. İlk denklemdeki ε Qo'nun başlangıç ​​durumu olması veya nihai durum olması nedeniyle mi? İki nihai devletim varsa da aynı şekilde uygulanabilir mi?
Georgio3

@ Yukarıdaki tanımını kontrol edin (satır); çünkü son durumdur. Qiq0
Raphael

28

Brzozowski cebirsel yöntem

Bu, Raphael'in cevabında açıklanan yöntemle aynıdır , ancak sistematik bir algoritma ve daha sonra gerçekten de algoritma açısından. Nereden başlayacağınızı öğrendikten sonra uygulamanın kolay ve doğal olduğu ortaya çıkıyor. Ayrıca, eğer tüm otomatların çizilmesi bir nedenden ötürü pratik değilse, elle yapmak daha kolay olabilir.

Bir algoritma yazarken, denklemlerin her zaman lineer olması gerektiğini hatırlamanız gerekir, böylece denklemlerin iyi bir soyut temsiline sahip olacaksınız, el ile çözerken unutabileceğiniz şeyler.

Algoritma fikri

Nasıl çalıştığını anlatmayacağım çünkü daha önce okumayı önerdiğim Raphael'in cevabında iyi iş çıkardın . Bunun yerine, fazladan fazla hesaplama veya fazladan durum olmadan denklemleri hangi sırayla çözmeniz gerektiğine odaklanıyorum.

Başlayarak Arden'in kuralı 'ın ustaca çözümü dili denkleme biz formun denklem kümesi olarak Otomaton düşünebiliriz:X=ABX=AXB

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

buna göre ve dizilerini güncelleyerek indüksiyon yaparak çözebiliriz . adımında , biz var:nAi,jBi,jn

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

Arden'in kuralı bize şunları veriyor:

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

ve ve ayarını :Bn=An,nBnAn,i=An,nAn,i

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

ve sistemde tüm gereksinimlerini için ayarlayarak kaldırabiliriz :Xni,j<n

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

olduğunda çözdüğümüzde şu gibi bir denklem elde ederiz:Xnn=1

X1=B1

bir ile . Böylece düzenli ifademizi aldık.A1,i

Algoritması

Bu sayede algoritmayı geliştirebiliriz. Yukarıdaki indüksiyondaki ile aynı konvansiyona sahip olmak için, ilk durumun olduğunu ve durum sayısının olduğunu . İlk olarak, doldurmak için başlatma :q1mB

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

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

ve sonra çözme:

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]

Son ifade şudur:

e := B[1]

uygulama

Bir algoritma için çok sembolik görünen bir denklem sistemi gibi görünse de, bu uygulama için çok uygundur. İşte bu algoritma Ocaml (kırık link) bir uygulamasıdır . İşlevden ayrı olarak brzozowski, her şeyin yazdırmak veya Raphael'in örneğini kullanmak için olduğunu unutmayın. Düzenli ifadelerin basitleştirilmesinde şaşırtıcı derecede etkili bir işlev bulunduğunu unutmayın simple_re.


4
Link öldü ...
Columbo


24

Geçişli kapatma yöntemi

Bu yöntemin bir algoritma biçiminde yazması kolaydır, ancak çok büyük düzenli ifadeler oluşturur ve el ile yaparsanız, çoğunlukla bu çok sistematik olduğu için pratik değildir. Yine de bir algoritma için iyi ve basit bir çözüm.

Anahtar fikir

Let dizeleri düzenli ifade giden temsil için durumlarını kullanarak . Otomatların durum sayısı olsun .Ri,jkqiqj{q1,,qk}n

Zaten düzenli ifade biliyorum varsayalım dan için ara devlet olmadan herkes için, (ekstremitelerde hariç) . Ardından, başka bir durum eklemenin yeni normal ifade ifadesini nasıl etkileyeceğini tahmin edebilirsiniz : yalnızca doğrudan geçişleriniz varsa değişir ve şöyle ifade edilebilir:Ri,jqiqjqki,jRi,jqk

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

( , dir ve , .)RRk1RRk

Örnek

Raphael'in cevabındaki gibi aynı örneği kullanacağız . İlk başta, yalnızca doğrudan geçişleri kullanabilirsiniz.

İşte ilk adım (a etiketli öz döngüsünün ilk dönüştüğünü unutmayın .aε(ε+a)

R0=[εabbεaabε]

İkinci adımda kullanabiliriz (ki bu bizim için olarak yeniden adlandırılmıştır , çünkü zaten yukarıdaki amaç için kullanılmaktadır). nasıl çalıştığını göreceğiz .q0q1R0R1

Kaynaktan için : .q2q2R2,21=R2,20+R2,10R1,10R1,20=ε+bεa=ε+ba

Neden? Bu gidiş nedeni için sadece kullanılarak bir ara devlet burada kalıyorum (yapılabilir olarak ) ya da giderek ( orada döngü,) ( ) ve geri geliyor ( ).q2q2q1εq1aεb

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

Bunun gibi ve de hesaplayabilirsiniz ve size son ifadeyi verecektir çünkü hem başlangıç ​​hem de sondur. İfadelerin basitleştirilmesinin burada yapıldığını unutmayın. Aksi takdirde, ilk bölgesinin olacaktır ve birinci bölgesinin olur .R2R3R1,131aR0(+a)aR1((+a)+ε(ε)a)

Algoritma

Başlatma:

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

Geçişli kapatma:

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)

O zaman son ifade şöyledir (varsayalım ki ilk durumdur):qs

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

Ancak bunun çirkin düzenli ifadeler oluşturduğunu hayal edebilirsiniz. Gerçekten de aynı dili temsil eden gibi şeyleri bekleyebilirsiniz . Düzenli bir ifadeyi basitleştirmenin pratikte faydalı olduğunu unutmayın.bir bir()+(a+())(ε)(a+)aa

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.