# Generate LaTeX Truth Table with Python Cheetah

While looking for code which can automatically generate truth table in LaTeX I stumbled on this Python generator. It appears that the code can be used from Cheetah's framework. Can anybody point me to a simple example of use. I started reading documentation for Cheetah ? Additionally can people provide me with other examples of using Cheetah (or some other frame work) to automatically generate LaTeX code.

Edit: I am not sure if Sphinx also could be used as a wrapper for above code.

-
It's not Python Cheetah, but have you considered the sagetex package? Sage uses Python and in Examples of embedding Sage in LaTeX with SageTeX the issue is covered on page 11. – DJP Jan 22 '12 at 18:40
Sege is not ported to OpenBSD which is my OS of choice so no I have not even seen Sege. – Predrag Punosevac Jan 23 '12 at 1:23

I am also interested in generating LaTeX code with Python, so your posting gave me the hint to the framework to use. I just created a simple example:

from Cheetah.Template import Template
definition = """\\documentclass{article}

\\title{$paper.title} \\author{$author.name}

\\begin{document}

\\maketitle

\\end{document}"""

class author:
"""A simple example author class"""
name = "Uwe Ziegenhagen"
def f(self):
return 'Hello World'

class paper:
"""A simple example paper class"""
title = "My First paper"
def f(self):
return 'hello world'

uwe = author()
mypaper = paper()

print Template(definition, searchList=[{'author' : uwe,'paper' : mypaper}])


For archiving purposes, for people less familiar with Cheetah framework, the above is just a regular Python script. The output of the script on the standard output (could be of course piped into a file) is the LaTeX code.

-
What is the advantage of using a template engine rather than writing it straight to a file? I can understand that the template can be useful for web pages, but can't really see the benefit here. – Yiannis Lazarides Jan 22 '12 at 6:50
With this simple example there may not be much difference. But consider a document management system preparing dozens or hundreds of different templates. Using a template engine can help you by separating the template code from the rest. – Uwe Ziegenhagen Jan 22 '12 at 8:03
@Uwe Ziegenhagen spot on! Great answer. It just hit me how to use Cheetah and that code generator. Thank you so much! – Predrag Punosevac Jan 22 '12 at 15:50
@Uwe Ziegenhagen Can Sphinx be used as a wrapper to do the same? I have never played with it before but it might be a time. – Predrag Punosevac Jan 22 '12 at 16:06
No idea, until yesterday I even didn't lnow Cheetah. – Uwe Ziegenhagen Jan 23 '12 at 5:30

Not really an answer to this question as it doesn't involve Cheetah. However if anyone searches for truth table, potentially they would like a truth table macro so I'll post this for that reason. The macro \truthtable{<prims>}{<exprs>} (compile with LuaLaTeX) takes two arguments:

• The first argument is a comma separated list of primitives (variables)
• The second argument is a semi-colon separated list of logical statements involving the operations of:
• Negation, entered as -
• Conjunction, entered as *
• Disjunction, entered as +
• Implication, entered as (stuff)->(stuff)

For example, \truthtable{a,b,c,d}{-a;a*b*d;(a)->(b);a*(b+c);(a*(b+c))->(b)} produces the following:

\documentclass{article}
\usepackage{xparse}

\begingroup
\catcode\%=12\relax
\gdef\patmatch{"(%b())->(%b())","!%1||%2"}
\endgroup

\def\setimpaux#1{%
\directlua{
local s, _ = string.gsub("\luatexluaescapestring{#1}",\patmatch)
tex.sprint(s)
}
}

\ExplSyntaxOn
\int_new:N \l__tt_num_rows_int
\int_new:N \l__tt_num_cols_int
\int_new:N \l__tt_num_vars_int
\clist_new:N \l__tt_vars_clist
\seq_new:N \l__tt_exprs_seq

\NewDocumentCommand {\truthtable}{ m m }
{
\truth_table:nn {#1}{#2}
}

\cs_new_protected:Npn \truth_table:nn #1#2
{
\clist_set:Nn \l__tt_vars_clist {#1}
\seq_set_split:Nnn \l__tt_exprs_seq {;} {#2}
\int_set:Nn \l__tt_num_vars_int {\clist_count:N \l__tt_vars_clist}
\int_set:Nn \l__tt_num_rows_int {\fp_to_int:n {2^{\l__tt_num_vars_int}-1}}
\int_set:Nn \l__tt_num_cols_int {\clist_count:N \l__tt_vars_clist +\seq_count:N \l__tt_exprs_seq}
\__tt_gen_bins:
\seq_map_function:NN \l__tt_exprs_seq \__tt_eval_bools:n
\__tt_build_table:
}

{
\tl_replace_all:Nnn \l_tmpa_tl {*} {\wedge}
\tl_replace_all:Nnn \l_tmpa_tl {+} {\vee}
\tl_replace_all:Nnn \l_tmpa_tl {->} {\to}
\tl_replace_all:Nnn \l_tmpa_tl {-} {\neg}
\tl_use:N \l_tmpa_tl
}

\cs_generate_variant:Nn \seq_use:Nnnn {cnnn}
\cs_new_protected:Npn \__tt_build_table:
{
\begin{array}{*{\int_use:N \l__tt_num_cols_int}{c}}
\int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
{
\seq_use:cnnn {l__tt_row_{##1}_seq}{&}{&}{&}\\
}
\end{array}
}

\cs_new_protected:Npn \__tt_set_imp:n #1
{
\tl_if_in:nnT {#1} {->}
{
\tl_set:Nx \l_tmpb_tl {\setimpaux{#1}}
\exp_args:NV \__tt_set_imp:n \l_tmpb_tl
}
}
\cs_generate_variant:Nn \__tt_set_imp:n {V}

\cs_generate_variant:Nn \tl_replace_all:Nnn {Nnx}
\cs_new_protected:Npn \__tt_eval_bools:n #1
{
\tl_set:Nn \l_tmpa_tl {#1}
\int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
{
\int_set:Nn \l_tmpa_int {1}
\tl_set_eq:NN \l_tmpb_tl \l_tmpa_tl
\__tt_set_imp:V \l_tmpb_tl
\tl_replace_all:Nnn \l_tmpb_tl {*}{&&}
\tl_replace_all:Nnn \l_tmpb_tl {+}{||}
\tl_replace_all:Nnn \l_tmpb_tl {-}{!}
\clist_map_inline:Nn \l__tt_vars_clist
{
\tl_replace_all:Nnx \l_tmpb_tl {####1} {\seq_item:cn {l__tt_row_{##1}_seq} {\l_tmpa_int}}
\int_incr:N \l_tmpa_int
}
\seq_put_right:cx {l__tt_row_{##1}_seq} {\fp_eval:n \l_tmpb_tl}
}
}

\cs_generate_variant:Nn \seq_set_split:Nnn {cnx}
\cs_new_protected:Npn \__tt_gen_bins:
{
\int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
{
\seq_clear_new:c {l__tt_row_{##1}_seq}
\seq_set_split:cnx {l__tt_row_{##1}_seq} {} {\int_to_binary:n {##1}}
\int_while_do:nn {\seq_count:c {l__tt_row_{##1}_seq} < \l__tt_num_vars_int}
{
\seq_put_left:cn {l__tt_row_{##1}_seq} {0}
}
}
}

\ExplSyntaxOff
\begin{document}

$\truthtable{a,b,c,d}{-a;a*b*d;(a)->(b);a*(b+c);(a*(b+c))->(b)}$

\end{document}

-
I was just looking for a truth table so thank you very much for your not really answer ;-) – Ignasi Feb 26 '14 at 8:47
This looks awesome. The best I've found in the past was a script I ran outside TeX to generate a truth table which I then adapted for use in TeX. It would be fantastic to see this expanded into a package on CTAN. (Wish list: option to use T/F rather than 1/o; option to toggle first variable fastest, right variable slowest since there are, for some reason, textbooks which insist on doing this.) This is the first compelling reason I've seen to use something other than pdflatex. (For me - I have seen compelling reasons-if-they-applied-which-they-don't.) – cfr Feb 26 '14 at 20:22
Great macro! Thanks for the code. What part of the code would you need to change for it to display T's and F's instead of 0's and 1's? – EthanAlvaree May 30 '15 at 19:49

Template modules, like Cheetah, are overkill if you want to use Python for this type of work. I would use straight Python as follows:

template = """\\documentclass{{article}}

\\title{{ {title} }}
\\author{{ {author} }}

\\begin{{document}}

\\maketitle

\\end{{document}}"""

info = {"title": "My First Paper",
"author": "A. Author"}

print template.format(**info)

-
Interesting. I didn't know one could do this in Python. I see this goes back to PEP 3101. and the documentation is here. – Faheem Mitha Dec 5 '12 at 19:08

Making truth tables is especially easy using pythontex. Pythontex integrates with sympy and allows you to insert sympy code into your document. A simple truth table can be created for example like this:

\documentclass[letterpaper]{article}
\usepackage[autoprint=false]{pythontex}

\begin{document}
\begin{sympycode}
# declare symbols used
a,b,c = symbols("a b c")
# define expressions:
exprs = (~b, a & ~b, (a & ~b) >> c)
print("&".join(latex(i) for i in (a,b,c) + exprs) + "\\\\\\hline")
# generate and print rows of truth table:
for var_values in cartes([False, True], repeat = 3):
value_dict = dict(zip([a,b,c],var_values))
l = list(var_values) + [i.subs(value_dict) for i in exprs]
print("&".join(str(i) for i in l) + "\\\\")
\end{sympycode}

\begin{tabular}{cccccc}
\printpythontex
\end{tabular}

\end{document}


The result will look like this:

Note that sympy takes care of converting the expressions into LaTeX, using the latex function.

-
I agree with you %100. However PythonTeX was not available when my student wrote parser for propositional logic which outputs truth table in LaTeX code. Unfortunately I never finished cleaning his files and posting complete solution for my original problem. – Predrag Punosevac May 27 '13 at 5:24

## Pweave

I use Pweave for embedding Python code in LaTeX. Here is my minimal working example.

It uses cals to generate the table. The Python code generates and calculates the tube measurements.

It is also Python that takes care of formatting the output in the nl_BE.utf8 locale which replaces commas for decimal points.

The first lines of LaTeX comments indicate how to compile this .Pnw file to produce .tex and .pdf files. When in doubt, consult the following excellent article which got me started.

The Python comment shows how to generate additional locales in Debian GNU/Linux.

%sudo easy_install -U Pweave
%Pweave -f tex filename.Pnw | pdflatex -synctex=1 -interaction=nonstopmode filename.tex
\documentclass{article}

%text symbols
\usepackage{textcomp}

%table
\usepackage{cals}

\begin{document}
\makeatletter
\begin{calstable}
\colwidths{{12mm}{18mm}{18mm}{12mm}{15mm}}
\def\cals@cs@width{0pt} %no vertical column separation lines
\alignC
\thead{\brow \cell{sectie} \cell{$D_{out}$\,(m)} \cell{$D_{in}$\,(m)} \cell{$\ell$\,(m)} \cell{$A$\,(m\texttwosuperior)} \erow}
<%
from math import pi
from locale import setlocale, LC_ALL, format

#sudo dpkg-reconfigure locales
setlocale(LC_ALL, 'nl_BE.utf8')

Atot = 0
for i in range(0,6):
section = i + 1
Dout = 0.060 - i * 0.005
Din = Dout - 0.004
length = 1.8
A = pi * (Dout + Din) * length + pi / 2.0 * (Dout**2 - Din**2)
print('\\brow \\cell{%s} \\cell{%s} \\cell{%s} \\cell{%s} \\cell{%s} \\erow' % (section, format('%.3f', Dout), format('%.3f', Din), format('%.2f', length), format('%.2f', A)))
Atot += A
%>
\tfoot{\brow \alignR \nullcell{ltb} \nullcell{tb} \nullcell{tb} \nullcell{tbr} \spancontent{Totaal:} \alignC \cell{<%=format('%.2f', Atot)%>} \erow}
\end{calstable}
\makeatother
De totale oppervlakte bedraagt <%=format('%.2f', Atot)%>\,m\texttwosuperior.
\end{document}

-

This is the first in series of several Python scripts which I will post over the next couple of days as we add license which completely solves original problem. The code is written by my student Stephen Pardue. The first one is the final wrapper bftruthtable.py (boolean functions truth table). However, I have to post couple objects on which wrapper depends before you can use it.

#!/usr/local/bin/python

# Copyright (c) 2011,  Stephen Pardue <spardue@aug.edu>

# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.

# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.

import argparse

from asciitruthtable import ascii_tables
from latextruthtable import latex_tables

if __name__ == "__main__":

parser = argparse.ArgumentParser(
description="generates truth tables for boolean functions",
epilog="By Stephen Pardue. Fear the pandas")

"function", metavar="fn", type=str, nargs="+",
help="boolean function(s) to generate the table(s) for")

"--ascii", dest="ascii", action="store_const",
const=True,
help="output the table(s) to stdout in ascii format"
)

"--latex", dest="latex", action="store_const",
const=True,
help="output the table(s) to stdout in LaTex format")

args = parser.parse_args()

if args.ascii:
ascii_tables(args.function)

if args.latex:
latex_tables(args)
`
-