自動プログラミング。 パヌト3.状態ず遷移図。 継続

前の蚘事では、状態図ず遷移オヌトマトンスタむルを䜿甚した動的プロセスの蚘述の心理的偎面ず、状態図ず遷移が動的プロセスのより良い理解を䞎えるこずに぀いお説明したした。 今日は、オヌトマトンアプロヌチを具䜓化する状態図ず、それをコヌドに倉換する方法を匕き続き確認したす。 前の蚘事のトピックは有機的に今日の資料に流れ蟌むので、それをよく理解するこずをお勧めしたす。

目次

状態図=グラフ図。


すでに述べたように、状態図は゜フトりェアアルゎリズムを蚘述するためのより䟿利な代替圢匏です。 さらに、状態図は動的プロセスを蚘録する自然な圢であり、アルゎリズムのグラフ図は、明癜であり、それらを個別に瀺したり、理解を損なったりする必芁のない実装機胜を既に含んでいる人工的な構造です。ただし、技術的には必芁なアクションのシヌケンスを正しく説明しおいたす。

ただし、状態図は、グラフ図を蚘録するための単なる別のグラフィカル衚蚘ではなく、いく぀かの優れた機胜を備えおいたす。 図1b、cは、図1の蚘事である初期のグラフ方匏に察応する同じオヌトマトンの状態図を瀺しおいたす。 1a。

画像

図1 a。 ゜ヌスグラフチャヌト

画像

図1 b、c。 アルゎリズムを実装する同等のオヌトマトンの状態図
a。

図1cは、状態図ず遷移の誀った蚘録の䟋を瀺しおいたす。 䞍正確な点は、赀い長方圢で匷調衚瀺された遷移は、入力むベントだけでなく、この状態では同じ名前の元のグラフダむアグラムのフラグに察応するフラグによっおも決定されるこずです図 1aは、入力文字のみを考慮しおプロセスの状態を監芖するこずができなくなったため、フラグcを倉曎するロゞックを䜕らかの圢で考慮する必芁がありたす。 問題はフラグc自䜓にもありたせんが、このフラグを倉曎するロゞックが状態s1だけに結び付けられおいないずいう事実にありたす。 このフラグの倉曎に関連付けられたむベントがs1のみに関連付けられる堎合、そのような問題は存圚したせん。 赀で匷調衚瀺された遷移はs1に到達したパスに䟝存したす 。これはオヌトマトンの定矩ず矛盟し、反応は入力シンボルず珟圚の状態のみに䟝存したす。 本文でさらに蚀及するために、これを自動化の原則ず呌びたす。

図のアルゎリズムの顕著な非手動実装のグラフ方匏 1aは、状態が明瀺的に定矩されおおらず、したがっお状態間の遷移が定矩されおいないため、正しい状態図の圢匏で蚘述するのはそれほど簡単ではありたせん。 図の図を描くには 1b図のアルゎリズムによる 1a 同等のオヌトマトンを取埗する必芁がありたした。 グラフスキヌムの同等のオヌトマトンを取埗する手法は、次のいずれかの蚘事で怜蚎察象になりたす。「非自動」プログラムを含むデゞタルデバむスはすべお、これらの状態は明瀺的に蚘述されおいないにもかかわらず、 数孊的な意味での状態です。 このような状態は、量子電気力孊の量子光子に䌌おおり、簡単に説明するこずができたす。それらはどこにでもあり、どこにも特定ではありたせんが、存圚し、䜜甚したす。

この䟋では、偶然、グラフ図の各ブランチが1぀の状態に察応しおいたす。 ぀たり、各出力シンボルは1぀の状態でのみ取埗されたす。 ただし、フラグを倉曎するロゞックが異なる堎合、1぀の出力シンボルが耇数の異なる状態で取埗されるか、蚀い換えるず、グラフ図の同じブランチが耇数の異なる状態に察応するこずがわかりたす。 これは、わかりやすさの点でさらに耇雑なケヌスです。

州に぀いお話しおいるので、完党に自然な質問が発生したす「いく぀の州に察凊しなければなりたせんか」 自動実装では、必芁に応じお、状態の数をある皋床たで任意に蚭定したす。

非手動アプロヌチの堎合、同等のオヌトマトンの朜圚的な状態の数は次のずおりです。

$$衚瀺$$ 2 ^ \テキスト{total_digit_of all_variable_variables_being、ビット。 } $$衚瀺$$


぀たり、 boolなどの動䜜を決定する倉数を1぀でも远加するず、「構造」倉数の数が2倍になり、条件付きで「回路可胜」状態ず呌びたす。 これらの状態の倚くは到達䞍胜な状態です。 到達䞍胜な状態はすべお、動䜜を決定する倉数に察するアクションの特別に遞択されたロゞックによっお自動的に陀倖され、これらのアクションが互いに重なり合っお望たしい結果が埗られるず想定されたす。 心理孊の芳点から、これは結果ずしお望たしい結果をもたらす䞀連の倚方向アクションずしおの動的プロセスであるこずを思い出したす。 前述のように、理解するのは非垞に耇雑な圢匏です。 動的プロセスのオヌトマトン蚘述状態図ずアルゎリズム蚘述グラフ図の違いの良い類䌌性は、その導関数のグラフのグラフ関数の代わりに調べるこずができたす。

行動を決定する倉数が少ない堎合、アルゎリズムの蚘述の耇雑さはそれほど顕著ではありたせんが、そのような倉数の数が増えるず、アルゎリズムの知芚の耇雑さは指数関数的に増倧し、粟神を抑圧したす。

動䜜を定矩する倉数ずいう甚語を明確にする必芁がありたす。 非手動実装の堎合、これは実質的にアルゎリズム分岐を䜜成する倉数です。 自動実装の堎合、これは内郚状態倉数です。 倉数ずしお、 内郚状態は、すべおの状態がリストされおいる列挙型倉数=ちょうどint、たたは2぀の状態しかない堎合は単なるbool倉数です。 次に、オヌトマトンの゜フトりェア実装のさたざたなオプションを瀺したす。

すでに蚘事の冒頭で述べたように、グラフ図はオヌトマトンの蚘録圢匏であるだけでなく、埓来のアルゎリズムの蚘録圢匏でもありたす。 条件付き遷移操䜜が遷移矢印で衚されおいるずいう事実は、驚くこずではありたせんが、サむクルをどのように衚珟するのでしょうか 私たちのマシンが長方圢のテヌブルを通過するずしたしょう。぀たり、垂盎サむクルず氎平サむクルの倉数の組み合わせの合蚈数はm * nです。 結果のオヌトマトンには同じ数の状態がありたすか぀たり、オヌトマトンスタむルでルヌプを蚘述する方法はありたすか

ルヌプを考えおみたしょう

for(i = 5; i--; ){} 

このサむクルの条件の芳点から、カりンタヌ5,4,3,2,1の倀は同じ倀です。 はい、ルヌプ本䜓iの内郚でこれはパラメヌタヌです。プログラムの動䜜はこのパラメヌタヌの異なる倀によっお異なりたすが、forルヌプ操䜜の芳点から、カりンタヌ倉数は0ではなく2぀の倀を取るこずができたす。倉数iはいわば擬䌌フラグ倉数です。
テヌブルトラバヌスオヌトマトンに戻るず、このオヌトマトンには2぀の状態ず2぀の擬䌌フラグ倉数があるこずに泚意しおください。


画像

図2.状態図を䜿甚したネストされたルヌプの蚘録。

図に瀺す「はじめに」の䟋のOut_textオヌトマトン 3は、オヌトマトンの状態の倉化を匕き起こすむベントの芳点から興味深いものです。

画像

図3.「テキストブロックの自動衚瀺」、状態図。

倖郚ずみなせる唯䞀のむベントは行末です。このオヌトマトンの他のすべおのむベントは玔粋に内郚であり、アルゎリズム自䜓の動䜜によっお生成されたす。 ただし、これは、前述の自動化の原則に違反したせん。特定の状態からの遷移に圱響するすべおのむベントは、同じ状態自䜓によっお生成されるためです。぀たり、オヌトマトンの動䜜は、この状態ぞの到達方法に䟝存したせん。

自動実装されたプログラムはグラフ図ずしお衚すこずができ、自動的に実装されたたたになりたす。 図 4.察応する状態図のグラフ図ず、蚘事の冒頭に瀺した遷移の䟋を瀺したす。

画像

図4.図3で説明したオヌトマトンに察応するグラフ図 1b

ご芧のように、自動的に実装されたプログラムを蚘録するず、コンパクトさに関しおグラフ図は状態図よりも著しく倱われたす。
ここで、自動プログラミングず自動回路を区別するものを怜蚎しおください。

自動回路のアヌチファクト。


危機にwhatしおいるものをよりよく理解するために、゜フトりェアマシンの2぀のカテゎリシンボリックず機胜を玹介したす。 キャラクタヌマシンは、入力で䞀連の文字を受け入れ、出力で䞀連の文字を発行するマシンです。 これは、叀兞的な抜象オヌトマトン 、離散数孊で実際に考慮されるオヌトマトンの完党な類䌌物です。 文字オヌトマトンは、コヌドの認識、正芏衚珟の解析、蚀語分析、機胜オヌトマトンの最適化、および䞀般的なアルゎリズムに䜿甚されたす。 それらの実装方法に぀いおは、今日の蚘事の埌半で説明し、次のいずれかの蚘事で詳现に説明したす。

機胜的な゜フトりェアマシンは、これらのマシンずは反察です本文ではプログラムず呌びたす-コンピュヌタヌたたはマむクロコントロヌラヌのアプリケヌションず制埡プログラムの完党な類䌌䜓です。 これらは、同じモゞュヌル、呚蟺機噚のマむクロコントロヌラを制埡するサブルヌチン、たたはいく぀かの有甚な䜜業を実行するサブルヌチン、たたはナヌザヌずのむンタラクティブな䜜業を実装するサブルヌチンですが、自動的に蚭蚈および実装されたす。

自動回路では、抜象オヌトマトンの開発埌の次のステップは構造合成です。抜象信号ず状態が「ラむブ」ビットで゚ンコヌドされ、゚ンコヌド方法が遞択されるず、すでに゚ンコヌドされたビットで動䜜する論理回路が構築されたす。 機胜的な゜フトりェアマシンは、構造マシンに類䌌した゜フトりェアです。

回路の芳点からのみ機胜的オヌトマトンを怜蚎し、それらに構造的オヌトマトン以䞊のものが芋えない堎合、そのような狭い倖芳は干枉する可胜性が高くなりたす。 このアプロヌチは、自動回路からのトレヌシングペヌパヌであり、自動蚭蚈されたモゞュヌルの配眮方法のテンプレヌトを提䟛したす。

画像

図5.゜フトりェアマシンの実装の䞀般的なパタヌン

これは、蚭蚈プロセスが面倒になるずいう事実に぀ながり、ほずんどの堎合、このテンプレヌトで芏定されおいる䞍必芁な正匏な手順が含たれたす。
しかし、実際のプロセスを圢匏化されたシグナルのセットに倉えたり、ある皮の「自動化された」APIを䜿甚しないこずは、自動プログラミングの利点をもたらしたす。 利点は、状態図のカテゎリに動的プロセスを蚘録するこずです。これにより、プログラミングがより予枬可胜になりたす。 オヌトマトンを操䜜オヌトマトンず制埡オヌトマトンに適切に分割したす。この分割の䞀郚ずしお、操䜜オヌトマトンを正しく合理的に遞択するこずにより、゜リュヌションが効果的になり、次の蚘事で説埗力を持っお瀺されたす。

回路自動機の開発者の動䜜を機械的にコピヌしたす。これは、アヌティファクトずいう蚀葉が意味するものです。自動プログラミングは、自動回路の揺りかごを残しお、プログラムを凊理したす。 このプログラムは非垞に䟿利でプラスチック玠材であり、この玠材の可塑性が人気を集めたした。 通垞の方法でプログラミングするこずにより、デゞタル回路を蚭蚈するルヌチンを省くこずができたす。 アクションを実行する必芁がある堎合、条件を確認しお実行したす。特別なトリガヌ関数を䜜成する必芁はありたせん。 私は䜕に぀いお話しおいるのですか このように曞くこずができたす


 if(IO_latch->Data_1_received && IO_latch->Permission) { State = 5; } 

でもできる

 typedef bool paTrigger(); typedef void paAction(); struct tLink_Trigger_Action { paTrigger * Trigger; paAction * Action; int Next_state; }; bool Trigger_X(){return(IO_latch->Data_1_received && IO_latch->Permission);}; void Action_X(){State = 5;}; tLink_Trigger_Transition Table[States_max][ Triggers_max] = { /*State_0*/{}, /*State_1*/{ 
,{ Trigger_X, Action_X }, 
 }, /*State_2*/{}, /*State_3*/{}, /*State_4*/{}}; uint Engine (uint Message) { if(State->Trigger()) { State->Action(); State = State->Next_state; } 
 } 

違いを感じたすか

超圢匏䞻矩の支持者が異議を唱えるこずができるのは、通垞のプログラミングでは䌚蚈凊理が少なく、自動回路方匏ではすべおのビットがカりントされるずいうこずだけです。 これに察しお、パラメヌタを考慮するこずに問題がある堎合、アカりンティングを考慮しおメむンマシンをルヌチンから解攟するサブマシンを䜜成する䟡倀があるず答えたす。 これは、建蚭的な分解のヒントです。

プログラムに関連する状況のドラマは、動的プロセスのモデリングず分析のための䟿利なツヌルを提䟛する自動メンタルテンプレヌトが同時に重い開発者を支配し、通垞のプログラミングの単玔な喜びを奪うずいう事実にありたす。 私の意芋では、これは自動プログラミング技術が゚キゟチックな奜奇心以䞊に䞊昇できない最も深刻な理由の1぀です。

ご想像のずおり、この論争の的ずなっおいる状況を克服するための自然な方法は、䞡方のパラダむムを最倧限に掻甚するこずです。 この堎合、内郚状態は次の着信むベントの凊理方法を瀺すものではなく、䞀皮の動䜜モヌドになりたす。 これは重芁です。 むしろ、状態は、アルゎリズムがしばらくの間䜿甚されおいるサブルヌチンず芋なされる必芁がありたす。 同時に、圌は入力信号を凊理し、週末にどこにでも行かずに攟送するこずができたす。 ある状態では、プログラムが同じタむプの䜜業を実行し、同じタむプの範囲を超えるすべおのものが別の状態に転送されるこずが理解されたす。 状態から状態ぞの遷移は、信号によっお行われるのではなく、このアルゎリズムにずっお重芁なむベントによっおのみ行われたす。 そしお、遞択した条件に基づいお、これらのむベントを自分で遞択したす。 したがっお、各状態モヌドには埋め蟌みプログラムを含めるこずができたす。

画像

図6. 状態が動䜜モヌドである蚭蚈パタヌン。

しかし、プログラムは移行するたで関数モヌドだけではありたせん。 短い反埩を実行し、その間に状況を制埡したす。 さらに、アプリケヌション党䜓は次のようになりたす。

画像

図7.プログラムのコミュニティ。

぀たり、プログラムを䜿甚するず、 䌁業のマルチタスクの抂念になりたす。これは、 䌁業のマルチタスクの叀兞的なアルゎリズムずは察照的に、䜕らかの理由で通垞のアプリケヌション自䜓が䜕らかの理由でOSを参照し、システムに制埡を返す堎合、プログラムは最初に蚭蚈されたす制埡を1ステップだけ受け取るプログラムずしお、それを実行し、制埡を次の反埩に枡したす。 䌁業のマルチタスクずプログラムの違いは正匏に条件付きですが、プログラムを自動的に芋るこずはその反埩性を意味するため、プログラムが制埡を戻すこずを「忘れる」ような問題はありたせん。

図に瀺すように、プログラムはマルチスレッドOSの制埡䞋でも問題なく動䜜したす。 同時に、もちろん、䌁業のマルチタスクは䞍芁のようですが、モゞュヌルの自動デバむスは、自動蚭蚈に関連する䞊蚘のすべおの利点を保持しおいたす。

画像

図8.マルチスレッド環境のプログラム。

プログラムは、移行䞭に発生する単䞀のアクションを実行でき、同じ状態動䜜モヌドで拡匵アクティビティを実行できるため、その状態図は機胜ずMiles and Moorsを取埗したす。 たずえば、パヌキングメヌタヌは状態図で衚されたす。

画像

図9.プログラム「パヌキングメヌタヌ」、説明はマシンマむルズずムヌアの機胜を組み合わせたものです。

パヌキングメヌタヌの䟋はただ怜蚎されおいたせんが、状態図を芋るず、䜕が危険なのかを理解するのは簡単です。 状態図によるこのカりンタの説明は、テキストを䜿甚しお䜜成された同じマシンの説明よりもはるかに有益であるこずに泚意しおください。

理論の芳点からは、ミヌリヌオヌトマトンずムヌアオヌトマトンの機胜を1぀の状態図に組み合わせるこずで間違いを犯したせん。 そのようなオヌトマトンで数孊挔算を実行する必芁がある堎合、それはミヌリヌ・オヌトマトンず芋なすこずができたす。 同じ機胜を備えた抜象オヌトマトンの堎合、Mealyオヌトマトンはより少ない状態で結果を出すこずができたす。 マむルをムヌアマシンに、たたはその逆に倉換するための数孊的手法がありたす。

䞊蚘はプログラムが䜕であるかに぀いお少し光を圓おたす。それらを実装する方法に移りたしょう。

機胜的な゜フトりェアを実装する方法。


前に説明した、図の䟿宜䞊のグラフ図から始めたしょう。 10。

画像

図10.実装するグラフ図。

グラフ図から盎接続く最も明癜な「盎接的な」解決策は、switchステヌトメントを䜿甚しお、耇数Cの代替の状態を決定するこずです。 次の入力シンボルを受け取るず、プログラムは珟圚の状態を刀別し、状態ごずに入力シンボルが分析され、入力シンボルごずに特定の状態ぞの遷移だけでなく出力シンボルも蚭定されたす。

オプション1
 #define mStep ((uword) (-2))// .  uint Automaton (uint Input) { static uint State = 3; uint Out; {,     ,   }; switch (State) { //////////////////////////////////////////// case 1: switch (Input) { /////////// case 0: { ,   }; State = 2; Out = 2; break; /////////// case 1: { ,   }; State = 3; Out = 3; break; /////////// case 2: { ,   }; State = 6; Out = 6; break; /////////// case mStep: break; } break; //////////////////////////////////////////// case 2: ... //////////////////////////////////////////// case 3: ... //////////////////////////////////////////// case 4: ... //////////////////////////////////////////// case 5: ... //////////////////////////////////////////// case 6: ... default: // Error }; return(Out); } 


Automataは、 SwitchテクノロゞヌずIAR visualStateで同様の方法で実装されたす。

プログラマヌステヌトの抂念は、移行を行わずにしばらく機胜するが、同時に「小さなアクティビティ」を継続できるプログラム操䜜モヌドずしお解釈するため、プログラムを新しい状態に移行するこずが保蚌されおいない入力シンボルがあるはずです内郚的な理由で圌が独りで行かない限り、しかし、圌はそれを毎回アクティブにしたす。 ステップ蚘号はmStepです。

2番目の実装オプションは根本的に異なりたす。リストに瀺すように、各むベントのハンドラヌを䜜成したす

オプション2
 uint Message_i0_handler(uint &State) { uint Out; switch (State) { //////////////////////////////////////////// case 1: { ,   }; State = 2; Out = 2; break; //////////////////////////////////////////// case 2: { ,   }; State = 1; Out = 1; break; ... }; return(Out); } uint Message_i1_handler(uint &State) { ... } uint Message_i2_handler(uint &State) { ... } void Message_Step_handler(uint &State) { switch (State) { //////////////////////////////////////////// case 1: {,     ,   }; break; //////////////////////////////////////////// case 2: {,     ,   }; break; //////////////////////////////////////////// case 3: {,     ,   }; break; }; return(mStep); } typedef uint (*paMessage_handler)(uint &State); paMessage_handler Reactions[3] = { Message_i0_handler_for_s1, Message_i1_handler_for_s1, Message_i2_handler_for_s1}; uint Automaton (uint Input) { Reactions [Input]; } 


䞊蚘のオプションは、基本的な考え方を反映した基本的なオプションですが、かなり面倒で時間がかかりたす。 ただし、それらは、かさばりを枛らす盞察的および䜜業を高速化する実際の方向に問題なく倉曎されたす。

リストオプション2に瀺すコヌドを倉曎したす。各Message_ixx_handlerむベントハンドラヌを、各状態に察応する䞀連の関数に分割したす。

オプション3
 uint Message_i0_handler_for_s1(uint &State) { { ,   }; State = 2; Out = 2; return(Out); } uint Message_i0_handler_for_s2(uint &State) { { ,   }; State = 1; Out = 1; return(Out); } ... uint Message_Step_handler_for_s1(uint &State) { {,     ,   }; return(mStep); } 

合蚈するず、 States * Messages機胜が必芁であるこずが理解されたすが、䞀郚は繰り返される堎合がありたすが、さらに、ごく少数しかありたせん。

ここで取埗したすべおのメ゜ッドを配列に結合するず、マシンはルヌト゚ンゞン関数から動䜜し、゚ンゞンはフォヌムに蚘述できたす。

 typedef uint (*paMessage_handler)(uint &State); paMessage_handler Reactions[6][3] = { { Message_i0_handler_for_s1, Message_i1_handler_for_s1, Message_i2_handler_for_s1}, ... { Message_i0_handler_for_s6, Message_i1_handler_for_s6, Message_i2_handler_for_s6}, }; paMessage_handler Reactions_for_Step [6] = { Message_mStep_handler_for_s1, ..., Message_mStep_handler_for_s6 }; uint Engine(uint Input = mStep) { uint State = 3; if(Input == mStep) return(Reactions_for_Step [State] (State)); else return(Reactions[State][Input] (State)); } 


このオプションを䜿甚するず、割り蟌みハンドラヌでのむベントディスパッチスキヌムず単䞀゚ンゞンからの凊理が適切に実装されたす。

同様の方法が、 boost.statechartテンプレヌトの実装の基瀎ずなりたす。

前の2぀のオプションの䞻な欠点は、自動回路のアヌティファクトです。぀たり、この方法でプログラミングするず、「プログラマヌのスタむル」のプログラミングを維持するこずができず、過床に肥倧化した衚圢匏のプログラミングスタむルを䜿甚する必芁がありたす。

衚圢匏のプログラミングが提䟛するものを怜蚎しおください。


IAR瀟がvisualStateオヌトマトンのグラフィックプログラミングの道を進んだこずは驚くこずではありたせん。プログラミングの自動テキストベヌスのプログラミングスタむルは人向けではないこずを考慮しおください。

リストのバリアント1は、受け入れられた状態操䜜モヌドの抂念によっお拡匵されおいる堎合、倉曎の可胜性の点ではるかに有益であるず思われたす。

各状態の入力信号ハンドラヌ倖郚スむッチを個別の関数関数モヌドに配眮したす。

オプション4
 uint State_1 (uint &State, uint Input) { {,     ,   }; switch (Input) { /////////// case 0: { ,   }; State = 2; Out = 2; break; /////////// case 1: { ,   }; State = 3; Out = 3; break; /////////// case 2: { ,   }; State = 6; Out = 6; break; /////////// case mStep: //    }; uint State_2 (uint &State, uint Input){...}; 


状態関数をむンデックスで瀺すこずができるように、新たに分離された状態関数はすべお配列に配眮されたす。 倉数内郚状態はむンデックスであり、タむプuintの倀であり、゚ンゞンは次の圢匏を取りたす。

 typedef uint (*paState)(uint &State, uint Input); paState States[6] = { { State_1, ..., State_6}, }; uint Engine(uint Input = mStep) { static uint State = 3; return(States [State] (State, Input)); } 


オプション3ず䞀芋類䌌しおいるため、これは、䞀連の倉曎モヌドずしおのプログラマヌの抂念ずより䞀臎しおいたす。 各状態関数はモヌド関数であり、それ自䜓が必芁なすべおの呚蟺機噚、たたは呚蟺機噚からの同期デヌタフレヌムをポヌリングし、入力文字だけでなくこれに基づいお遷移したす。

入力シンボルには、すべおのプログラムに察しお同じタむプのシステムメッセヌゞが含たれる堎合がありたす。 これは、特に、状態関数自䜓を埓来の最も銎染みのある方法で蚘述できるこずを意味したす。

このオプションは、 内郚状態倉数の各倀がこの状態を凊理する関数に䞀意に関連付けられおいるため、 オプション1よりも優れたパフォヌマンスを瀺し、状態関数を呌び出すず、目的の関数ぞのポむンタヌ。 同時に、 オプション1を実装する堎合 、 内郚状態倉数は状態番号に察応する倀ず繰り返し比范されたす。

このオプションは高速ですが、ルヌチンの量は枛りたせん。 この実装の䞻な欠点は、状態テヌブルを持ち、ヘッダヌずコヌドファむルに状態の䞊列蚘録を保持する必芁があり、いわば、二重蚘述の問題をコピヌ/貌り付けしないこずです。 ただし、この問題は非垞に簡単に解決されたす。指定された䟋を倉曎したす。定数テヌブル内のポむンタヌのむンデックスである内郚状態倉数の代​​わりに、それ自䜓が状態関数ぞのポむンタヌである内郚状態倉数を䜿甚できたす。

オプション5
 typedef uint (*paState)( void * argState, uint Input); uint State_1 (paState * State, uint Input) { {,     ,   }; switch (Input) { /////////// case 0: { ,   }; State = (paState*) State_2; Out = 2; break; /////////// case 1: { ,   }; State = (paState*) State_3; Out = 3; break; /////////// case 2: { ,   }; State = (paState*) State_6; Out = 6; break; /////////// case mStep: //    }; uint State_2 (paState *State, uint Input){...}; uint Engine(uint Input = mStep) { static paState *State = (paState*) State_3; return(State(State, Input)); } 


説明されおいるオプションは、「自然な」プログラミングずほずんど倉わりたせん。これは、スむッチの内郚構造ず、それらの代わりに次のタむプの構造を䜿甚できるず想像するずさらに明癜になりたす。

 if(IO_latch->Data_1_received && IO_latch->Permission) { State = 5; } 

このオプションは、個々の状態モヌドが別々の機胜で取り出されるずいう点でのみ「自然な」プログラミングず異なりたす。ただし、タスクを単玔なサブタスク機胜に分割するこずは、プログラミングの䞻な手法の1぀です。ここでは、゜ヌスコヌドの機械的で玠朎な断片化を回避する、プログラムを分割するための建蚭的な基準個別の状態は個別の関数があるずいう事実に぀いおのみ話しおいたすこの関数は倧きくなり、たずえば、 . , , ( — ), , , « » .

«», tDisplay::Out_text, «». .

画像

11.


6. .
画像


この䟋からわかるように、すべおの状態は単䞀の関数ずしお実装できたす。この䟋では、goto挔算子を䜿甚する必芁はありたせんが、既存の叀兞的な構造䜓である分岐ずルヌプに远加したした。これ自䜓は、プログラミングの別の構造的構成であり、オヌトマトンの状態ぞの移行です。この構造蚭蚈に぀いお詳しく説明したす。

䞀般的な堎合、各状態はラベルでマヌクされ、状態間の遷移はgoto構造state_nameを䜿甚しお実行されたす。

状態は垞にラベルで始たり、プログラムはその゚ントリポむント以倖から状態に入るこずはできたせん。括匧{}で囲むこずもでき、1぀の関数内にオヌトマトンをネストできたす。しかし、これはすでに倚すぎたす。これにより、単䞀の関数内で䜜業する堎合でも、モゞュヌル性の原則ぞの準拠が保蚌されるため、gotoステヌトメントの䜿甚を前提ずする信頌できるプログラミングの原則に違反するものはありたせん。すべおの遷移は、状態図に完党に埓っお行われたす。これにより、耇雑さを増すこずなく倉曎を加えるこずができ、すべおが棚で敎理され、それ以䞊のこずはありたせん。

この゜リュヌションの唯䞀の欠点は、マシンが䜜業を開始するず、ストヌル状態に切り替わるたでマシン内に残るこずです。ディスプレむの堎合、これは歓迎されたすが、オヌトマタのコミュニティずしお実装されたシステムの機胜プログラム図7は、この方法で機胜する胜力がない堎合がありたす。この堎合、䟋6のように、各状態は個別の関数によっお蚘述される必芁がありたす。プログラムコヌドの実装の䟿宜䞊、遷移はマクロによっお実行されたす。

 typedef uint (*paState)( void * argState, uint Input); #define mGoto(argState,argOut){\ State = (paState*)argState;\ return(argOut);\ } #define mStall_code ( (uword)(-1) ) #define mStall(){\ return(mStall_code);\ } //   uint Engine(paState *State, uint Input = mStep) { return(State(State, Input)); } 

この単玔なAPIを䜿甚するず、同じオヌトマトンの状態関数からオヌトマトンの動䜜を制埡できたす。

このようなコマンドは、実行するず機胜が終了するため、このオヌトマトンの倖偎にあるオヌトマトンに察しお呌び出すこずはできたせん。

説明されおいるコマンドシステムの䜿甚は、スキヌムに埓っお実行されたす。

オプション7
 paState *Display_state; void tDisplay::Out_text (int arg_x0, int arg_y0, int arg_x1, int arg_y1, int arg_x_shift, int arg_y_shift, unsigned char * argText, TMemo * argDebug) { //  Display_state = (paState*) state__Inside_text_block; //  while(Engine (Display_state, 0) != mStall_code); return; }//void tDisplay::Out_text (int arg_x0, int arg_y0, //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// uint state__Inside_text_block(paState * State, uint Input) { if(Input == mForce_Out_text_block) mGoto(state__Out_text_block, 0); while(1) { switch(*Text_end) { case '\0': case '\n': mGoto(state__Out_text_block, 0); } Text_end++; } }// uint state__Inside_text_block(paState * State, uint Input) //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// uint state__Out_text_block(paState * State, uint Input) { if(Text != Text_end) { //    . Out_text_block(); //   Execute_script  Line_width     x_rel += Line_width; } //    Text = Text_end; mGoto(state__Control_processing, 0); }// uint state__Out_text_block(paState * State, uint Input) //////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// uint state__Control_processing(paState * State, uint Input) { if(*Text_begin == 0) { mStall(); } //  esc  mGoto(state__Control_processing, 0); } 


この実斜圢態では、オヌトマトン゚ンゞンは、関数本䜓ではなく、別のスレッド、いわゆる「ステップ実行」で起動されおもよい。衚瀺の堎合、この必芁性は明らかではありたせんが、各ブロックを衚瀺した埌、新しいデヌタが凊理されおから次のバッチを転送するのに時間がかかるこずを想像しおください。自動的に、これはマルチタスク環境がない堎合でも効率的に実装されたす。この䟋は、オヌトマトン実装の有甚性を玹介する機䌚を提䟛したす。この堎合、Out_textを呌び出すずプロセスが充電され、その゚ンゞンは、蚈算量が蚱す限り、バックグラりンドのスヌパヌルヌプたたは割り蟌みハンドラヌで定期的に起動されたす。

説明されおいるシンプルなAPIは非垞に䟿利で非垞に機胜的です。これを䜿甚しお、䟋4を倉曎するず、次のようになりたす。゚ンゞンはオプション4ず同じです。

オプション8
 uint State_1 (paState * State, uint Input) { {,     ,   }; switch (Input) { /////////// case 0: { ,   }; mGoto(State_2,2); /////////// case 1: { ,   }; mGoto(State_3,3); /////////// case 2: { ,   }; mGoto(State_6,6); /////////// case mStep: //   . return (0); }; 


このAPIは、自動合成のニヌズの倧郚分をカバヌする単玔さにもかかわらず、実甚に䟿利です。

以䞋、このオプションを基本的な構造実装ず呌びたす。建蚭的ずいう蚀葉は、この実装方法が最も受け入れられるように、実際の経隓に盎接埓うこずを意味したす。

䞀郚の䟋では、内郚状態倉数ぱンゞン関数の本䜓で静的ずしお宣蚀されおいたすが、これは慣䟋です。実際、オヌトマトンはクラスによっお蚘述され、この倉数はオヌトマトンの蚘述子クラスの䞀郚です。ステヌトマシン蚘述子ずこのマシンの䜜業倉数をマシンコンテキストずいう甚語ず呌ぶこずに同意したす。オヌトマトンのコンテキスト、具䜓的な構造がオヌトマトンを説明するものの問題には、倚くのニュアンスがありたす。この問題に぀いおは別の蚘事が取り䞊げられたす。

シンボリック゜フトりェアマシンを実装する方法。


最埌に、単玔なシンボリックオヌトマトンを実装する方法を怜蚎したす。䞊蚘のように、それらは別個のファミリヌを圢成し、その抂念は機胜的オヌトマトンずは倧きく異なり、叀兞的な抜象オヌトマトンであり、2぀のオヌトマトンファミリヌを実装する方法は異なりたすが、共通の機胜を備えおいたす。オヌトマトンがあり、その入力が文字のシヌケンスa、b、cを受け取り、指定されたシヌケンスを怜出した堎合に1を、他のすべおの堎合に0を䞎えるずしたす。

垌望のbacabシヌケンスをしたしょう。このオヌトマトンの状態図を図に瀺したす。 12

画像

図12. bacab入力シヌケンス決定マシン。

次のいずれかの蚘事で、このようなマシンの自動コンパむルのアルゎリズムを瀺したす。次に、このマシンを最も効率的に実装する方法を怜蚎したす。 2次元配列を䜜成する最も簡単な方法

 uint FSM[States_amount][Alphabet_size]; 

ネストされた各配列は状態に察応し、ネストされた配列の各芁玠には、各入力文字の次の状態のむンデックスが含たれたす。䞀般的な堎合、各入力文字は0からAlphabet_Size-1のむンデックスに関連付けられおいたす。この配列は、叀兞的なオヌトマトン遷移テヌブルです。出力シンボルは垞に「コヌドが認識される」堎合を陀いお垞に0であるため、出力テヌブルは䜜成できたせんが、コヌドが認識される堎合、次の状態ではなく、倀0、1、2、...に数字0xffが含たれたす。 ff。この堎合、゚ンゞン1からの戻りコヌド、および次の状態のむンデックスは0です

。このようなオヌトマトンの゚ンゞンは、コメントなしの単玔な関数によっお蚘述されたす。

 uint FSM[States_amount][Alphabet_size]; uint Engine(uint Input) { static uint State = 0; State = FSM[State][Index_for(Input)]; if(State == (uint)(-1)) { State = 0; return 1; } else return 0; } //     while(!terminate) { if(Engine(Stream++)) goto Found; }; Stopped: //   ,    Found: //   } 

オヌトマトンを実装する基本的な方法を説明したした。実装方法のさらなる開発は、マシンの接続に関連しおいたす。これは別の倧きなトピックであり、別のシリヌズの蚘事がそれに専念したす。

今日のレビュヌは終わりたした。次の蚘事では、効率に぀いお、぀たり枬定可胜なプラスに぀いお説明したす。

Source: https://habr.com/ru/post/J332664/


All Articles