How can I get rid of the do in a for loop and the then in an if statement when typesetting algorithms using the algorithm
and algorithmicx
packages?
[Tex/LaTex] “For” loop without “do”; “if” statement without “then”
algorithmicalgorithmicxalgorithms
Related Solutions
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[]
).
\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.
\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.
\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}
The only reason for not having the "end for" is that you are using the noend
option when loading algpseudocode
.
In fact, the following MWE
\documentclass{article}
\usepackage{algorithm}
\usepackage[noend]{algpseudocode}
\begin{document}
\begin{algorithm}
\caption{My algorithm}\label{alg:myalgo}
\begin{algorithmic}[1]
\Procedure{Algo1}{}
\For{\texttt{<condition>}}
\State \texttt{<my stuff>}
\EndFor
\EndProcedure
\end{algorithmic}
\end{algorithm}
\end{document}
gives
while, if you replace
\usepackage[noend]{algpseudocode}
with
\usepackage{algpseudocode}
you obtain
Best Answer
You can redefine
\algorithmicthen
and\algorithmicdo
:Adding the previous lines in the preamble (respectively, before a particular algorithmic environment enclosing the construct inside a group) will remove the "then" and "do" from all the
algorithmic
environments (for the particular environment, respectively). If the change has to be applied only to some structures of a particular algorithm while others still will have the "then" and "do", then you can define commands to "switch on/off" the expressions: