1

I would like to draw an NFA and to fit it into the column width I have made it zig-zag shaped. To my greatest dismay, it looks like it just left a bar after many shots of tequila. I have tried specifying relative positions explicitly for q₇ – q₁₁ without success. Where does this extra shift come from and how do I straighten it now?automaton

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{arrows,automata,positioning}
\usepackage{libertine}

\begin{document}
\begin{tikzpicture}[->,>=stealth',semithick,node distance=2cm,shorten >=5pt]
  \node[initial,state]      (0)                                     {q₀};
  \node[state]              (1)  [above right of=0]                 {q₁};
  \node[state]              (2)  [below of=1]                       {q₂};
  \node[state]              (3)  [above right of=2]                 {q₃};
  \node[state]              (4)  [below of=3]                       {q₄};
  \node[state]              (5)  [above right of=4]                 {q₅};
  \node[state]              (6)  [below of=5]                       {q₆};
  \node[state]              (7)  [above right=1cm and 1cm of 6]     {q₇};
  \node[state]              (8)  [below of=7]                       {q₈};
  \node[state]              (9)  [above right=1cm and 1cm of 8]     {q₉};
  \node[state]              (10) [below=1cm of 9]                   {q₁₀};
  \node[state]              (11) [above right=1cm and 1cm of 10]    {q₁₁};
  \node[state,accepting]    (12) [below=1cm of 11]                  {q₁₂};

  \path (0)     edge [right]                node {\textit{F}}       (1)
        (1)     edge [right]                node {\textit{o}}       (2)
        (2)     edge [right]                node {\textit{o}}       (3)
        (3)     edge [right]                node {\textit{:}}       (4)
        (4)     edge [right]                node {␣}                (5)
        (5)     edge [right]                node {\textit{t}}       (6)
        (6)     edge [right]                node {\textit{h}}       (7)
        (7)     edge [right]                node {\textit{i}}       (8)
        (8)     edge [right]                node {\textit{n}}       (9)
        (9)     edge [right]                node {\textit{g}}       (10)
        (10)    edge [right]                node {\textit{s}}       (11)
        (11)    edge [right]                node {\textit{!}}       (12)
        (0)     edge [loop above, above]    node {$Σ$}          (0)
  ;
\end{tikzpicture}
\end{document}
4
  • 1
    Could you please be a bit more specific and tell us which output you'd like to have?
    – user121799
    Jul 14, 2018 at 11:31
  • You're mixing old above right of = positioning with the new one above right = ... of. Use only one of them and distances will keep consistent.
    – Ignasi
    Jul 14, 2018 at 12:10
  • @Ignasi I tried it now, the positioning is certainly slightly different, but the image is still skewed with a heavier right side.
    – Mr. Tao
    Jul 14, 2018 at 14:34
  • @marmot I’d like to minimize the area used, so a horizontally placed accordion-like path (like Aleanno did here) was first to come to my mind. btw: it’s not that complicated with ^+⌘+space and no parenthesis-flooded heresy can beat its readability 😉
    – Mr. Tao
    Jul 14, 2018 at 14:38

1 Answer 1

2

I think you could save a lot of code space with a \foreach (automation is love) and a couple of calculations for node placement.

The character is not showing in my example, but I guess it's not critical for the solution to work in this case.

Output

enter image description here

Code

\documentclass[margin=5pt]{standalone}
\usepackage{tikz}

\usetikzlibrary{arrows,automata}

\usepackage{libertine}

\begin{document}
\begin{tikzpicture}[->,>=stealth',semithick,node distance=2cm,shorten >=5pt]

\foreach \labels [count=\x starting from 0, remember=\x as \lastx (initially 0)] in {%
{$Σ$},
\textit{F},%
\textit{o},%
\textit{o},%
\textit{:},%
\textit{␣},%
\textit{t},%
\textit{h},%
\textit{i},%
\textit{n},%
\textit{g},%
\textit{s},%
\textit{!}%
}{
    \pgfmathsetmacro\xpos{int(\x+1-mod(\x+1,2))}
    \pgfmathsetmacro\ypos{int(mod(\x,2)*2)}
    \ifnum\x=0
        \node[initial,state] (\x) at (0,0) {$q_{\x}$};
        \path (0)  edge [loop above, above] node {\labels} (0);
    \else\ifnum\x=12
        \node[accepting,state] (\x) at (\xpos,\ypos) {$q_{\x}$};
    \else
        \node[state] (\x) at (\xpos,\ypos) {$q_{\x}$};
    \fi
        \path (\lastx) edge[right] node {\labels} (\x);
    \fi
}

\end{tikzpicture}
\end{document}
3
  • This is a beautiful solution. But can you make it use real subscripts? See here for the difference, I’ve only enclosed inner state name in \mathrm in your code.
    – Mr. Tao
    Jul 14, 2018 at 14:29
  • Quick fix would be \node[state] (\x) at (\xpos,\ypos) {q{\addfontfeature{VerticalPosition = ScientificInferior} \x}}, but this creates new font for each inner state behind the curtains. It might be wiser to define \newfontface or \newfontfamily with ScientificInferior feature enabled.
    – Mr. Tao
    Jul 14, 2018 at 15:36
  • The solution would contain \newfontfamily\libertineInferiors{Linux Libertine O}[VerticalPosition = ScientificInferior] \newcommand\sciinf[1]{\libertineInferiors{#1}} in the preamble and {$q_{\x}$} in the picture would become {q{\sciinf{\x}}}. I took a liberty of suggesting an edit, but for reasons beyond my comprehension, it was rejected by @troy.
    – Mr. Tao
    Jul 15, 2018 at 15:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .