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.
Güvenli (olay tetiklendi)
Trafik Işığı (zaman tetiklendi | sensör [olay] tetiklendi)
Otomat (olay tetiklendi, güvenli bir varyasyonu)
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.
İ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.
İ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.
Etkin durumunda, yönlendirici ConnectRetry zamanlayıcısını sıfırlar ve Bağlan durumu.
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.
Kurulu durumunda yönlendirici şunları gönderebilir/alabilir: Keepalive; Güncelleme; ve Yaşıtına/yaşıtlarından gelen bildirim mesajları.
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.
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:
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:
Devletleri:
Geçişler:
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.
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.
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.
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, goto
s 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.
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.
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:
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
Pratikte, Devlet Makineleri genellikle aşağıdakiler için kullanılır:
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)