algorithmicx 中使用“noend”选项的垂直循环/块线

algorithmicx 中使用“noend”选项的垂直循环/块线

我正在使用该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[])。

版本 1 代码输出的图像

\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直接传递,这会在重新处理内容之前测量行高。由于它具有不同的界面,并且可能更不可靠(我还不确定),所以我保留了上面的原始答案,而不是替换它。

版本 2 代码输出的图像

\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功能,因此需要多次运行才能稳定(第一次运行或在页面上进行其他更改后第一次运行时,线条不会出现在正确的位置)。同样,在某些情况下,这可能不利(或由于尚未确定的其他原因),因此我也保留了上述两种方法。

版本 3 代码输出的图像

\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}

在此处输入图片描述

相关内容