[Tex/LaTex] How to draw a 8×8 Karnaugh map in LaTeX

karnaughtikz-pgf

I am quite new at using LaTeX, however now I need to draw an 8×8 Karnaugh map. I have already found many helpful codes on this topic, however when I try to modify those codes the result is simply messy.
I would appreciate the help, I am lost 🙂

Best Answer

kvmap

Ben Frank was kind enough to package this answer and put it on CTAN (package kvmap).

With the kvmap package you can input your Karnaugh map like a tabular. This works even for very large sizes (I just tested 64x64 fields), so it is definitely able to typeset an 8x8 map.

If you want to draw implicants you can use the \bundle macro and pass the coordinates of the corners to it. For further explanation see the old answer (which explains the code a bit better).

Full code example:

\documentclass{article}
\usepackage{kvmap}

\begin{document}
    \begin{kvmap}
        \begin{kvmatrix}{a,b,c,d,e,f}
        0 & 1 & 1 & 0 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\
        0 & 0 & 1 & 1 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
        0 & 1 & 1 & 0 & 0 & 0 & 0 & 0
        \end{kvmatrix}
        \bundle{3}{3}{2}{3}
        \bundle[color=blue]{3}{2}{3}{1}
        \bundle[invert=true,reducespace=2pt,overlapmargins=6pt]{1}{0}{2}{7}
    \end{kvmap}
\end{document}

Old answer

The following code will produce Karnaugh maps in any size you want it to have (tested for some 2n) as TikZ pictures. You input your map like you would input a table in LaTeX using the kvmatrix environment. The only argument of this environment is a comma-separated list of your variable names. Therefore a simple 2x2 matrix would look like

\begin{kvmatrix}{a,b}
    0 & 1\\
    0 & 1
\end{kvmatrix}

There is a second environment provided, kvmap, which is basically a tikzpicture (but for the sake of semantic consistency). You should use this if you are planning to work with the fields. Each field is named by its x- and y-index in the following way: xy (where 00 is the top-left corner and nm is the bottom-right corner with n+1 and m+1 as the dimensions of your matrix, e.g. 11 for a 2x2 matrix).

The code is also able to draw borders around cells which can be bundled. Therefore you would use the command \package[options]{x1}{y1}{x2}{y2} with the coordinates of the corners of the rectangle. If the package should be open to the margin use the invert option (if the coordinates are at the outer-most rows/columns; the overlapmargins option specifies how far the bundle is drawn into the margin). You can color a package with the color option and to avoid overlapping with other packages specify a reduction of space with reducespace.

\begin{kvmap}
    \begin{kvmatrix}{a,b}
        0 & 1\\
        0 & 1
    \end{kvmatrix}
    \package[color=red]{1}{0}{1}{1}
\end{kvmap}

Here the working code:

\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usepackage{environ}

\ExplSyntaxOn
\cs_generate_variant:Nn \seq_set_split:Nnn   { Nno, Nnx }
\cs_generate_variant:Nn \int_mod:nn          { VV       }
\cs_generate_variant:Nn \int_div_truncate:nn { VV       }

% see https://tex.stackexchange.com/questions/418853/latex3-pad-something-unexpandable
\cs_new:Npn \__kvmap_graycode_xor_bits:nn #1#2
  {
    \int_compare:nTF { #1 = #2 }
      { 0 } { 1 }
  }
\cs_new:Npn \__kvmap_graycode_xor:w #1#2\q_stop#3#4\q_stop
  {
    \__kvmap_graycode_xor_bits:nn { #1 } { #3 }
    \tl_if_empty:nF { #2 }
      {
        \__kvmap_graycode_xor:w #2\q_stop#4\q_stop
      }
  }
\cs_new:Npn \__kvmap_graycode_xor:nn #1#2
  {
    \__kvmap_graycode_xor:w #1\q_stop#2\q_stop
  }
\cs_generate_variant:Nn \__kvmap_graycode_xor:nn { xx }

\cs_new:Npn \kvmap_graycode_at:nn #1#2
{
    \__kvmap_graycode_xor:xx
      { \tl_tail:f { \int_to_bin:n { #1 - 1 + #2 } } }
      { \tl_tail:f { \int_to_bin:n { \fp_eval:n { floor((#1-1)/2) + #2 } } } }
}
\cs_generate_variant:Nn \kvmap_graycode_at:nn { nV }

\bool_new:N \l__kvmap_matrix_isintikz_bool
\int_new:N \l__kvmap_matrix_height_int
\int_new:N \l__kvmap_matrix_width_int
\cs_new:Nn \__kvmap_zeichnegraycode:
  {
    \int_step_inline:nnnn { 1 } { 1 } { \l__kvmap_matrix_width_int }
      {
\node ~ at ~ (\fp_eval:n { 0.5 + (##1-1) }, .3)
{ \kvmap_graycode_at:nV { ##1 } \l__kvmap_matrix_width_int };
      }
    \int_step_inline:nnnn { 1 } { 1 } { \l__kvmap_matrix_height_int }
      {
\node[anchor = east] ~ at ~ (0, \fp_eval:n { -0.5 - (##1-1) })
{ \kvmap_graycode_at:nV { ##1 } \l__kvmap_matrix_height_int };
      }
  }

\tikzset{kvnode/.style = { inner ~ sep = 8pt }}
\cs_new:Npn \__kvmap_zeichnematrix:n #1
{
\int_zero:N \l_tmpa_int
\seq_set_from_clist:Nn \l_tmpa_seq { #1 }
\seq_map_inline:Nn \l_tmpa_seq
{
\node[kvnode] ~
(\int_mod:VV \l_tmpa_int \l__kvmap_matrix_width_int
                    \int_div_truncate:VV \l_tmpa_int \l__kvmap_matrix_width_int ) ~
at ~
(.5+\int_mod:VV \l_tmpa_int \l__kvmap_matrix_width_int,
                -.5-\int_div_truncate:nn \l_tmpa_int \l__kvmap_matrix_width_int ) ~
{$##1$};
\int_incr:N \l_tmpa_int
}
}

\keys_define:nn { kvmap/package }
{
reducespace    .dim_set:N      = \l__kvmap_package_reducespace_dim,
reducespace    .initial:n      = { 0pt },
color          .tl_set:N       = \l__kvmap_package_color_tl,
color          .initial:n      = { black },
invert         .bool_set:N     = \l__kvmap_package_invert_bool,
invert         .initial:n      = false,
overlapmargins .dim_set:N      = \l__kvmap_package_overlapmargins_dim,
overlapmargins .initial:n      = { 0pt },
}
\tikzset{kvpacket/.style = { rounded ~ corners = 5pt }}
\int_new:N \l__kvmap_package_minx_int
\int_new:N \l__kvmap_package_miny_int
\int_new:N \l__kvmap_package_maxx_int
\int_new:N \l__kvmap_package_maxy_int
\NewDocumentCommand { \package } { O{} m m m m }
{
\group_begin:
\keys_set:nn { kvmap/package } { #1 }
\int_set:Nn \l__kvmap_package_minx_int { \int_min:nn { #2 } { #4 } }
\int_set:Nn \l__kvmap_package_miny_int { \int_min:nn { #3 } { #5 } }
\int_set:Nn \l__kvmap_package_maxx_int { \int_max:nn { #2 } { #4 } }
\int_set:Nn \l__kvmap_package_maxy_int { \int_max:nn { #3 } { #5 } }
\bool_if:nTF { \l__kvmap_package_invert_bool && (
(\int_compare_p:n  { \l__kvmap_matrix_height_int - 1 = \l__kvmap_package_maxy_int } &&
\int_compare_p:n { 0 = \l__kvmap_package_miny_int }) ||
(\int_compare_p:n { \l__kvmap_matrix_width_int - 1 = \l__kvmap_package_maxx_int} &&
\int_compare_p:n { 0 = \l__kvmap_package_minx_int } )) }
{
\int_compare:nT { \l__kvmap_matrix_height_int - 1 = \l__kvmap_package_maxy_int }
{
\draw[draw=\l__kvmap_package_color_tl,kvpacket] ~
([xshift=\l__kvmap_package_reducespace_dim,yshift=\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_miny_int . north ~ west) --
([xshift=\l__kvmap_package_reducespace_dim,yshift=\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_miny_int . south ~ west) --
([xshift=-\l__kvmap_package_reducespace_dim,yshift=\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_miny_int . south ~ east) --
([xshift=-\l__kvmap_package_reducespace_dim,yshift=\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_miny_int . north ~ east);
\draw[draw=\l__kvmap_package_color_tl,kvpacket] ~
([xshift=\l__kvmap_package_reducespace_dim,yshift=-\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ west) --
([xshift=\l__kvmap_package_reducespace_dim,yshift=-\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_maxy_int . north ~ west) --
([xshift=-\l__kvmap_package_reducespace_dim,yshift=-\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_maxy_int . north ~ east) --
([xshift=-\l__kvmap_package_reducespace_dim,yshift=-\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ east);
}
\int_compare:nT { \l__kvmap_matrix_width_int - 1 = \l__kvmap_package_maxx_int }
{
\draw[draw=\l__kvmap_package_color_tl,kvpacket] ~
([yshift=-\l__kvmap_package_reducespace_dim,
xshift=-\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_miny_int . north ~ west) --
([yshift=-\l__kvmap_package_reducespace_dim,
xshift=-\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_miny_int . north ~ east) --
([yshift=\l__kvmap_package_reducespace_dim,
xshift=-\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ east) --
([yshift=\l__kvmap_package_reducespace_dim,
xshift=-\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ west);
\draw[draw=\l__kvmap_package_color_tl,kvpacket] ~
([yshift=-\l__kvmap_package_reducespace_dim,
xshift=\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_miny_int . north ~ east) --
([yshift=-\l__kvmap_package_reducespace_dim,
xshift=\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_miny_int . north ~ west) --
([yshift=\l__kvmap_package_reducespace_dim,xshift=
\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ west) --
([yshift=\l__kvmap_package_reducespace_dim,xshift=
\l__kvmap_package_overlapmargins_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ east);
}
}
{
\draw[draw=\l__kvmap_package_color_tl, kvpacket] ~
([xshift=\l__kvmap_package_reducespace_dim,
yshift=-\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_minx_int
\int_use:N \l__kvmap_package_miny_int . north ~ west) ~
rectangle ~
([xshift=-\l__kvmap_package_reducespace_dim,
yshift=\l__kvmap_package_reducespace_dim]
\int_use:N \l__kvmap_package_maxx_int
\int_use:N \l__kvmap_package_maxy_int . south ~ east);
}
\group_end:
}
\cs_new:Npn \kvmap_diagram:nn #1#2
{
\draw ~ (0,0) ~ grid ~
(\int_use:N \l__kvmap_matrix_width_int, -\int_use:N \l__kvmap_matrix_height_int);
\__kvmap_zeichnematrix:n  { #1 }
\__kvmap_zeichnegraycode:
\draw ~ (0,0) ~ -- ~ (-.7,.7);
\int_set:Nn \l_tmpa_int
{ \fp_eval:n { floor(ln(\l__kvmap_matrix_width_int)/ln(2)) }  }
\tl_clear:N \l_tmpa_tl
\int_step_inline:nnnn { 1 } { 1 } { \l_tmpa_int }
{
 \tl_put_right:Nn \l_tmpa_tl { \clist_item:nn { #2 } { ##1 } }
}
\node[anchor = west] ~ at ~ (-.5, .7) ~ { $\tl_use:N \l_tmpa_tl$ };
\tl_clear:N \l_tmpa_tl
\int_step_inline:nnnn { \l_tmpa_int + 1 } { 1 }
{ \l_tmpa_int + \fp_eval:n { floor(ln(\l__kvmap_matrix_height_int)/ln(2)) } }
{
 \tl_put_right:Nn \l_tmpa_tl { \clist_item:nn { #2 } { ##1 } }
}
\node[anchor = east] ~ at ~ (-.4, .2) ~ { $\tl_use:N \l_tmpa_tl$ };
}
\cs_generate_variant:Nn \kvmap_diagram:nn { xn }

\NewDocumentEnvironment { kvmap } { O{} }
{
\group_begin:
\keys_set:nn { kvmap } { #1 }
\int_gzero:N \l__kvmap_matrix_height_int
\int_gzero:N \l__kvmap_matrix_width_int
\begin{tikzpicture}
}
{
\end{tikzpicture}
\group_end:
}

\seq_new:N \l__kvmap_tmp_seq
\NewEnviron { kvmatrix } [ 1 ]
{
\seq_set_split:Nno \l_tmpa_seq { \\ } { \BODY }
\seq_remove_all:Nn \l_tmpa_seq { }
\seq_set_split:Nnx \l_tmpb_seq { & } { \seq_item:Nn \l_tmpa_seq { 1 } }
\seq_remove_all:Nn \l_tmpb_seq { }
\int_gset:Nn \l__kvmap_matrix_width_int  { \seq_count:N \l_tmpb_seq }
\int_gset:Nn \l__kvmap_matrix_height_int { \seq_count:N \l_tmpa_seq }
\seq_clear:N \l__kvmap_tmp_seq
\seq_map_inline:Nn \l_tmpa_seq
{
\seq_clear:N \l_tmpb_seq
\seq_set_split:Nnn \l_tmpb_seq { & } { ##1 }
\seq_concat:NNN \l__kvmap_tmp_seq \l__kvmap_tmp_seq \l_tmpb_seq
}
\tikzifinpicture
{ \bool_set_true:N  \l__kvmap_matrix_isintikz_bool }
{ \bool_set_false:N \l__kvmap_matrix_isintikz_bool }
\bool_if:NF \l__kvmap_matrix_isintikz_bool
{ \begin{tikzpicture} }
\kvmap_diagram:xn
{ \seq_use:Nnnn \l__kvmap_tmp_seq { , } { , } { , } }
{ #1                       }
\bool_if:NF \l__kvmap_matrix_isintikz_bool
{ \end{tikzpicture} }
}
\ExplSyntaxOff

\begin{document}
    \begin{kvmap}
        \begin{kvmatrix}{a,b,c,d,e,f}
        0 & 1 & 1 & 0 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\\
        0 & 0 & 1 & 1 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
        0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
        0 & 1 & 1 & 0 & 0 & 0 & 0 & 0
        \end{kvmatrix}
        \package{3}{3}{2}{3}
        \package[color=blue]{3}{2}{3}{1}
        \package[invert=true,reducespace=2pt,overlapmargins=6pt]{1}{0}{2}{7}
    \end{kvmap}
\end{document}
Related Question