# The context

While studying logic, I found myself creating truth tables with different numbers of propositional variables. Sometimes I need to create a truth table for propositions that contains 6 propositional variables which results in a huge table. The one I'm presenting here is a minimal working example.

\documentclass{article}

\begin{document}
\begin{center}
\begin{tabular}{*{3}{|c}|}
\hline
$p$ & $q$ & $p \wedge q$ \\ \hline
0 & 0 & 0 \\ \hline
0 & 1 & 0 \\ \hline
1 & 0 & 0 \\ \hline
1 & 1 & 1 \\ \hline
\end{tabular}
\end{center}
\end{document}


I would find this table easier to see if cells that contain 1s are filled with an specific color and cells that contains 0s are empty (see below).

\documentclass{article}

\usepackage[table]{xcolor}

\begin{document}
\begin{center}

\begin{tabular}{*{3}{|c}|}
\hline
$p$ & $q$ & $p \wedge q$ \\ \hline
&  &  \\ \hline
& \cellcolor{gray!50!white} &  \\ \hline
\cellcolor{gray!50!white} &  &  \\ \hline
\cellcolor{gray!50!white} & \cellcolor{gray!50!white} & \cellcolor{gray!50!white} \\ \hline
\end{tabular}

\end{center}
\end{document}


However, this would clutter up the code of a table which presents such a simple topic. Ideally, the code from \tabular environment from the first table should generate the second table shown.

Of course, I can create a macro for both kinds of cells to accomplish that but

1. that would also clutter up the tabular environment.
2. that would make text processing of columns more difficult since all columns are not of the same size. When saying "text processing" I'm referring to tasks such as sort a given column: When the contents of this columns are 0s and 1s sorting the columns is easier than if the size of each row were different and their contents are characters from the latin alphabet.
3. the number of characters needed to typeset a table does not significantly decrease.

I've never done something like this so I don't know where to search for.

# The question

How can I make a table whose source code shows 1s and 0s such that in the output 0s and 1s are replaced with a given value (in this scenario, 1s and 0s would be replaced with the \cellcolor command and nothing, respectively, in all columns)?

In general, I would like this to occur for some specified columns from a given table. That is, this behavior must not occur in all columns.

You can use collcell. It allows you to wrap the contents of the cells in a macro. The macro used here is a simple \ifnum switch.

\documentclass{article}

\usepackage[table]{xcolor}
\usepackage{collcell}
\newcommand\ColorCell[1]{\ifnum#1=1\relax
\cellcolor{gray!50!white}%
\fi}
\newcolumntype{P}{>{\collectcell\ColorCell}c<{\endcollectcell}}%

\begin{document}
\begin{center}

\begin{tabular}{*{3}{|P}|}
\hline
\multicolumn{1}{|c|}{$p$} & \multicolumn{1}{c|}{$q$} & \multicolumn{1}{c|}{$p \wedge q$} \\ \hline
0&  0& 0 \\ \hline
0 & 1 & 0 \\ \hline
1 & 0 &  0\\ \hline
1 & 1 & 1 \\ \hline
\end{tabular}
\end{center}
\end{document}


You can do better. ;-) You have a computer, so let it do the computations for us. So here's a set of macros that indeed compute the truth tables and typeset them. And collcell is not necessary.

The limit is nine parameters. Sorry, but I didn't implement the conversion from the typeset formula to direct Polish notation necessary for doing the computations.

The first argument is the number of variables, the second argument the formulas or formulas which we want to show the the truth values of. The third argument is the translation into Polish notation, where the variables are denoted by #1, #2 and so on. The * means using gray and white instead of 1 and 0.

The examples should be clear enough.

\documentclass{article}
\usepackage{xparse}
\usepackage[table]{xcolor}

\ExplSyntaxOn
\NewDocumentCommand{\truthtable}{smmm}
{% #2 = number of variables, #3 = formulas, #4 = formulas
\IfBooleanTF { #1 }
{
\cs_set_eq:NN \__morales_truthtable_cell:n \__morales_truthtable_color:e
}
{
\cs_set_eq:NN \__morales_truthtable_cell:n \use:n
}
\morales_truthtable_prepare:nnn { #2 } { #3 } { #4 }
\exp_args:NnV \begin{tabular} \l__morales_truthtable_preamble_tl
\hline
\hline
\l__morales_truthtable_body_tl
\end{tabular}
}

\NewExpandableDocumentCommand{\AND}{mm}
{
\int_min:nn { #1 } { #2 }
}
\NewExpandableDocumentCommand{\OR}{mm}
{
\int_max:nn { #1 } { #2 }
}
\NewExpandableDocumentCommand{\NOT}{m}
{
\int_abs:n { #1 - 1 }
}
\NewExpandableDocumentCommand{\IMP}{mm}
{
\OR{\NOT{#1}}{#2}
}
\NewExpandableDocumentCommand{\IFF}{mm}
{
\AND{\IMP{#1}{#2}}{\IMP{#2}{#1}}
}

\int_new:N \l__morales_truthtable_columns_int
\int_new:N \l__morales_truthtable_formula_int
\seq_new:N \l__morales_truthtable_values_seq
\tl_new:N \l__morales_truthtable_preamble_tl
\tl_new:N \l__morales_truthtable_body_tl
\tl_new:N \l__morales_truthtable_temp_tl

\cs_new_protected:Nn \morales_truthtable_prepare:nnn
{
\int_set:Nn \l__morales_truthtable_columns_int { \clist_count:n { #3 } }
\tl_set:Nx \l__morales_truthtable_preamble_tl
{
@{}c@{}| *{ \l__morales_truthtable_columns_int } { c| }
}
\clist_map_inline:nn { #2 }
{
\tl_put_right:Nn \l__morales_truthtable_header_tl { & \multicolumn{1}{c|}{$##1$} }
}
% now build the truth values
\seq_clear:N \l__morales_truthtable_values_seq
\int_step_inline:nnn { 1 } { \fp_eval:n { 2**(#1) } }
{
\tl_set:Nx \l__morales_truthtable_temp_tl { \int_to_bin:n { ##1 - 1 } }
\seq_put_right:Nx \l__morales_truthtable_values_seq
{
\prg_replicate:nn
{
#1 - \tl_count:N \l__morales_truthtable_temp_tl
}
{ 0 }
\tl_use:N \l__morales_truthtable_temp_tl
}
}
\tl_clear:N \l__morales_truthtable_body_tl
\int_zero:N \l__morales_truthtable_formula_int
\clist_map_inline:nn { #3 }
{
\int_incr:N \l__morales_truthtable_formula_int
\cs_set:cn
{
__morales_truthtable_formula_
\int_eval:n { \l__morales_truthtable_formula_int }
:\prg_replicate:nn { #1 } { n }
}
{ ##1 }
}
\seq_map_inline:Nn \l__morales_truthtable_values_seq
{
\int_step_inline:nn { \l__morales_truthtable_columns_int }
{
\tl_put_right:Nn \l__morales_truthtable_body_tl
{
&
\__morales_truthtable_cell:n
{
\use:c
{
__morales_truthtable_formula_ ####1
:\prg_replicate:nn { #1 } { n }
}
##1
}
}
}
\tl_put_right:Nn \l__morales_truthtable_body_tl { \\ \hline }
}
}

\cs_new:Nn \__morales_truthtable_color:n
{
\int_compare:nT { #1 > 0 } { \cellcolor{gray!40} }
}
\cs_generate_variant:Nn \__morales_truthtable_color:n { e }

\ExplSyntaxOff

\begin{document}

\truthtable{2}{p,q,p\land q,p\lor q}{#1,#2,\AND{#1}{#2},\OR{#1}{#2}}
\truthtable*{2}{p,q,p\land q,p\lor q}{#1,#2,\AND{#1}{#2},\OR{#1}{#2}}

\bigskip

\truthtable{3}{p,q,p\land q,r,(p\land q)\to r}{
#1,#2,\AND{#1}{#2},#3,\IMP{\AND{#1}{#2}}{#3}
}
\truthtable*{3}{p,q,p\land q,r,(p\land q)\to r}{
#1,#2,\AND{#1}{#2},#3,\IMP{\AND{#1}{#2}}{#3}
}

\bigskip

\truthtable{3}{% a tautology
A,B,C,((A\land B)\to C)\leftrightarrow(A\to(B\to C))
}{
#1,#2,#3,\IFF{\IMP{\AND{#1}{#2}}{#3}}{\IMP{#1}{\IMP{#2}{#3}}}
}

\end{document}


The code prepares a suitable table preamble, based on the number of formulas. Then it generates the numbers from 0 to 2^n-1 padding with initial zeros.

For each formula a function with as many parameters as the stated variables is defined, with replacement text the given formula. After this each number is used as input for each macro and the rows are generated one by one.

• While this is way overkill, I must admit it is an elegant way to accomplish the task. I didn't know such things were possible just by using macros, your answer has expanded the limits I knew about LaTeX. I'm grateful that you gave me such a meaningful answer.
– gfe
May 28, 2020 at 6:50