13

I am using the algorithmicx package to write an algorithm. However I am using the noend option:

\usepackage[noend]{algpseudocode}

Is there anyway to get vertical lines for each block of code? This question has been answered here:

https://tex.stackexchange.com/a/52778/37056

However, it does not work when using the noend option.

EDIT: I'm looking for something like the algorithms here: http://www.isg.rhul.ac.uk/~kp/dtls.pdf

16

Here are some more natural (automatic and better-behaved) implementations of the vertical lines, where I have used Werner's answer to the linked question as a starting point.

Version 1: Draw a fixed-height rule for each line and each indent level

This version does not work well if the line height and depths differ; see below for attempted update to solve this.

This works for the noend case too, but there is a fudge factor of \addvspace{-3pt} in the printing code to prevent unwanted gaps in lines that don't get printed. This is not very robust but I can't do any better currently as I haven't identified the space (seems to come from \item[]).

Image of output from version 1 code

\documentclass{article}
\usepackage{algorithm}% http://ctan.org/pkg/algorithm
\PassOptionsToPackage{noend}{algpseudocode}% comment out if want end's to show
\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx

\errorcontextlines\maxdimen

% begin vertical rule patch for algorithmicx (http://tex.stackexchange.com/questions/144840/vertical-loop-block-lines-in-algorithmicx-with-noend-option)
\makeatletter
% start with some helper code
% This is the vertical rule that is inserted
\newcommand*{\algrule}[1][\algorithmicindent]{\makebox[#1][l]{\hspace*{.5em}\vrule height .75\baselineskip depth .25\baselineskip}}%

\newcount\ALG@printindent@tempcnta
\def\ALG@printindent{%
    \ifnum \theALG@nested>0% is there anything to print
        \ifx\ALG@text\ALG@x@notext% is this an end group without any text?
            % do nothing
            \addvspace{-3pt}% FUDGE for cases where no text is shown, to make the rules line up
        \else
            \unskip
            % draw a rule for each indent level
            \ALG@printindent@tempcnta=1
            \loop
                \algrule[\csname ALG@ind@\the\ALG@printindent@tempcnta\endcsname]%
                \advance \ALG@printindent@tempcnta 1
            \ifnum \ALG@printindent@tempcnta<\numexpr\theALG@nested+1\relax% can't do <=, so add one to RHS and use < instead
            \repeat
        \fi
    \fi
    }%
\usepackage{etoolbox}
% the following line injects our new indent handling code in place of the default spacing
\patchcmd{\ALG@doentity}{\noindent\hskip\ALG@tlm}{\ALG@printindent}{}{\errmessage{failed to patch}}
\makeatother
% end vertical rule patch for algorithmicx


\begin{document}

\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}
        \State $a\gets b$
        \State $b\gets r$
        \State $r\gets a\bmod b$
      \EndWhile\label{euclidendwhile}
      \State \Return $b$\Comment{The gcd is b}
    \EndProcedure
  \end{algorithmic}
\end{algorithm}
\end{document}

Version 2: process boxes twice in attempt to measure heights

The following is a version that attempts to take better care of the line heights, by passing states to \myState wrapped in braces instead of \State directly, which measures the line heights before reprocessing the content. As it has a different interface, and may be even less robust (I am not yet sure), I am leaving the original answer above rather than replacing it.

Image of output from version 2 code

\documentclass{article}
\usepackage{algorithm}% http://ctan.org/pkg/algorithm
%\PassOptionsToPackage{noend}{algpseudocode}% comment out if want end's to show
\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx

\errorcontextlines\maxdimen

% begin vertical rule patch for algorithmicx (http://tex.stackexchange.com/questions/144840/vertical-loop-block-lines-in-algorithmicx-with-noend-option)
\makeatletter
% start with some helper code
% This is the vertical rule that is inserted
    \newcommand*{\algrule}[1][\algorithmicindent]{\makebox[#1][l]{\hspace*{.5em}\thealgruleextra\vrule height \thealgruleheight depth \thealgruledepth}}%
% its height and depth need to be adjustable
\newcommand*{\thealgruleextra}{}
\newcommand*{\thealgruleheight}{.75\baselineskip}
\newcommand*{\thealgruledepth}{.25\baselineskip}

\newcount\ALG@printindent@tempcnta
\def\ALG@printindent{%
    \ifnum \theALG@nested>0% is there anything to print
        \ifx\ALG@text\ALG@x@notext% is this an end group without any text?
            % do nothing
        \else
            \unskip
            \addvspace{-1pt}% FUDGE to make the rules line up
            % draw a rule for each indent level
            \ALG@printindent@tempcnta=1
            \loop
                \algrule[\csname ALG@ind@\the\ALG@printindent@tempcnta\endcsname]%
                \advance \ALG@printindent@tempcnta 1
            \ifnum \ALG@printindent@tempcnta<\numexpr\theALG@nested+1\relax% can't do <=, so add one to RHS and use < instead
            \repeat
        \fi
    \fi
    }%
\usepackage{etoolbox}
% the following line injects our new indent handling code in place of the default spacing
\patchcmd{\ALG@doentity}{\noindent\hskip\ALG@tlm}{\ALG@printindent}{}{\errmessage{failed to patch}}
\makeatother

% the required height and depth are set by measuring the content to be shown
% this means that the content is processed twice
\newbox\statebox
\newcommand{\myState}[1]{%
    \setbox\statebox=\vbox{#1}%
    \edef\thealgruleheight{\dimexpr \the\ht\statebox+1pt\relax}%
    \edef\thealgruledepth{\dimexpr \the\dp\statebox+1pt\relax}%
    \ifdim\thealgruleheight<.75\baselineskip
        \def\thealgruleheight{\dimexpr .75\baselineskip+1pt\relax}%
    \fi
    \ifdim\thealgruledepth<.25\baselineskip
        \def\thealgruledepth{\dimexpr .25\baselineskip+1pt\relax}%
    \fi
    %\showboxdepth=100
    %\showboxbreadth=100
    %\showbox\statebox
    \State #1%
    %\State \usebox\statebox
    %\State \unvbox\statebox
    %reset in case the next command is not wrapped in \myState
    \def\thealgruleheight{\dimexpr .75\baselineskip+1pt\relax}%
    \def\thealgruledepth{\dimexpr .25\baselineskip+1pt\relax}%
}
% end vertical rule patch for algorithmicx

\begin{document}

\begin{algorithm}
  \caption{Euclid’s algorithm}\label{euclid}
  \begin{algorithmic}[1]
    \Procedure{Euclid}{$a,b$}\Comment{The g.c.d.\ of a and b}
      \myState{$r\gets a\bmod b$}
      \While{$r\not=0$}\Comment{We have the answer if r is 0}
        \myState{$a\gets\displaystyle\sum_{i=1}^n x_i$}\Comment{Nonsense to show that tall lines might work}
        \myState{$a\gets b$}
        \myState{$b\gets r$}
        \myState{$r\gets a\bmod b$}
      \EndWhile\label{euclidendwhile}
      \myState{\Return $b$\Comment{The gcd is b}}
    \EndProcedure
  \end{algorithmic}
\end{algorithm}
\end{document}

Version 3: use tikzmark at start and end of each block

@desa pointed out that version 2 doesn't work when there are displayed equations in the algorithm. Here is a new implementation that attempts to fix that (I couldn't see how to correct the height guessing algorithm for this case).

This code uses tikz's remember picture feature so requires multiple runs to stabilise (the lines will not appear in the correct place in the first run, or in the first run following other changes on the page). Again, this may be disadvantageous in some cases (or for other reasons not yet identified), so I am also leaving the previous two approaches above.

Image of output from version 3 code

\documentclass{article}
\usepackage{algorithm}% http://ctan.org/pkg/algorithm
%\PassOptionsToPackage{noend}{algpseudocode}% comment/uncomment depending on whether want ends to show
\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx

\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\usetikzlibrary{calc}

\errorcontextlines\maxdimen

% begin vertical rule patch for algorithmicx (http://tex.stackexchange.com/questions/144840/vertical-loop-block-lines-in-algorithmicx-with-noend-option)
% note that some of the packages above are also needed
\newcommand{\ALGtikzmarkcolor}{black}% customise this, if you want
\newcommand{\ALGtikzmarkextraindent}{4pt}% customise this, if you want
\newcommand{\ALGtikzmarkverticaloffsetstart}{-.5ex}% customise this, if you want
\newcommand{\ALGtikzmarkverticaloffsetend}{-.5ex}% customise this, if you want
\makeatletter
\newcounter{ALG@tikzmark@tempcnta}

\newcommand\ALG@tikzmark@start{%
    \global\let\ALG@tikzmark@last\ALG@tikzmark@starttext%
    \expandafter\edef\csname ALG@tikzmark@\theALG@nested\endcsname{\theALG@tikzmark@tempcnta}%
    \tikzmark{ALG@tikzmark@start@\csname ALG@tikzmark@\theALG@nested\endcsname}%
    \addtocounter{ALG@tikzmark@tempcnta}{1}%
}

\def\ALG@tikzmark@starttext{start}
\newcommand\ALG@tikzmark@end{%
    \ifx\ALG@tikzmark@last\ALG@tikzmark@starttext
        % ignore this, the block was opened then closed directly without any other blocks in between (so just a \State basically)
        % don't draw a vertical line here
    \else
        \tikzmark{ALG@tikzmark@end@\csname ALG@tikzmark@\theALG@nested\endcsname}%
        \tikz[overlay,remember picture] \draw[\ALGtikzmarkcolor] let \p{S}=($(pic cs:ALG@tikzmark@start@\csname ALG@tikzmark@\theALG@nested\endcsname)+(\ALGtikzmarkextraindent,\ALGtikzmarkverticaloffsetstart)$), \p{E}=($(pic cs:ALG@tikzmark@end@\csname ALG@tikzmark@\theALG@nested\endcsname)+(\ALGtikzmarkextraindent,\ALGtikzmarkverticaloffsetend)$) in (\x{S},\y{S})--(\x{S},\y{E});%
    \fi
    \gdef\ALG@tikzmark@last{end}%
}



% the following line injects our new tikzmarking code
\apptocmd{\ALG@beginblock}{\ALG@tikzmark@start}{}{\errmessage{failed to patch}}
\pretocmd{\ALG@endblock}{\ALG@tikzmark@end}{}{\errmessage{failed to patch}}
\makeatother
% end vertical rule patch for algorithmicx


\begin{document}

\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}%
        \State $a\gets\displaystyle\sum_{i=1}^n x_i$\Comment{Nonsense to show that tall lines might work}%
        \State $a\gets b$%
        \State $b\gets r$%
        \State \begin{equation} y = mx + c \end{equation}%
        \State $r\gets a\bmod b$%
      \EndWhile\label{euclidendwhile}%
      \State \Return $b$\Comment{The gcd is b}%
    \EndProcedure%
  \end{algorithmic}
\end{algorithm}

\end{document}
  • I've copied your preamble to my .tex, but can't compile it. I'm getting this error: ! Use of \ALG doesn't match its definition. – sazr Feb 21 '14 at 15:52
  • @sazr: Sounds like it might be a \makeatletter problem? Can you confirm that this MWE works for you? Would probably need a bit more to go on otherwise. – cyberSingularity Feb 22 '14 at 19:07
  • jeez that was it... I can't even copy paste right x) thanks for putting up with my incompetence. it kinda works (compiled with no errors) but I don't think its working very well, I took a screenshot to show you: screenshot – sazr Feb 23 '14 at 1:33
  • 1
    @desa: Thanks for alerting me to this. Sorry I couldn't work out why guessing the size of the equations didn't work in the previous code, but I have added an alternative approach to drawing the lines that hopefully solves the problem you identified. – cyberSingularity Mar 28 '17 at 12:00
  • 1
    @desa: Hmm, okay, I might need a more detailed MWE to resolve this. But first, can you check that all your latex packages are up to date? – cyberSingularity Mar 28 '17 at 21:13
-2

this is my solution for a one lined for each block

 \begin{algorithm}

\algnewcommand\algorithmiceach{\textbf{each}}
\algnewcommand\Each{\algorithmiceach}

\algnewcommand{\LineForEach}[2]{
    \State\algorithmicfor\ \Each\ {#1}\ \algorithmicdo \ {#2}\ }


\begin{algorithmic}[1]
\Procedure{my procedure}{}
\LineForEach{( condition)}{ what to do}%
\EndProcedure
\end{algorithmic}
\end{algorithm}

enter image description here

  • 3
    Welcome! Did you see that the op asked for vertical lines, not horizontal lines? – Mensch Apr 21 '16 at 11:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.