19

I am using the algorithmic package (or even algorithm2e is fine). Is it possible to use curly braces to group some lines in the algorithm so as to be able to put an explanation to the right?

Peter Grill
  • 223,288
Legend
  • 559

2 Answers2

24

Here is an example using the infamous \tikzmark macro applied to the example from How to typeset gotos and labels using LaTeX pseudocode environments?.

enter image description here

Usage:

  • Mark the horizontal position with: \tikzmark{right}. Here I used the end of the header procedure Euclid(a,b) as the right` node. Hence the horizontal position of the brace.
  • Mark the top of the brace with: \tikzmark{top}.
  • Mark the bottom of the brace with \tikzmark{bottom}.
  • Call \AddNote{<top node>}{<bottom node>}{<right node>}{<text>}.

These node names top, bottom, and right are arbitrary so if you have multiple places in the same algorithm where you want to place such notes, you can use different node names. Just pass them to the \AddNote macro.

Notes:

  • This does require two runs. First one to determine the locations, and the second to do the drawing.

Further Enhancements:

  • The macro \AddNote could accept additional formatting parameters for the text of the node, and line color selection. Currently this is hard coded to used red and text width=2.5cm.

References:

Here are a few similar applications using \tikzmark:

Code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing,calc}
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture] \node (#1) {};}

\newcommand*{\AddNote}[4]{% \begin{tikzpicture}[overlay, remember picture] \draw [decoration={brace,amplitude=0.5em},decorate,ultra thick,red] ($(#3)!(#1.north)!($(#3)-(0,1)$)$) --
($(#3)!(#2.south)!($(#3)-(0,1)$)$) node [align=center, text width=2.5cm, pos=0.5, anchor=west] {#4}; \end{tikzpicture} }%

\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx \usepackage{algorithm}% http://ctan.org/pkg/algorithm \begin{document} \algnewcommand{\algorithmicgoto}{\textbf{go to}}% \algnewcommand{\Goto}[1]{\algorithmicgoto~\ref{#1}}% \begin{algorithm} \caption{Euclid’s algorithm}\label{euclid} \begin{algorithmic}[1] \Procedure{Euclid}{$a,b$}\tikzmark{right}\Comment{The g.c.d. of a and b} \State $r\gets a\bmod b$ \While{$r\not=0$} \tikzmark{top}\Comment{We have the answer if r is 0} \label{marker} \State $a\gets b$ \State $b\gets r$ \State $r\gets a\bmod b$ \EndWhile \tikzmark{bottom} \State \textbf{return} $b$\Comment{The gcd is b} \State \Goto{marker} \EndProcedure \end{algorithmic} \AddNote{top}{bottom}{right}{We loop here until $r=0$.} \end{algorithm} \end{document}

Peter Grill
  • 223,288
  • 1
    Can someone explain to me, what ($(#3)!(#1.north)!($(#3)-(0,1)$)$) does? – Matthias Dec 10 '12 at 02:40
  • @Matthias: Good question. Have a look at 13.5.5 The Syntax of Projection Modifiers of the tikz-pgf manual. This would make an great follow up question as I had totally forgotten this syntax as I don't use it very often. – Peter Grill Dec 10 '12 at 04:36
  • Note that, at least in algorithm2e, the \AddNote command needs to be inside the algorithm environment (as in the MWE) – Jon Jan 14 '16 at 16:22
  • @Jon: Yes, it needs to stay with the float and get executed on the same page. – Peter Grill Jan 14 '16 at 22:47
5

Here is a more traditional way of performing this bracketed grouping (using Peter's example):

enter image description here

\documentclass{article}
\usepackage{xcolor}% http://ctan.org/pkg/xcolor
\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx
\usepackage{algorithm}% http://ctan.org/pkg/algorithm
\begin{document}
\algnewcommand{\algorithmicgoto}{\textbf{go to}}%
\algnewcommand{\Goto}[1]{\algorithmicgoto~\ref{#1}}%
\begin{algorithm}
  \caption{Euclid’s algorithm}\label{euclid}
  \begin{algorithmic}[1]
    \Procedure{Euclid}{$a,b$}\Comment{The g.c.d. of a and b}
    \State $r\gets a\bmod b$
    \While{$r\not=0$} \Comment{We have the answer if r is 0}\label{marker}
      \State $a\gets b$
      \State $b\gets r$\hspace*{4em}%
        \rlap{\smash{$\left.\begin{array}{@{}c@{}}\\{}\\{}\\{}\\{}\end{array}\color{red}\right\}%
          \color{red}\begin{tabular}{l}We loop here\\until $r=0$.\end{tabular}$}}
      \State $r\gets a\bmod b$
    \EndWhile
    \State \textbf{return} $b$\Comment{The gcd is b}
    \State \Goto{marker}
  \EndProcedure
\end{algorithmic}
\end{algorithm}
\end{document}

The approach is similar to that described in A set of equations, vertically aligned, individually tagged, with subequations, and separate label. The idea is to create a zero-height object (an appropriately-sized, \smashed array) at the correct location (line 5 in this example) and let LaTeX do the rest.

Werner
  • 603,163
  • 1
    This approach makes maintaining the code a hassle; if you add two extra lines to the while-loop, you also need to both move the \rlap command to the new center line, as well as add \\{}\\{} to it. And what if you add just one extra line to the while-loop—where would you even place the \rlap command in that case, as when you have an even number of lines, there is no center line? – StrawberryFieldsForever Aug 20 '20 at 10:40
  • For an even number of lines, put the code just below the middle and move it up adding \raisebox{\dimexpr.5\normalbaselineskip+.5\jot} in the argument of \smash – user6530 Aug 12 '22 at 21:22