it-swarm.asia

Sonlu Durum Makinalarına Örnekler

Sonlu durum makinelerine iyi örnekler arıyorum; dil özellikle önemli değil, sadece iyi örnekler.

Kod uygulamaları yararlıdır (genelleştirilmiş sahte kod), ancak FSM'lerin çeşitli kullanımlarını toplamak da çok yararlıdır.

Örneklerin mutlaka bilgisayar tabanlı olması gerekmez, örneğin Mike Dunlavey'in Demiryolu ağları örneği çok faydalıdır.

26
ocodo

Güvenli (olay tetiklendi)

  • Durumlar : Birden çok "kilitli" durum, bir "kilitli" durum
  • Geçişler : Doğru kombinasyonlar/anahtarlar, nihayet kilidi açılana kadar sizi ilk kilitli durumlardan kilitli durumlara yakın kilitli durumlara taşır. Yanlış kombinasyonlar/anahtarlar sizi ilk kilitli duruma geri döndürür (bazen boşta olarak bilinir.

Trafik Işığı (zaman tetiklendi | sensör [olay] tetiklendi)

  • Durumlar : KIRMIZI, SARI, YEŞİL (en basit örnek)
  • Geçişler : Bir zamanlayıcıdan sonra KIRMIZI YEŞİL, YEŞİL SARI ve SARI KIRMIZI olarak değiştirin. Çeşitli (daha karmaşık) durumlardaki arabaları algılamakla da tetiklenebilir.

Otomat (olay tetiklendi, güvenli bir varyasyonu)

  • Durumlar : IDLE, 5_CENTS, 10_CENTS, 15_CENTS, 20_CENTS, 25_CENTS, vb, VEND, CHANGE
  • Geçişler : Bozuk para, fatura, doğru satın alma tutarı üzerine VEND'ye geçiş (veya daha fazlası), ardından DEĞİŞİM veya BOŞTA'ya geçiş (değişiklik Satış Otomatınızın ne kadar etik olduğu)
28
aqua

Sınır Ağ Geçidi Protokolü Örneği

BGP, internetteki temel yönlendirme kararlarını destekleyen bir protokoldür. Belirli bir düğümden ana bilgisayarların erişilebilirliğini belirlemek için bir tablo tutar ve interneti gerçekten ademi merkezileştirir.

Ağda, her BGP düğüm bir eşdir ve altı durumdan biriyle sonlu durum makinesi kullanır Boşta , Bağlan, Etkin, OpenSent, OpenConfirm ve Kurulmuş. Ağdaki her eş bağlantısı bu durumlardan birini korur.

BGP protokolü, durumlarını değiştirmek için eşlere gönderilen mesajları belirler.

BPG istatistik çizelgesi.

BGP statechart

Boşta

İlk durum Boşta . Bu durumda BGP kaynakları başlatır ve gelen bağlantı girişimlerini reddeder ve eşle bağlantı başlatır.

Bağlan

İkinci durum Bağlan . Bu durumda, yönlendirici bağlantının tamamlanmasını bekler ve başarılı olursa OpenSent durumuna geçer. Başarısız olursa, ConnectRetry zamanlayıcısını sıfırlar ve sona erme sonrasında Etkin durumuna geçer.

Aktif

Etkin durumunda, yönlendirici ConnectRetry zamanlayıcısını sıfırlar ve Bağlan durumu.

OpenSent

OpenSent durumunda, yönlendirici bir Açık mesaj gönderir ve karşılığında bir tane bekler. Kalıcı mesajlar değiştirilir ve başarılı bir şekilde alındıktan sonra yönlendirici Kurulu durumuna yerleştirilir.

Kurulmuş

Kurulu durumunda yönlendirici şunları gönderebilir/alabilir: Keepalive; Güncelleme; ve Yaşıtına/yaşıtlarından gelen bildirim mesajları.

Daha BGP hakkında wikipedia hakkında bilgi

14
ocodo

Her türlü şeyi modellemek için kullanışlıdırlar. Örneğin, bir seçim döngüsü devletlerle birlikte (normal hükümet) - seçim denilen -> (erken kampanya) - Parlamento feshedildi -> (ağır kampanya) - seçim -> (oy sayımı) ). Sonra (oy sayma) - çoğunluk yok -> (koalisyon müzakereleri) - anlaşmaya varıldı -> (normal hükümet) veya (oy sayma) - çoğunluk -> (normal hükümet). Siyasi alt oyunu olan bir oyunda bu şemaya bir varyant uyguladım.

Oyunların diğer yönlerinde de kullanılırlar: AI genellikle devlet tabanlıdır; menüler ve seviyeler arasındaki geçişler ve ölüm veya tamamlanan seviye üzerindeki geçişler genellikle FSM'ler tarafından iyi bir şekilde modellenmiştir.

7
Peter Taylor

jquery-csv eklentisinde kullanılan CSV ayrıştırıcısı

Temel bir Chomsky Tip III gramer ayrıştırıcıdır.

Bir regex tokenizer, verileri char-by-char bazında değerlendirmek için kullanılır. Bir kontrol karakteriyle karşılaşıldığında, kod başlangıç ​​durumuna göre daha fazla değerlendirme için bir anahtar deyimine geçirilir. Kontrol dışı karakterler, gereken dize kopyalama işlemlerinin sayısını azaltmak için toplu olarak gruplanır ve kopyalanır.

Belirteç:

var tokenizer = /("|,|\n|\r|[^",\r\n]+)/;

İlk eşleşme grubu kontrol karakterleridir: değer sınırlayıcı (") değer ayırıcı (,) ve giriş ayırıcı (yeni satırın tüm varyasyonları) Son eşleşme kontrol dışı karakter gruplamasını işler.

Ayrıştırıcının yerine getirmesi gereken 10 kural vardır:

  • Kural # 1 - Her satıra bir giriş, her satır bir satırsonu ile biter
  • Kural # 2 - Dosyanın sonundaki satır sonu
  • Kural # 3 - İlk satır başlık verileri içeriyor
  • Kural # 4 - Boşluklar veri olarak kabul edilir ve girdiler sondaki virgül içermemelidir
  • Kural # 5 - Satırlar çift tırnak işareti ile sınırlandırılmış olabilir veya olmayabilir
  • Kural # 6 - Satır sonu, çift tırnak ve virgül içeren alanlar çift tırnak içine alınmalıdır
  • Kural # 7 - Alanları kuşatmak için çift tırnak işareti kullanılıyorsa, alanın içinde görünen çift tırnaktan önce başka bir çift tırnak işareti konarak kaçılmalıdır
  • Değişiklik # 1 - Alıntı yapılmayan bir alan olabilir veya olabilir
  • Değişiklik # 2 - Alıntılanan bir alan olabilir veya olmayabilir
  • Değişiklik # 3 - Girişteki son alan boş değer içerebilir veya içermeyebilir

Not: İlk 7 kural doğrudan IETF RFC 418 kaynağından türetilmiştir. Son 3, varsayılan olarak tüm değerleri sınırlamayan (yani alıntı yapmayan) modern elektronik tablo uygulamaları (Excel, Google Elektronik Tablo gibi) tarafından sunulan Edge vakalarını kapsayacak şekilde eklendi. RFC'deki değişikliklere katkıda bulunmaya çalıştım, ancak henüz soruşturmam için bir yanıt duymadım.

Kuruma yeter, şema şöyledir:

CSV parser finite state machine

Devletleri:

  1. bir girişin ve/veya bir değerin başlangıç ​​durumu
  2. bir açılış teklifiyle karşılaşıldı
  3. ikinci bir teklifle karşılaşıldı
  4. alıntılanmamış bir değerle karşılaşıldı

Geçişler:

  • a. alıntılanan değerleri (1), sıralanmamış değerleri (3), boş değerleri (0), boş girdileri (0) ve yeni girdileri (0) kontrol eder
  • b. ikinci fiyat teklifini denetler (2)
  • c. çıkış işareti (1), değer sonu (0) ve giriş sonu (0) olup olmadığını kontrol eder
  • d. (0) değerinin sonunu ve (0) girişin sonunu kontrol eder

Not: Aslında bir durumu eksik. 'C' -> 'b' işaretinden '1' durumuyla işaretlenmiş bir çizgi olmalıdır, çünkü kaçan ikinci bir sınırlayıcı, ilk sınırlayıcının hala açık olduğu anlamına gelir. Aslında, onu başka bir geçiş olarak temsil etmek daha iyi olurdu. Bunları yaratmak bir sanattır, tek bir doğru yol yoktur.

Not: Ayrıca bir çıkış durumu eksik, ancak geçerli verilerde ayrıştırıcı her zaman 'a' geçişiyle biter ve ayrıştırılacak bir şey olmadığı için durumların hiçbiri mümkün değildir.

Durumlar ve Geçişler Arasındaki Fark:

Bir durum sonludur, yani sadece bir şey ifade etmek için çıkarılabilir.

Bir geçiş, devletler arasındaki akışı temsil eder, böylece birçok şey ifade edebilir.

Temel olarak, durum-> geçiş ilişkisi 1 -> * (yani bire çok) şeklindedir. Devlet 'ne olduğunu' ve geçiş 'nasıl ele alındığını' tanımlar.

Not: Durumların/geçişlerin uygulanması sezgisel gelmiyorsa endişelenmeyin, sezgisel değil. Nihayet yapışmayı düşünmeden önce benden çok daha akıllı biriyle ilgili biraz geniş bir karşılık aldı.

Sözde Kod:

csv = // csv input string

// init all state & data
state = 0
value = ""
entry = []
output = []

endOfValue() {
  entry.Push(value)
  value = ""
}

endOfEntry() {
  endOfValue()
  output.Push(entry)
  entry = []
}

tokenizer = /("|,|\n|\r|[^",\r\n]+)/gm

// using the match extension of string.replace. string.exec can also be used in a similar manner
csv.replace(tokenizer, function (match) {
  switch(state) {
    case 0:
      if(opening delimiter)
        state = 1
        break
      if(new-line)
        endOfEntry()
        state = 0
        break
      if(un-delimited data)
        value += match
        state = 3
        break
    case 1:
      if(second delimiter encountered)
        state = 2
        break
      if(non-control char data)
        value += match
        state = 1
        break
    case 2:
      if(escaped delimiter)
        state = 1
        break
      if(separator)
        endOfValue()
        state = 0
        break
      if(newline)
        endOfEntry()
        state = 0
        break
    case 3:
      if(separator)
        endOfValue()
        state = 0
        break
      if(newline)
        endOfEntry()
        state = 0
        break
  }
}

Not: Bu Gist, pratikte dikkate alınması gereken çok şey var. Örneğin, hata denetimi, boş değerler, sondaki boş satır (geçerli olan) vb.

Bu durumda, normal ifade eşleştirme bloğu bir yinelemeyi bitirdiğinde durumdur. Geçiş, vaka ifadeleri olarak temsil edilir.

İnsanlar olarak, düşük seviyeli operasyonları daha yüksek seviyeli özetler halinde basitleştirme eğilimindeyiz, ancak FSM ile çalışmak is düşük seviyeli operasyonlarla çalışmak. Durumlar ve geçişler tek tek çalışmak çok kolay olsa da, hepsini bir anda görselleştirmek doğal olarak zordur. Geçişlerin nasıl yürüdüğünü sezene kadar tek tek yürütme yollarını takip etmenin en kolay yolunu buldum. Temel matematik öğrenmeye benziyor, düşük seviyeli ayrıntılar otomatikleşmeye başlayana kadar kodu daha yüksek bir seviyeden değerlendiremezsiniz.

Kenara: Eğer gerçek uygulama bakarsanız, eksik birçok bilgi var. İlk olarak, tüm imkansız yollar özel istisnalar getirecektir. Onları vurmak imkansız olmalı, ancak bir şey kırılırsa, kesinlikle test koşucusunda istisnaları tetikleyecektir. İkincisi, 'yasal' bir CSV veri dizgisinde izin verilenler için ayrıştırıcı kuralları oldukça gevşek olduğundan çok sayıda belirli Edge vakasını işlemek için gereken kod. Bu gerçeğe bakılmaksızın, bu, tüm hata düzeltmeleri, uzantılar ve ince ayarlardan önce FSM'yi taklit etmek için kullanılan işlemdi.

Çoğu tasarımda olduğu gibi, uygulamanın tam bir temsili değildir, ancak önemli kısımları ana hatlarıyla belirtir. Pratikte, aslında bu tasarımdan türetilen 3 farklı ayrıştırıcı işlevi vardır: csv'ye özgü bir çizgi ayırıcı, tek satırlı bir ayrıştırıcı ve tam bir çok satırlı ayrıştırıcı. Hepsi benzer şekilde çalışırlar, yeni satır karakterlerini işleme biçimleri bakımından farklılık gösterirler.

4
Evan Plaice

Bir asansörü (asansörü) düşünmenin/modellemenin sonlu durum makinesinin iyi bir örneği olduğunu buldum. Giriş için çok az şey gerektirir, ancak uygulanması önemsiz bir durumdan çok uzaktır.

Devletler, örneğin, zemin katta, birinci katta vb., Ve zemini birinci kata taşıyorlar veya üçüncü olarak zemin kata gidiyorlar, ancak şu anda 3. ve 2. katlar arasında.

Kaldırma kafesindeki ve katlardaki düğmelerin etkisi, her iki durumun da mevcut durumla birlikte basılan düğmeye bağlı olan girişler sağlar.

Üst ve alt hariç her katta iki düğme bulunur: biri asansörün yukarı çıkmasını, diğeri aşağı inmesini ister.

3
jan

Java'da basit FSM

int i=0;

while (i<5) {
 switch(i) {
   case 0:
     System.out.println("State 0");
     i=1;
     break;
   case 1:
     System.out.println("State 1");
     i=6;
     break;
   default:
     System.out.println("Error - should not get here");
     break;      
  }

} 

İşte böyle. Tamam, parlak değil, ama fikri gösteriyor.

Telekom ürünlerinde FSM'leri sıklıkla bulabilirsiniz çünkü aksi takdirde karmaşık bir duruma basit bir çözüm sunarlar.

3
Gary Rowe

Tamam, işte bir örnek. Bir tamsayıyı ayrıştırmak istediğinizi varsayalım. dd* burada d bir tam sayı basamağıdır.

state0:
    if (!isdigit(*p)) goto error;
    p++;
    goto state1;
state1:
    if (!isdigit(*p)) goto success;
    p++;
    goto state1;

Elbette @Gary'nin dediği gibi, gotos anahtarını bir switch deyimi ve durum değişkeni ile gizleyebilirsiniz. Orijinal normal ifadeye izomorfik olan bu koda yapılandırılabilecek bir uyarı:

if (isdigit(*p)){
    p++;
    while(isdigit(*p)){
        p++;
    }
    // success
}
else {
    // error
}

Tabii ki bunu bir arama tablosu ile de yapabilirsiniz.

Sonlu durum makineleri birçok yolla yapılabilir ve birçok şey sonlu durum makinelerinin örnekleri olarak tanımlanabilir. Bir şey olarak düşünmek için bir kavram kadar bir "şey" değildir.

Demiryolu Ağı Örneği

Bir FSM örneği demiryolu ağıdır.

Bir trenin iki pistten birine gidebileceği sınırlı sayıda anahtar vardır.

Bu anahtarları bağlayan sınırlı sayıda yol vardır.

Herhangi bir zamanda, bir tren bir pistte, tek bir giriş bilgisine dayanarak bir anahtarın geçilmesiyle başka bir piste gönderilebilir.

2
Mike Dunlavey

Ruby'de Sonlu Durum Makinesi:

module Dec_Acts
 def do_next
    @now = @next
    case @now
    when :invite
      choose_round_partner
      @next = :wait
    when :listen
      @next = :respond
    when :respond
      evaluate_invites
      @next = :update_in
    when :wait
      @next = :update_out
    when :update_in, :update_out
      update_edges
      clear_invites
      @next = :exchange
    when :exchange
      update_colors
      clear_invites
      @next = :choose
    when :choose
      reset_variables
      choose_role
    when :done
      @next = :done
    end
  end
end

Bu, dağıtılmış bir sistemdeki tek bir hesaplama düğümünün davranışıdır ve bağlantıya dayalı bir iletişim şeması oluşturur. Az çok. Grafik biçiminde şöyle görünür:

enter image description here

2
philosodad

Sözcüksel analizin (FSM) bazı basit örnekleri için bu bağlantıya göz atın:

http://ironbark.bendigo.latrobe.edu.au/subjects/SS/clect/clect03.html

Örnekler için "ejderha kitabına" da bakabilirsiniz (hafif okuma değildir)

http://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools

1
jmq

Pratikte, Devlet Makineleri genellikle aşağıdakiler için kullanılır:

  • Tasarım amaçları (bir programdaki farklı eylemlerin modellenmesi)
  • Doğal dil (dilbilgisi) ayrıştırıcıları
  • Dize ayrıştırma

Bir örnek, doğru söz dizimine sahip olup olmadığını görmek için bir dizeyi tarayan bir Durum Makinesi olabilir. Örneğin, Hollanda Posta kodları "1234 AB" olarak biçimlendirilmiştir. İlk kısım sadece rakam içerebilir, sadece ikinci harf. NUMBER durumunda mı yoksa LETTER durumunda mı olduğunu ve yanlış girdi ile karşılaşıp karşılaşmadığını takip eden bir Durum Makinesi yazılabilir.

Bu alıcı durum makinesinin iki durumu vardır: sayısal ve alfa. Durum makinesi sayısal durumda başlar ve denetlenecek dizenin karakterlerini okumaya başlar. Durumlardan herhangi biri sırasında geçersiz karakterlerle karşılaşılırsa, işlev Yanlış değeriyle döner ve girişi geçersiz olarak reddeder.

Python kodu:

import string

STATE_NUMERIC = 1
STATE_ALPHA = 2

CHAR_SPACE = " "

def validate_zipcode(s):
cur_state = STATE_NUMERIC

for char in s:
    if cur_state == STATE_NUMERIC:
        if char == CHAR_SPACE:
            cur_state = STATE_ALPHA
        Elif char not in string.digits:
            return False
    Elif cur_state == STATE_ALPHA:
        if char not in string.letters:
            return False
return True

zipcodes = [
    "3900 AB",
    "45D6 9A",
]

for zipcode in zipcodes:
    print zipcode, validate_zipcode(zipcode)

Kaynak: (Sonlu-) Devlet Makineleri pratikte

0
theD