状態遷移図を TikZ で描く

はじめに

有限オートマトン、状態機械、UML のステートマシン ── いずれも「状態(円)」と「遷移(ラベル付きの矢印)」からなる状態遷移図です。TikZ の automata ライブラリを使うと、初期状態の矢印や受理状態の二重丸まで含めて短く書けます。ノードと矢印を並べるという点は、グラフィカルモデル・可換図式・ブロック線図・深層学習のモデル図と共通です。

automata ライブラリの基本

\usepackage{tikz}
\usetikzlibrary{automata, positioning}
  • \node[state] (q0) {$q_0$}; … 状態(円)
  • \node[state, initial] (q0) {...}; … 初期状態(左から「start」矢印が付く)
  • \node[state, accepting] (qf) {...}; … 受理状態(二重丸)
  • \path[->] (a) edge node {ラベル} (b); … 遷移。edge の node が遷移ラベル
  • edge[loop above] … 自己ループ(above / below / left / right)
  • edge[bend left] / edge[bend right] … 2 状態間を行き来する遷移を曲げて重ならないようにする

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

「1 の個数が偶数の 2 進文字列」を受理する DFA です。initial と accepting を同じ状態に付けられます。

\begin{tikzpicture}[>=Stealth, node distance=32mm, on grid, auto,
  every state/.style={thick, minimum size=10mm}]
  \node[state, initial, accepting] (q0) {$q_0$};
  \node[state, right=of q0]         (q1) {$q_1$};
  \path[->]
    (q0) edge[bend left]  node {$1$} (q1)
    (q1) edge[bend left]  node {$1$} (q0)
    (q0) edge[loop above] node {$0$} ()
    (q1) edge[loop above] node {$0$} ();
\end{tikzpicture}
初期かつ受理状態の q0 と状態 q1。1 で q0 と q1 を行き来し、0 で自己ループする、1 の個数が偶数の文字列を受理する DFA

出力例:DFA。initial で start 矢印、accepting で二重丸。行き来する遷移は bend left で振り分ける。

  • on grid を付けると node distance が中心間の距離になり、格子に載せやすい
  • auto はラベルを辺の外側に自動配置する

回転木戸(turnstile)

「Locked / Unlocked」の 2 状態。硬貨(coin)で解錠、押す(push)と施錠、それ以外の入力は自己ループです。

\begin{tikzpicture}[>=Stealth, node distance=42mm, on grid, auto,
  every state/.style={thick, minimum size=13mm}]
  \node[state, initial] (L) {Locked};
  \node[state, right=of L] (U) {Unlocked};
  \path[->]
    (L) edge[bend left]  node[above] {coin} (U)
    (U) edge[bend left]  node[below] {push} (L)
    (L) edge[loop above] node        {push} ()
    (U) edge[loop above] node        {coin} ();
\end{tikzpicture}
初期状態 Locked と状態 Unlocked。coin で Locked から Unlocked へ、push で Unlocked から Locked へ、それ以外は各状態で自己ループする回転木戸の状態遷移図

出力例:回転木戸。往復の遷移を bend left で上下に分け、無反応の入力を loop above で表す。

信号機

3 状態を巡回する例です。状態を三角形に配置し、timer で次へ遷移します。

\begin{tikzpicture}[>=Stealth, auto,
  every state/.style={thick, minimum size=12mm}]
  \node[state] (R) at (0,0)      {Red};
  \node[state] (G) at (3.6,0)    {Green};
  \node[state] (Y) at (1.8,-2.6) {Yellow};
  \path[->]
    (R) edge node[above] {timer} (G)
    (G) edge node[right] {timer} (Y)
    (Y) edge node[left]  {timer} (R);
\end{tikzpicture}
Red、Green、Yellow の 3 状態が三角形に並び、timer で Red から Green、Green から Yellow、Yellow から Red へ巡回する信号機の状態遷移図

出力例:信号機。巡回する遷移は座標を直に置いて三角形に配し、ラベルの向きを個別に指定する。

素の TikZ で描く場合

automata を使わず、スタイルを自分で定義しても同じものが書けます。

\tikzset{
  st/.style       = {circle, draw, thick, minimum size=10mm},
  accept/.style   = {st, double, double distance=1.2pt},
}
\begin{tikzpicture}[>=Stealth, auto, node distance=28mm]
  \node[accept] (q0) {$q_0$};
  \node[st, right=of q0] (q1) {$q_1$};
  \draw[<-] (q0.west) -- ++(-8mm,0) node[left] {start};
  \draw[->] (q0) to[bend left] node {$1$} (q1);
  \draw[->] (q1) to[bend left] node {$1$} (q0);
\end{tikzpicture}

accepting は double、initial の矢印は左向きの \draw を 1 本足すだけです。既存の状態遷移図を他の TikZ 図と体裁をそろえたいときは、この方法が調整しやすくなります。

レイアウトのコツ

  • >=Stealth と every state/.style を最初に決め、全体の見た目をそろえる
  • node distance + on grid で状態を格子に載せる。三角形など不規則な配置は座標を直に書く
  • 往復する遷移は bend left / bend right。曲げ具合は bend angle=45 などで調整
  • 自己ループの向き(loop above ほか)は、他の遷移とラベルがぶつからない側を選ぶ
  • 長い遷移のラベルは node[sloped] で辺に沿わせる、pos=0.3 で位置をずらす

運用

図は standalone で 1 枚ずつ別ファイルにし、本文から \input します。ビルドは latexmk、環境の固定は TeX Live 入りコンテナの記事にまとめてあります。この記事の図も、上のコードを standalone でコンパイルして dvisvgm で SVG 化したものです。

関連記事

まとめ

  • 状態遷移図は automata ライブラリ。\node[state]、initial、accepting、\path (a) edge node {ラベル} (b) が基本。
  • 自己ループは loop above ほか、往復する遷移は bend left / bend right で振り分ける。
  • 配置は node distance + on grid、不規則な形は座標を直に置く。
  • 体裁を他の図とそろえたいなら、circle, draw + double で自前スタイルにしてもよい。

状態と遷移という 2 要素だけなので、automata の語彙を一度覚えれば、たいていの図は数行で書けます。

LaTeX組版・教材校正のご依頼・ご相談はコレクトコネクトへお問い合わせください。

← コラム一覧へ