【Python】簡単に状態遷移図を作成することができる!automata-libの使い方について

1. automata-lib

今回はpythonのライブラリであるautomata-libの使い方について説明させていただきます。これが使えれば、答えのないオートマトンの問題(大学の教科書)の助けになります。

1.1. インストール方法

PyPIの場合:

pip install automata-lib

Githubの場合:

pip install git+https://github.com/caleb531/automata.git

PyPIからインストールしたときに、正規表現がうまく動かなかったため、私はgithubからインストールしました。また、オートマトンのグラフを表示したい場合は、graphvizをインストールする必要があります。

1.2. 決定性有限オートマトン(DFA)

from automata.fa.dfa import DFA

まず、automata.fa.dfaからDFAをimportする必要があります。これで、DFAを作ることができるようになりました。

そして、以上の画像のオートマトンは以下のように書くとDFAを作ることができます。

dfa = DFA(
    states={'q0', 'q1', 'q2','q3'},
    input_symbols={'0', '1'},
    transitions={
        'q0': {'0': 'q0', '1': 'q3'},
        'q1': {'0': 'q3', '1': 'q2'},
        'q2': {'0': 'q3', '1': 'q1'},
        'q3': {'0': 'q2', '1': 'q3'},
        
    },
    initial_state='q0',
    final_states={'q0','q3'}
)

DFAの中に、states、input_symbols、transitions、initial_state、final_statesを辞書型で書くことでオートマトンを定義することができる。

1.3. DFAの引数の意味

states・・・状態を書く。上の場合はq0、q1、q2、q3が状態です。
input_symbols・・・DFAの入力を書きます。
transitions・・・状態遷移を書きます。例えば、上記のDFAの場合、’q0’は’0’のとき、’q0’に移動して、’1’のとき、’q3’に移動します。
initial_state・・・DFAの初期状態を書きます。
final_states・・・DFAの受理状態を書きます。

1.4. DFA.read_input

dfa.read_input('111') #'q3'
dfa.read_input('1101') #RejectionException

read_inputでは言語が受理するかどうかを判定することができます。
受理するときは、受理状態が返されて、受理しないときはRejectionExceptionとなり、エラーとなります。

1.5. DFA.accepts_input

dfa.accepts_input('111') #True
dfa.accepts_input('1101') #False

accepts_inputは言語を受理するかどうかをTrue、Falseで返してくれます。受理する場合はTrue、受理しない場合は、Falseです。

1.6. 最小化

MinDfa=dfa.minify()

minifyを用いることで、最小化することができます。
MinDfaは以下のようになります。

2. オートマトンの表示

dfa.show_diagram("dfa.png")

show_diagram()にファイル名・保存先を書くことで、オートマトンの状態遷移図の画像を作ることができます。緑色で塗られた部分が初期状態で、二重に線がひかれている部分が受理状態です。しかし、Graphvizをインストールする必要があります。

2.1. 非決定性有限オートマトン(NFA)

from automata.fa.nfa import NFA

まず、automata.fa.nfaからNFAをimportします。これでNFAを作ることができるようになりました。

DFAと基本的に同様に考えてコードを書けば問題ありません。ただし、状態遷移のvalue(例えば、’q4’の’0’のときのvalueは{‘q0′,’q2’})はsetで書きます。

nfa = NFA(
    states={'q0', 'q1', 'q2','q3','q4'},
    input_symbols={'0', '1'},
    transitions={
        'q0': {'0': {'q1'}},
        'q1': {'0': {'q1','q3','q0'}, '': {'q2','q4'}},
        'q2': {'1': {'q0'}},
        'q3': {'1': {'q2','q0'}},
        'q4':{'0':{'q0','q2'}}
    },
    initial_state='q0',
    final_states={'q3','q4'}
)

2.2. NFA.read_input

nfa.read_input('0') #frozenset({'q1', 'q2', 'q4'})
nfa.read_input('111') #RejectionException

read_inputでは同様に言語が受理するかどうかを判定することができます。
受理するときは、停止する状態が返されて、受理しないときはRejectionExceptionとなり、エラーとなります。

2.3. NFA.accepts_input

nfa.accepts_input('0') #True
nfa.accepts_input('111') #False

accepts_inputは同様に言語を受理するかどうかをTrue、Falseで返してくれます。受理する場合はTrue、受理しない場合は、Falseです。

3. 正規表現

$(aab+bba)^*$という正規表現を考えると以下のように表現することができます。

(aab|bba)*

と書きます。
+は|と書くので注意しましょう。

4. オートマトンの変換

4.1. NFAからDFA

from automata.fa.dfa import DFA
from automata.fa.nfa import NFA

DFAとNFAをimportする必要があります。
DFA.from_nfa(対象のnfa)を用いることで、DFAに変換することができます。また、NFAが変換されると、最小のDFAが生成されます。

dfa = DFA.from_nfa(nfa)

試しに、先ほど紹介したNFAをDFAに変換すると以下のようになります。

4.2. 正規表現からNFA・DFA

nfa = NFA.from_regex('(aab|bba)*', input_symbols={'a', 'b'})
dfa=DFA.from_nfa(nfa)

正規表現からNFAにNFA.from_regexを用いることで変換します。入力はinput_symbolsに定義します。上の場合はa、bが入力です。
そして、DFA.from_nfaを用いて、NFAからDFAに変換すると、正規表現からDFAを生成することができます。
上記のDFAは以下のようになります。


check

Pythonの基本から応用まで、幅広くカバーする記事を公開中です。学習のポイントや実践的なコード例を通じて、Pythonの魅力と実用性を深く理解することができます。ぜひ、こちらの記事で気になる記事を見つけてください!

Pythonの記事のまとめ

PR