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.

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 (like true),
  • 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).