8

I have the following images:

Binary Decision Diagram (BDD):

Binary Decision Tree (BDT):

and I would like to draw them in LaTeX with TikZ.

Furthermore, I would like to make them "consistent" between each other (i.e., 0-edges becomes dashed arrows in both images, the two pictures must be in black and not in grayscale, no need for the labels on the arrows of the BDD).

How can this be done ?

So far I can only make the BDT with one style of arrow, and I have absolutely no idea how to make the BDD :|

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,arrows,positioning}
\begin{document}
\tikzset{
treenode/.style = {align=center},
c/.style = {treenode,circle,draw=black,minimum width=1.5em,minimum height=1.5em,text centered,font=\footnotesize},
r/.style = {treenode,rectangle,draw=black,minimum width=1.5em,minimum height=1.5em,text centered,font=\footnotesize},
level 1/.style={sibling distance=60mm},
level 2/.style={sibling distance=30mm},
level 3/.style={sibling distance=15mm},
level 4/.style={sibling distance=7mm}
}
\begin{tikzpicture}[->,>=stealth',thick] 
\node[c] {a}
    child{ node[c] {b} 
            child{ node[c] {c}
                    child{ node[c] {d}
                        child{ node[r] {0}}
                        child{ node[r] {0}}
                    }
                    child{ node[c] {d}
                        child{ node[r] {0}}
                        child{ node[r] {1}}
                    }
            }
            child{ node [c] {c}
                    child{ node[c] {d}
                        child{ node[r] {0}}
                        child{ node[r] {0}}
                    }
                    child{ node[c] {d}
                        child{ node[r] {0}}
                        child{ node[r] {1}}
                    }
            }
    }
    child{ node[c] {b}
            child{ node [c] {c}
                    child{ node[c] {d}
                        child{ node[r] {0}}
                        child{ node[r] {0}}
                    }
                    child{ node[c] {d}
                        child{ node[r] {0}}
                        child{ node[r] {1}}
                    }
            }
            child{ node [c] {c}
                    child{ node[c] {d}
                        child{ node[r] {1}}
                        child{ node[r] {1}}
                    }
                    child{ node[c] {d}
                        child{ node[r] {1}}
                        child{ node[r] {1}}
                    }
            }
    }
;
\end{tikzpicture}
\end{document}
5

How about this:

\documentclass[tikz,border=2pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}

\tikzset{%
  zeroarrow/.style = {-stealth,dashed},
  onearrow/.style = {-stealth,solid},
  c/.style = {circle,draw,solid,minimum width=2em,
        minimum height=2em},
  r/.style = {rectangle,draw,solid,minimum width=2em,
        minimum height=2em}
}

\begin{document}

\begin{tikzpicture}[node distance=1cm and 1cm]\footnotesize
   \node[c] (a) {a};
   \node[c] (b) [below right=of a] {b};
   \node[c] (c) [below left=of b] {c};
   \node[c] (d) [below=of c] {d};
   \node[r] (final-one) [below right=of d,xshift=-2pt] {1};
   \node[r] (final-zero) [below left=of d] {0};

   \draw[onearrow] (a) -- (b);
   \draw[onearrow] (b) -- (final-one);
   \draw[onearrow] (c) -- (d); 
   \draw[onearrow] (d) -- (final-one);

   \draw[zeroarrow] (a) -- (c);
   \draw[zeroarrow] (c) -- (final-zero);
   \draw[zeroarrow] (b) -- (c);
   \draw[zeroarrow] (d) -- (final-zero);
\end{tikzpicture}

\begin{tikzpicture}[
level 1/.style={sibling distance=60mm},
level 2/.style={sibling distance=30mm},
level 3/.style={sibling distance=15mm},
level 4/.style={sibling distance=7mm}
]
\node[c] {a}
    child{ node[c]  {b} edge from parent[zeroarrow]
            child{ node[c] {c} 
                    child{ node[c] {d} 
                        child{ node[r] {0}}
                        child{ node[r] {0} edge from parent[onearrow]} 
                    }
                    child{ node[c] {d} edge from parent[onearrow]
                        child{ node[r] {0} edge from parent[zeroarrow]}
                        child{ node[r] {1}} 
                    }
            }
            child{ node [c] {c} edge from parent[onearrow]
                    child{ node[c] {d}  edge from parent[zeroarrow]
                        child{ node[r] {0}} 
                        child{ node[r] {0} edge from parent[onearrow]} 
                    }
                    child{ node[c] {d} edge from parent[onearrow]
                        child{ node[r] {0} edge from parent[zeroarrow]} 
                        child{ node[r] {1}} 
                    }
            }
    }
    child{ node[c] {b} edge from parent[onearrow]
            child{ node [c] {c} edge from parent[zeroarrow]
                    child{ node[c] {d} 
                        child{ node[r] {0}} 
                        child{ node[r] {0} edge from parent[onearrow]} 
                    }
                    child{ node[c] {d} edge from parent[onearrow]
                        child{ node[r] {0} edge from parent[zeroarrow]} 
                        child{ node[r] {1}} 
                    }
            }
            child{ node [c] {c} edge from parent[onearrow]
                    child{ node[c] {d} edge from parent[zeroarrow]
                        child{ node[r] {1}} 
                        child{ node[r] {1} edge from parent[onearrow]} 
                    }
                    child{ node[c] {d} edge from parent[onearrow]
                        child{ node[r] {1} edge from parent[zeroarrow]} 
                        child{ node[r] {1}} 
                    }
            }
    }
;
\end{tikzpicture}


\end{document}

You might want to fine-tune it a bit, e.g. if you want to have curved edges in the BDD. I had to manually shift the final 1 node in order for the edge from b being truly vertical.

enter image description here enter image description here

  • I just ran across a neat trick that assures a vertical edge between b and 1 without shifting the nodes: \draw[onearrow] (b) -- (final-one.north-|b); does the job. However, the edge will, of course, not arrive at the center of the node's top border. – Philipp Imhof Aug 5 '15 at 15:47
6

A specialised tree-drawing library or package would make this task much easier and allow you to specify the tree much more concisely. Various options are available e.g. qtree (non-TikZ), tikz-qtree (like qtree but in TikZ), forest (based on TikZ) etc.

forest is the most powerful and probably the best choice here. (But I am biased.)

\usepackage{forest}

For convenience, we set up 2 styles for the edges: my edge is the basic style with an arrow; 0 my edge is a dashed variant of my edge. We define these with \tikzset making them available both when customising the style of the BDT diagram and when tweaking it for the BDD version.

\usetikzlibrary{arrows.meta}
\tikzset{
  0 my edge/.style={densely dashed, my edge},
  my edge/.style={-{Stealth[]}},
}

We now set up a style suitable for drawing BDTs of the kind shown:

\forestset{
  BDT/.style={
    for tree={
      if n children=0{}{circle},% use a circle unless there are 0 children
      draw,% draw every node
      edge={
        my edge,% use the my edge style for edges (with the arrow)
      },
      if n=1{
        edge+={0 my edge},% if the child is the first one, add the 0 my edge style (dashed)
      }{},
      font=\sffamily,% use sans serif for node text
    }
  },
}

The BDT is then straightforward:

\begin{forest}
  BDT
  [a
    [b
      [c
        [d
          [0]
          [0]
        ]
        [d
          [0]
          [1]
        ]
      ]
      [c
        [d
          [0]
          [0]
        ]
        [d
          [0]
          [1]
        ]
      ]
    ]
    [b
      [c
        [d
          [0]
          [0]
        ]
        [d
          [0]
          [1]
        ]
      ]
      [c
        [d
          [1]
          [1]
        ]
        [d
          [1]
          [1]
        ]
      ]
    ]
  ]
\end{forest}

BDT

For instructions explaining how to specify a tree in bracket notation see my explanation in this answer.

The BDD is a bit more complex and I'm not sure if I understand what is essential to the diagram and what not. Some arrows are curved, for example, but some not and I'm not always sure why.

To ensure consistency, we use the BDT style and then use two methods to tweak the code:

  1. ,phantom makes a node a 'phantom' node which affects how other nodes are spaced without being visible itself. We use these for the 'missing' nodes.

  2. tikz={} allows you to specify TikZ code which will be run after the rest of the tree is drawn. We can use this for the arrows which skip levels. We can specify the current node using (). The other node can either be named using name= - as in the case of my one in the code below - or be specified relative to the current node by using a ! node name. In this case, we use !l1 to specify the current-node's-last-child's-first-child when drawing the arrows from a and c.

Then we can write:

\begin{forest}
  BDT
  [a, tikz={\draw [0 my edge] () [bend right] to (!l1.north) ;}
    [,phantom]
    [b, tikz={\draw [my edge] () [bend left] to (my one.north) ;}
      [c, tikz={\draw [0 my edge] () [bend right] to (!l1.north) ;}
        [,phantom]
        [d
          [0]
          [1, name=my one]
        ]
      ]
      [,phantom]
    ]
  ]
\end{forest}

BDD

If you need the line from b to be a straight vertical drop, you can adjust the tree but it is a little more complex. Since the other 'skipping' arrows are curved, I don't do this as there's no obvious reason to think it necessary.

Complete code:

\documentclass[tikz,multi,border=10pt]{standalone}
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\tikzset{
  0 my edge/.style={densely dashed, my edge},
  my edge/.style={-{Stealth[]}},
}
\forestset{
  BDT/.style={
    for tree={
      if n children=0{}{circle},
      draw,
      edge={
        my edge,
      },
      if n=1{
        edge+={0 my edge},
      }{},
      font=\sffamily,
    }
  },
}
\begin{document}
\begin{forest}
  BDT
  [a, tikz={\draw [0 my edge] () [bend right] to (!l1.north) ;}
    [,phantom]
    [b, tikz={\draw [my edge] () [bend left] to (my one.north) ;}
      [c, tikz={\draw [0 my edge] () [bend right] to (!l1.north) ;}
        [,phantom]
        [d
          [0]
          [1, name=my one]
        ]
      ]
      [,phantom]
    ]
  ]
\end{forest}
\begin{forest}
  BDT
  [a
    [b
      [c
        [d
          [0]
          [0]
        ]
        [d
          [0]
          [1]
        ]
      ]
      [c
        [d
          [0]
          [0]
        ]
        [d
          [0]
          [1]
        ]
      ]
    ]
    [b
      [c
        [d
          [0]
          [0]
        ]
        [d
          [0]
          [1]
        ]
      ]
      [c
        [d
          [1]
          [1]
        ]
        [d
          [1]
          [1]
        ]
      ]
    ]
  ]
\end{forest}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.