Introduction to ppprog¶
The ppprog
package is a simple package for typesetting pseudocode in LaTeX.
It is oriented towards math-heavy code in particular and it is supposed to be
compact. I wrote it because I had an article to write but none of the packages
I looked through (algorithmx
, algorithm2e
, program
, lstlisting
,
etc.) worked quite the way I would have liked them to and they were cumbersome
on top of everything.
Contents
The basic principles that ppprog
aims to achieve are:
- ease of use – there is no reason to make typesetting algorithms difficult,
- simplicity – make the commands behave in simple and predictable ways without adding scores of options and conditions (basically, if the way it works bothers you, though—you will probably have to redefine some commands),
- compactness – the resulting pseudocode has to be as compact as possible.
Example¶
Here’s a short and basic example showing how the environment looks compiler and how it works:
Getting it¶
The source code is available at github.
Include ppprog.sty
with your LaTeX document or import it into your package
directory. Then include it in your document:
\usepackage{ppprog}
The ppprog environment¶
You can then typeset using the ppprog
environment, for instance:
\begin{ppprog}[\NewProgram]{insert-unique}
\Proc{insert}{e, \mathbb{S}}
\If{e \in \mathbb{S}}
\pp \Return{\mathbb{S}}
\Else
\pp \Return{\mathbb{S} \cup e}
\Fi
\EndProc
\end{ppprog}
The environment has one mandatory and one optional parameter. You have to
provide a name of the algorithm as the mandatory argument. This will be used to
create labels automatically at certain points in the program (see:
Procedures and functions). Here, the name of the program is insert-unique
.
Only use characters here that can be used in labels (so no spaces or
underscores, for instance).
The optional argument is used to decide from what number to start counting
lines in the program. This argument can be set to \NewProgram
(like in the
example above) which will start counting the lines from 1. If you omit the
argument altogether, ppprog
will also start numbering lines from 1.
\begin{ppprog}{some-program}
...
\end{ppprog}
You can also
set it to start on whatever line number the last program ended on using
\ContinueProgram
—this is helpful if you want to split your program into
smaller chunks but want it to still appear as if it were a continuous thing.
\begin{ppprog}[\NewProgram]{some-program-part-1}
...
\end{ppprog}
\begin{ppprog}[\ContinueProgram]{some-program-part-2}
...
\end{ppprog}
You can also specify any starting line number you want using
\ProgramStartsAtLine{n}
where n would be the actual line number. This
can be use for explicit exerpts.
\begin{ppprog}[\ProgramStartsAtLine{15}]{exerpt-of-program-from-line-15}
...
\end{ppprog}
Once inside the ppprog
environment you are basically in LaTeX math mode, so
you can use any mathematical symbols you want. You also don’t have to worry
about indentation or whitespaces in general.
The ppprog
environment can be embedded into a figure environment, a
minipage, etc. or just placed alongside your run-of-the-mill text.
The basics¶
To start a new line in the ppprog
environment you will (with some
exceptions I will describe later) have to use \pp
. This creates a new
numbered line that you can fill up any way you like. The line is in math mode
by default.
\begin{ppprog}{alg}
\pp \text{Hello world!}
\pp x = 2^n
\end{ppprog}
If you need to break the line for any reason it is best to use \ppempty
or
its alias \ppmt
. This will create a new line with a continuation symbol
instead of a line number.
\begin{ppprog}{alg}
\pp x = 2^n + a_x, y = 2^m + a_y, \text{ and }
\ppmt z = 2^k + a_z
\end{ppprog}
You can change the line continuation symbol by reloading the \ppemptylinesymbol
command. For example:
\def\ppemptylinesymbol{\Bat}
If you really need to (although I would not recommend it) you can also use some
raw low-level commands. \\
will break the line, &
will mark the point
where line numbering ends and the contents begin, \ppin
will bring the
indentation of the current line to the level in the preceeding line, and
\ppdectabdepth
and \ppinctabdepth
will respectivelly decrease and
increase the depth of the indentation. Do not use these unless you really must.
\begin{ppprog}{alg}
\pp x_0 = 2^n \\
\ldots & \ppin x_i = 2^{n + i}
\end{ppprog}
Procedures and functions¶
Typically your algorithm will consist of one or more function or procedure.
Commands \Proc
and \Func
are your friends there. They each take two
parameters: the first is the name of the procedure and the second is the list
of the procedure’s or function’s parameters. The commands typeset the relevant
keyword, the name, and the parameter list in parentheses and the symbol
\(\triangleeq\). It also sets the next line to be indented.
Commands \Proc
and \Func
will use the name to create a label at the
line where they are placed. So you can then refer to them by name and the name
of the algorithms they are in with the command \pplineref
. Details on that
are in the Cross-referencing section.
When are finished with your procedure or function insert \EndProc
or
\EndFunc
respectively. This mainly removes the indentation that was present
inside the procedure body it also adds spacing between functions. You can add
additional space by using \ppbreak
after \EndProc
or EndFunc
—this
won’t create a new line but spread the functions out a little bit. If you want
to spread the functions out more (or less) then use \ppbreak
with a
parameter wherein you define the length of the gap.
\begin{ppprog}{procsandfuncs}
\Proc{dostuff}{a, b}
...
\EndProc
\Proc{dootherstuff}{}
...
\EndProc
\ppbreak{1cm}
\Func{countstuff}{x, y, z}
...
\EndFunc
\end{ppprog}
Since I am interested in distributed algorithms ppprog
also has a little
variation on the procedures and functions that allows to prepend some sort of
site or location information to the procedure. This can also be used to prepend
anything else to the procedures and functions however. The variants are
\DistProc
and \DistFunc
and they work just like ordinary \Proc
and
\Func
but have an extra (2nd) argument.
\begin{ppprog}{procsandfuncs}
\DistProc{dodistributedstuff}{@s_1}{a, b}
...
\EndProc
\DistFunc{countdistributedstuff}{@s_2}{x, y, z}
...
\EndFunc
\end{ppprog}
There is no special way to refer to functions or procedures after they were
defined, but I recommend you use the command \ppfunction
for that purpose.
It will change the font of the word to normal text.
\begin{ppprog}{procreferenced}
\Proc{recproc}{x}
\pp \ppkeyword{recproc}(x + 1)
\EndProc
\end{ppprog}
Flow control statements¶
Control flow in the form of loops and if-statements and such like is another
big part of every algorithm. So there are structures for that sort of thing in
ppprog
.
Conditional statements¶
If you want to make an if-block there are four commands to do that for you:
\If
, \Else
, \Elif
, and \Fi
. Use the one-parameter command
\If
to start out the if-block. The parameter is used to describe the
condition of the if-statement. \Elif
is used in the exact same way to have
an if-block with additional conditions. \Else
takes no arguments and
typesets the else keyword, manipulating the indentation. When the if-block is
finished use \Fi
, this will come back to the indentation from before the
block began.
\begin{ppprog}{cases}
\If{x > 5}
...
\Elif{x > 3}
...
\Else
...
\Fi
\end{ppprog}
Note that \If
etc. should not use a \pp
in front of them, However, when
working within the if statement, set lines with \pp
as normal.
\begin{ppprog}{nonsensereally}
\If{x \in S}
\pp S' = S \setminus \{ x \}
\pp S' \cap S
\Else
\pp S \cap \varnothing
\Fi
\end{ppprog}
Loop statements¶
If you want to typeset a loop block there are a number of statements you can do
that with, depending on the type of loop you want: \For
, \Foreach
, or
\While
. Each of these commands sets a keyword (for, for each, or
while) followed by a condition and the keyword do. The condition is given
as the argument of each of the commands. Every loop is finished by the command
\Done
which returns to the indentation from before the loop.
\begin{ppprog}{loops}
\For{\forall x \in X}
...
\Done
\Foreach{x \in X}
...
\Done
\While{x < 10}
...
\Done
\end{ppprog}
Note that loops do not use a \pp
in front of them, but lines within loop
bodies normally do.
\begin{ppprog}{loops}
\Foreach{x \in X}
\pp S \leftarrow S \cup \{ x \}
\Done
\end{ppprog}
Font styles and various keywords¶
Algorithm descriptions often make use of fonts to distinguish certain words
from others. There are some common predefined font styles in ppprog
that
may be handy for that. There is also a (limited) number of useful keywords that
are already defined.
Font styles¶
There are 5 basic font styles offered for basic use-cases. They can be used by invoking the following commands with whatever text the style is supposed to be applied to passed as an argument:
ppkeyword
– bold font that signifies a keyword (like if or return),ppfunction
– ordinary font that is meant to be used for function and procedure names,ppliteral
– monospace font for literals (liketrue
),pptype
– sans-serif font to mark up types,ppvariable
– sans-serif font to distinguish variables.
Note that if you need to type ordinary text at any time you can use the
\text
command from amsmath.
\begin{ppproc}{fonts}
\Proc{something}{\ppvariable{x} \in \pptype{Integer}}
\pp \ppfunction{sleep} 5
\If{x \ppkeyword{mod} 2 = 0}
\pp \ppvariable{y} \leftarrow \ppliteral{"even"}
\Else
\pp \ppvariable{y} \leftarrow \ppliteral{"odd"}
\Fi
\EndProc
\end{ppproc}
Pre-defined literals and keywords¶
Some popular keywords are pre-defined for your convenience:
\Null
– a lowercase null literal,\True
and\False
– boolean literals, both lowercase,\Return
– the return keyword (for returning values from functions etc.), it takes one argument ,\Lock
and\Unlock
– the lock and release operations for locks,\Wait
and\Notify
– the wait and notify operation keyword for monitors.
\begin{ppproc}{atomic}
\Proc{next}{s}
\pp \Lock{s}
\pp s \leftarrow s + 1
\pp r \leftarrow s
\pp \Unlock{s}
\pp \Return{r}
\EndProc
\end{ppproc}
Define your own¶
Since the list of pre-defined commands is so limited you will probably need to define your own font styles and keywords. This is a short primer to get you going in a very rough-and-ready fashion.
When defining font styles you only need to remember that you are in math mode
initially. But if you use commands like \bf
(bold), \rm
(roman),
\tt
(typewriter), \sf
(sans serif), \it
(italics), etc. and
remember to insert the text into a new block, the definition is trivial. For
instance, use the command \def
to define the command \newstyle
. The
command will have one parameter #1
.
\def\newstyle#1{{\bf #1}}
Place the new definition in the document header.
Defining keywords, literal, or anything similar is just as simple. Typically you will use one of the existing styles and just type in whatever word you need.
\def\newkeyword{\ppkeyword{new~keyword}}
\def\newliteral{\ppliteral{new~literal}}
If you want the command to also take a, so that you can define a fixed space or surround something with parentheses, this is also quite simple. Typically you will want your parameter to be used outside the style used for the actual keyword or literal.
\def\newkeyword#1{\ppkeyword{new~keyword}(#1)}
Cross-referencing¶
If you want to refer to code within your text you can assign labels to certain lines and simply use ref
or pplineref
a command provided by pprog.
Referencing lines¶
One way to add a label is to use \pplab
. This creates a label on the current line in the form of line:name-argument
, where name
is the name of the current algorithm (the argument of the ppprog
environment) and argument
is whatever is passed though \pplab
. For example:
\begin{ppproc}{atomic}
\Proc{next}{s}
\pp \Lock{s} \pplab{lock}
\pp s \leftarrow s + 1
\pp r \leftarrow s
\pp \Unlock{s} \pplab{unlock}
\pp \Return{r}
\EndProc
\end{ppproc}
The code above creates two labels: line:atomic-lock
and line:atomic-unlock
(actually three labels, see _ppprog-referencing-procedures). You can refer to them using ref
. But typing all that in can become unwieldy so you can use the command supplied in ppprog—\pplineref
. This command takes two arguments. The first one is the name of the algorithm, and the second one is the last segment of the label. So for the example above:
The lock is obtained at \pplineref{atomic}{lock}
and released at \pplineref{atomic}{unlock}.
This is equivalent to typesetting:
The lock is obtained at line~\ref{line:atomic-lock}
and released at line~\ref{line:atomic-unlock}.
If necessary, you can also set up a raw label with no prefixes by using \pplabel
. This works just like you would expect ordinary \label
to work and can be referenced using ref
in a normal way.
Referencing procedures and functions¶
When procedures and functions are created using \Proc
, \Func
, etc. (see Procedures and functions) a label is created automatically. It has the form line:algname-procname
, where algname
is the name of the current algorithm (the argument of the ppprog
environment) and procname
is the name of the procedure. For example.
\begin{ppproc}{atomic}
\Proc{next}{s}
\pp \Lock{s}
\pp s \leftarrow s + 1
\pp r \leftarrow s
\pp \Unlock{s}
\pp \Return{r}
\EndProc
\end{ppproc}
The code above creates the label line:atomic-next
. You can refer to it using \pplineref
in the following manner:
Atomic incrementation is shown as procedure \emph{next}
(\pplineref{atomic}{next} in the pseudocode).
You can do the same using ref
:
Atomic incrementation is shown as procedure \emph{next}
(line~\ref{line:atomic-next} in the pseudocode).