我正在使用该algorithmicx
包编写算法。但是我使用的noend
选项是:
\usepackage[noend]{algpseudocode}
有没有办法为每个代码块获取垂直线?这个问题已经在这里得到回答:
https://tex.stackexchange.com/a/52778/37056
但是,使用该选项时它不起作用noend
。
编辑:我正在寻找类似这里的算法: http://www.isg.rhul.ac.uk/~kp/dtls.pdf
答案1
这里有一些更自然(自动且表现更好)的垂直线实现,我使用了 Werner 对链接问题的回答作为起点。
版本 1:为每一行和每个缩进级别绘制固定高度规则
如果线高和深度不同,此版本将无法正常工作;请参阅下文尝试更新以解决此问题。
这也适用于这种noend
情况,但打印代码中有一个模糊因素,\addvspace{-3pt}
以防止在未打印的行中出现不必要的间隙。这不是很可靠,但我目前无法做得更好,因为我还没有确定空格(似乎来自\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}
版本 2:处理盒子两次以尝试测量高度
以下版本尝试更好地处理行高,方法是将状态传递给\myState
括号中的而不是\State
直接传递,这会在重新处理内容之前测量行高。由于它具有不同的界面,并且可能更不可靠(我还不确定),所以我保留了上面的原始答案,而不是替换它。
\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}
版本 3:在每个块的开始和结束时使用 tikzmark
@desa 指出,当算法中有显示方程时,版本 2 不起作用。这里有一个新的实现,试图解决这个问题(我看不出如何纠正这种情况的高度猜测算法)。
此代码使用了 tikz 的remember picture
功能,因此需要多次运行才能稳定(第一次运行或在页面上进行其他更改后第一次运行时,线条不会出现在正确的位置)。同样,在某些情况下,这可能不利(或由于尚未确定的其他原因),因此我也保留了上述两种方法。
\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}
答案2
这伪法典(注意结尾的 x)包有一个noEnd
运行良好的选项。
答案3
根据 cyberSingularity 的回答,我尝试制作一个较短的版本
\usepackage{tikz}
\usepackage[noend]{algpseudocode}
\makeatletter
\providetoggle{ALG@Ruler@empty}
\newcounter{ALG@Ruler@Id}
\apptocmd{\ALG@beginblock}{%
\stepcounter{ALG@Ruler@Id}%
\def\ALG@Ruler{ALG@Ruler@BeginPoint-\arabic{ALG@Ruler@Id}}%
\expandafter\edef\csname ALG@Ruler@AtLevel@\theALG@nested\endcsname{\ALG@Ruler}%
\tikz[remember picture, overlay] \coordinate (\ALG@Ruler);%
\toggletrue{ALG@Ruler@empty}%
}{}{}
\pretocmd{\ALG@endblock}{%
\iftoggle{ALG@Ruler@empty}{}{%
\def\ALG@Ruler{\csname ALG@Ruler@AtLevel@\theALG@nested\endcsname}%
\unskip\tikz[remember picture, overlay] \draw[black!25]
([xshift=0.5em, yshift=-0.5ex]\ALG@Ruler) |- ([xshift=1em]\ALG@Ruler|-0,0);%
}%
\togglefalse{ALG@Ruler@empty}%
}{}{}
\makeatother
答案4
这是我为每个块设置一行的解决方案
\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}