algorithmicx 中的垂直线问题

algorithmicx 中的垂直线问题

我使用algorithmicx垂直线。代码运行良好:

\documentclass{article}

\usepackage{algorithm} 
\usepackage{algpseudocode}

% Vertical line
\makeatletter
\def\therule{\makebox[\algorithmicindent][l]{\hspace*{.5em}\vrule height .75\baselineskip depth .25\baselineskip}}%

\newtoks\therules% Contains rules
\therules={}% Start with empty token list
\def\appendto#1#2{\expandafter#1\expandafter{\the#1#2}}% Append to token list
\def\gobblefirst#1{% Remove (first) from token list
  #1\expandafter\expandafter\expandafter{\expandafter\@gobble\the#1}}%
\def\LState{\State\unskip\the\therules}% New line-state
\def\pushindent{\appendto\therules\therule}%
\def\popindent{\gobblefirst\therules}%
\def\printindent{\unskip\the\therules}%
\def\printandpush{\printindent\pushindent}%
\def\popandprint{\popindent\printindent}%

%      ***      DECLARED LOOPS      ***
% (from algpseudocode.sty)
\algdef{SE}[WHILE]{While}{EndWhile}[1]
  {\printandpush\algorithmicwhile\ #1\ \algorithmicdo}
  {\popandprint\algorithmicend\ \algorithmicwhile}%
\algdef{SE}[FOR]{For}{EndFor}[1]
  {\printandpush\algorithmicfor\ #1\ \algorithmicdo}
  {\popandprint\algorithmicend\ \algorithmicfor}%
\algdef{S}[FOR]{ForAll}[1]
  {\printindent\algorithmicforall\ #1\ \algorithmicdo}%
\algdef{SE}[LOOP]{Loop}{EndLoop}
  {\printandpush\algorithmicloop}
  {\popandprint\algorithmicend\ \algorithmicloop}%
\algdef{SE}[REPEAT]{Repeat}{Until}
  {\printandpush\algorithmicrepeat}[1]
  {\popandprint\algorithmicuntil\ #1}%
\algdef{SE}[IF]{If}{EndIf}[1]
  {\printandpush\algorithmicif\ #1\ \algorithmicthen}
  {\popandprint\algorithmicend\ \algorithmicif}%
\algdef{C}[IF]{IF}{ElsIf}[1]
  {\popandprint\pushindent\algorithmicelse\ \algorithmicif\ #1\ \algorithmicthen}%
\algdef{Ce}[ELSE]{IF}{Else}{EndIf}
  {\popandprint\pushindent\algorithmicelse}%
\algdef{SE}[PROCEDURE]{Procedure}{EndProcedure}[2]
   {\printandpush\algorithmicprocedure\ \textproc{#1}\ifthenelse{\equal{#2}{}}{}{(#2)}}%
   {\popandprint\algorithmicend\ \algorithmicprocedure}%
\algdef{SE}[FUNCTION]{Function}{EndFunction}[2]
   {\printandpush\algorithmicfunction\ \textproc{#1}\ifthenelse{\equal{#2}{}}{}{(#2)}}%
   {\popandprint\algorithmicend\ \algorithmicfunction}%

\makeatother

\begin{document}

\begin{algorithm}
  \caption{Examples}\label{alg:Examples}
  \begin{algorithmic}[1]
  \LState $X=45$
  \For{\textbf{от} $i=0$ \textbf{до} 5}
  \LState $X=X-2$
  \LState \Call {Find}{$X$}
  \While{$Y_2<5$}

  \If{$quality\ge 9$}
  \LState $a\gets perfect$
  \ElsIf{$quality\ge 7$}
  \LState $a\gets good$
  \ElsIf{$quality\ge 5$}
  \LState $a\gets medium$
  \ElsIf{$quality\ge 3$}
  \LState $a\gets bad$
  \Else
  \LState $a\gets unusable$
  \EndIf

  \EndWhile
  \LState \Return $X$
  \EndFor
  \end{algorithmic}
\end{algorithm}


\end{document}

一只忙碌的猫 http://harrix.org/2013-04-24_151430.png

  1. 我想将命令翻译成我的语言。对于常见命令,翻译不会破坏垂直线。

     \algrenewcommand\algorithmicwhile{\textbf{BlaBlaWhile}}
     \algrenewcommand\algorithmicif{\textbf{BlaBlaIf}}
    

但是当我翻译团队结构结束时,垂直线断了。

     \algrenewtext{EndWhile}{\textbf{BlaBlaEndWhile}}
     \algrenewtext{ElsIf}{\textbf{BlaBlaElsIf }}

代码:

    \documentclass{article}

    \usepackage{algorithm} 
    \usepackage{algpseudocode}

    % Vertical line
    \makeatletter
    \def\therule{\makebox[\algorithmicindent][l]{\hspace*{.5em}\vrule height .75\baselineskip depth .25\baselineskip}}%

    \newtoks\therules% Contains rules
    \therules={}% Start with empty token list
    \def\appendto#1#2{\expandafter#1\expandafter{\the#1#2}}% Append to token list
    \def\gobblefirst#1{% Remove (first) from token list
      #1\expandafter\expandafter\expandafter{\expandafter\@gobble\the#1}}%
    \def\LState{\State\unskip\the\therules}% New line-state
    \def\pushindent{\appendto\therules\therule}%
    \def\popindent{\gobblefirst\therules}%
    \def\printindent{\unskip\the\therules}%
    \def\printandpush{\printindent\pushindent}%
    \def\popandprint{\popindent\printindent}%

    %      ***      DECLARED LOOPS      ***
    % (from algpseudocode.sty)
    \algdef{SE}[WHILE]{While}{EndWhile}[1]
      {\printandpush\algorithmicwhile\ #1\ \algorithmicdo}
      {\popandprint\algorithmicend\ \algorithmicwhile}%
    \algdef{SE}[FOR]{For}{EndFor}[1]
      {\printandpush\algorithmicfor\ #1\ \algorithmicdo}
      {\popandprint\algorithmicend\ \algorithmicfor}%
    \algdef{S}[FOR]{ForAll}[1]
      {\printindent\algorithmicforall\ #1\ \algorithmicdo}%
    \algdef{SE}[LOOP]{Loop}{EndLoop}
      {\printandpush\algorithmicloop}
      {\popandprint\algorithmicend\ \algorithmicloop}%
    \algdef{SE}[REPEAT]{Repeat}{Until}
      {\printandpush\algorithmicrepeat}[1]
      {\popandprint\algorithmicuntil\ #1}%
    \algdef{SE}[IF]{If}{EndIf}[1]
      {\printandpush\algorithmicif\ #1\ \algorithmicthen}
      {\popandprint\algorithmicend\ \algorithmicif}%
    \algdef{C}[IF]{IF}{ElsIf}[1]
      {\popandprint\pushindent\algorithmicelse\ \algorithmicif\ #1\ \algorithmicthen}%
    \algdef{Ce}[ELSE]{IF}{Else}{EndIf}
      {\popandprint\pushindent\algorithmicelse}%
    \algdef{SE}[PROCEDURE]{Procedure}{EndProcedure}[2]
       {\printandpush\algorithmicprocedure\ \textproc{#1}\ifthenelse{\equal{#2}{}}{}{(#2)}}%
       {\popandprint\algorithmicend\ \algorithmicprocedure}%
    \algdef{SE}[FUNCTION]{Function}{EndFunction}[2]
       {\printandpush\algorithmicfunction\ \textproc{#1}\ifthenelse{\equal{#2}{}}{}{(#2)}}%
       {\popandprint\algorithmicend\ \algorithmicfunction}%

    \makeatother

    \begin{document}

    \algrenewcommand\algorithmicwhile{\textbf{BlaBlaWhile}}
    \algrenewcommand\algorithmicif{\textbf{BlaBlaIf}}

    \algrenewtext{EndWhile}{\textbf{BlaBlaEndWhile}}
    \algrenewtext{ElsIf}{\textbf{BlaBlaElsIf }}

    \begin{algorithm}
      \caption{Examples}\label{alg:Examples}
      \begin{algorithmic}[1]
      \LState $X=45$
      \For{\textbf{от} $i=0$ \textbf{до} 5}
      \LState $X=X-2$
      \LState \Call {Find}{$X$}
      \While{$Y_2<5$}

      \If{$quality\ge 9$}
      \LState $a\gets perfect$
      \ElsIf{$quality\ge 7$}
      \LState $a\gets good$
      \ElsIf{$quality\ge 5$}
      \LState $a\gets medium$
      \ElsIf{$quality\ge 3$}
      \LState $a\gets bad$
      \Else
      \LState $a\gets unusable$
      \EndIf

      \EndWhile
      \LState \Return $X$
      \EndFor
      \end{algorithmic}
    \end{algorithm}


    \end{document}

一只忙碌的猫 http://harrix.org/2013-04-24_153318.png

如何修复?

  1. 当我使用高度大于高度线的大公式时,垂直线会中断。

    \documentclass{article}
    
    \usepackage{algorithm} 
    \usepackage{algpseudocode}
    
    \usepackage{amsthm,amsfonts,amsmath,amssymb,amscd} 
    
    % Vertical line
    \makeatletter
    \def\therule{\makebox[\algorithmicindent][l]{\hspace*{.5em}\vrule height .75\baselineskip depth .25\baselineskip}}%
    
    \newtoks\therules% Contains rules
    \therules={}% Start with empty token list
    \def\appendto#1#2{\expandafter#1\expandafter{\the#1#2}}% Append to token list
    \def\gobblefirst#1{% Remove (first) from token list
      #1\expandafter\expandafter\expandafter{\expandafter\@gobble\the#1}}%
    \def\LState{\State\unskip\the\therules}% New line-state
    \def\pushindent{\appendto\therules\therule}%
    \def\popindent{\gobblefirst\therules}%
    \def\printindent{\unskip\the\therules}%
    \def\printandpush{\printindent\pushindent}%
    \def\popandprint{\popindent\printindent}%
    
    %      ***      DECLARED LOOPS      ***
    % (from algpseudocode.sty)
    \algdef{SE}[WHILE]{While}{EndWhile}[1]
      {\printandpush\algorithmicwhile\ #1\ \algorithmicdo}
      {\popandprint\algorithmicend\ \algorithmicwhile}%
    \algdef{SE}[FOR]{For}{EndFor}[1]
      {\printandpush\algorithmicfor\ #1\ \algorithmicdo}
      {\popandprint\algorithmicend\ \algorithmicfor}%
    \algdef{S}[FOR]{ForAll}[1]
      {\printindent\algorithmicforall\ #1\ \algorithmicdo}%
    \algdef{SE}[LOOP]{Loop}{EndLoop}
      {\printandpush\algorithmicloop}
      {\popandprint\algorithmicend\ \algorithmicloop}%
    \algdef{SE}[REPEAT]{Repeat}{Until}
      {\printandpush\algorithmicrepeat}[1]
      {\popandprint\algorithmicuntil\ #1}%
    \algdef{SE}[IF]{If}{EndIf}[1]
      {\printandpush\algorithmicif\ #1\ \algorithmicthen}
      {\popandprint\algorithmicend\ \algorithmicif}%
    \algdef{C}[IF]{IF}{ElsIf}[1]
      {\popandprint\pushindent\algorithmicelse\ \algorithmicif\ #1\ \algorithmicthen}%
    \algdef{Ce}[ELSE]{IF}{Else}{EndIf}
      {\popandprint\pushindent\algorithmicelse}%
    \algdef{SE}[PROCEDURE]{Procedure}{EndProcedure}[2]
       {\printandpush\algorithmicprocedure\ \textproc{#1}\ifthenelse{\equal{#2}{}}{}{(#2)}}%
       {\popandprint\algorithmicend\ \algorithmicprocedure}%
    \algdef{SE}[FUNCTION]{Function}{EndFunction}[2]
       {\printandpush\algorithmicfunction\ \textproc{#1}\ifthenelse{\equal{#2}{}}{}{(#2)}}%
       {\popandprint\algorithmicend\ \algorithmicfunction}%
    \makeatother
    
    \begin{document}
    
    \begin{algorithm}
      \caption{Examples}\label{alg:Examples}
      \begin{algorithmic}[1]
      \LState $X=45$
      \For{\textbf{от} $i=0$ \textbf{до} 5}
      \LState $X=X-2$
      \LState \Call {Find}{$X$}
      \While{$Y_2<5$}
    
      \If{$quality\ge 9$}
      \LState $a\gets perfect$
      \ElsIf{$quality\ge 7$}
      \LState Try
      \begin{flalign*}
        &\left( \begin{array}{c} X_{B} \\ f_B\left( \bar{x}_{B}\right)  \\ {g_i}_B\left( \bar{x}_B\right) \\ {h_j}_B\left( \bar{x}_B\right) \\ ParametersOfBinaryGA\end{array}\right)\\
        &=ConvertingIntoBinaryGA\left( \begin{array}{c} X \\ f\left( \bar{x}\right) \\ g_i\left( \bar{x}\right) \\ h_j\left( \bar{x}\right) \\ ParametersOfBinaryGA \\ ParametersOfConvertingIntoBinaryGA \end{array}\right)
        \end{flalign*}
      \ElsIf{$quality\ge 5$}
      \LState $a\gets medium$
      \ElsIf{$quality\ge 3$}
      \LState $a\gets bad$
      \Else
      \LState $\left( \begin{array}{c} X_{B} \\ f_B\left( \bar{x}_{B}\right)  \\ {g_i}_B\left( \bar{x}_B\right) \\ {h_j}_B\left( \bar{x}_B\right) \\ ParametersOfBinaryGA\end{array}\right)$
      \EndIf
    
      \EndWhile
      \LState \Return $X$
      \EndFor
      \end{algorithmic}
    \end{algorithm}
    
    
    \end{document}
    

一只忙碌的猫 http://harrix.org/2013-04-24_155014.png

如何修复?

答案1

缩进问题可以通过对解决方案的简单扩展来解决algorithmicx 中的强制缩进

垂直线带来了更难的问题。我们无法引入任何解决方案来创建一个垂直线应该开始的组,并在垂直线应该结束的组结束,因为这会破坏algorithmicx。因此,唯一能想到的解决方案是tikzzpos。我改编了来自的代码在页边空白处用线标记条件版本对于algorithmicx,以应对嵌套块并与边缘保持正确的距离。当然,这需要几次运行才能稳定,因为它本质上使用了tikzmark。然而,我的解决方案目前效果不佳使用矩阵(或其他更高的线条),我不知道如何修复它(注意:基于对确定您所在的行的高度,这既不容易,也是不可能的,至少没有 LuaTeX)。当算法跨越多列(有些线条位置错误或者根本没有画出来)。

最后,我没有使用你的代码示例,而是以如何在必须换行时自动保持缩进级别相反,为了简单起见。

\documentclass[twocolumn]{article}

\usepackage[paperheight=10cm]{geometry}% to help test the twocolumn behaviour

\usepackage{algpseudocode}

\errorcontextlines\maxdimen



% begin vertical rule patch for algorithmicx
% borrowing from https://tex.stackexchange.com/questions/41956/marking-conditional-versions-with-line-in-margin

\RequirePackage{tikz}
\RequirePackage{zref-abspage}
\RequirePackage{zref-user}
\RequirePackage{tikz}
\RequirePackage{atbegshi}
\usetikzlibrary{calc}
\RequirePackage{tikzpagenodes}
\RequirePackage{etoolbox}

\makeatletter
\newcommand*\ALG@lastblockb{b}
\newcommand*\ALG@lastblocke{e}
\apptocmd{\ALG@beginblock}{%
    %\typeout{beginning block, nesting level \theALG@nested, line \arabic{ALG@line}}%
    \ifx\ALG@lastblock\ALG@lastblockb
        \ifnum\theALG@nested>1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi{\ALG@tikzborder}{}%
    \fi
    \let\ALG@lastblock\ALG@lastblockb%
}{}{\errmessage{failed to patch}}

\pretocmd{\ALG@endblock}{%
    %\typeout{ending block, nesting level \theALG@nested, line \arabic{ALG@line}}%
    \ifx\ALG@lastblock\ALG@lastblocke
        \addtocounter{ALG@nested}{1}%
        \addtolength\ALG@tlm{\csname ALG@ind@\theALG@nested\endcsname}%
        \ifnum\theALG@nested>1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi{\endALG@tikzborder}{}%
        \addtolength\ALG@tlm{-\csname ALG@ind@\theALG@nested\endcsname}%
        \addtocounter{ALG@nested}{-1}%
    \fi
    \let\ALG@lastblock\ALG@lastblocke%
}{}{\errmessage{failed to patch}}


\tikzset{ALG@tikzborder/.style={line width=0.5pt,black}}

\newcommand*\currenttextarea{current page text area}

\newcommand*{\updatecurrenttextarea}{%
    \if@twocolumn
        \if@firstcolumn
            \renewcommand*{\currenttextarea}{current page column 1 area}%
        \else
            \renewcommand*{\currenttextarea}{current page column 2 area}%
        \fi
    \else
        \renewcommand*\currenttextarea{current page text area}%
    \fi
}


\newcounter{ALG@tikzborder}
\newcounter{ALG@totaltikzborder}
\newenvironment{ALG@tikzborder}[1][]{%
    % Allow user to overwrite the used style locally
    \ifx&#1&\else
        \tikzset{ALG@tikzborder/.style={#1}}%
    \fi
    \stepcounter{ALG@totaltikzborder}%
    \expandafter\edef\csname ALG@ind@border@\theALG@nested\endcsname{\theALG@totaltikzborder}%
    \setcounter{ALG@tikzborder}{\csname ALG@ind@border@\theALG@nested\endcsname}%
    %\typeout{begin ALG border nesting level=\theALG@nested, tikzborder=\theALG@tikzborder, tlm=\the\ALG@tlm}%
    \tikz[overlay,remember picture] \coordinate (ALG@tikzborder-\theALG@tikzborder);% node {\theALG@tikzborder};% Modified \tikzmark macro
    \zlabel{ALG@tikzborder-begin-\theALG@tikzborder}%
    % Test if end-label is at the same page and draw first half of border if not, from start place to the end of the page
    \ifnum\zref@extract{ALG@tikzborder-begin-\theALG@tikzborder}{abspage}=\zref@extract{ALG@tikzborder-end-\theALG@tikzborder}{abspage} \else
        \updatecurrenttextarea
        \ALG@drawvline{[shift={(0pt,.5\ht\strutbox)}]ALG@tikzborder-\theALG@tikzborder}{\currenttextarea.south east}{\ALG@thistlm}%
        % If it spreads over more than two pages:
        \newcounter{ALG@tikzborderpages\theALG@tikzborder}%
        \setcounter{ALG@tikzborderpages\theALG@tikzborder}{\numexpr-\zref@extract{ALG@tikzborder-begin-\theALG@tikzborder}{abspage}+\zref@extract{ALG@tikzborder-end-\theALG@tikzborder}{abspage}}%
        \ifnum\value{ALG@tikzborderpages\theALG@tikzborder}>1
            \edef\nextcmd{\noexpand\AtBeginShipoutNext{\noexpand\ALG@tikzborderpage{\theALG@tikzborder}{\the\ALG@thistlm}}}%some pages need a border on the whole page
            \nextcmd
        \fi
    \fi
}{%
    \setcounter{ALG@tikzborder}{\csname ALG@ind@border@\theALG@nested\endcsname}%
    %\typeout{end ALG border nesting level=\theALG@nested, tikzborder=\theALG@tikzborder, tlm=\the\ALG@tlm}%
    \tikz[overlay,remember picture] \coordinate (ALG@tikzborder-end-\theALG@tikzborder);% node {\theALG@tikzborder};% Modified \tikzmark macro
    \zlabel{ALG@tikzborder-end-\theALG@tikzborder}%
    % Test if begin-label is at the same page and draw whole border if so, from start place to end place
    \updatecurrenttextarea
    \ifnum\zref@extract{ALG@tikzborder-begin-\theALG@tikzborder}{abspage}=\zref@extract{ALG@tikzborder-end-\theALG@tikzborder}{abspage}\relax
        \ALG@drawvline{[shift={(0pt,.5\ht\strutbox)}]ALG@tikzborder-\theALG@tikzborder}{ALG@tikzborder-end-\theALG@tikzborder}{\ALG@thistlm}%
    % Otherwise draw second half of border, from the top of the page to the end place
    \else
        %\settextarea
        \ALG@drawvline{\currenttextarea.north west}{ALG@tikzborder-end-\theALG@tikzborder}{\ALG@thistlm}%
    \fi
}

\newcommand*{\ALG@drawvline}[3]{%#1=from, #2=to, #3=value of \ALG@tlm/\ALG@thisthm
    \begin{tikzpicture}[overlay,remember picture]
        \draw [ALG@tikzborder]
            let \p0 = (\currenttextarea.north west), \p1=(#1), \p2 = (#2)
             in
            (#3+\fboxsep+.5\pgflinewidth+\x0,\y1+\fboxsep+.5\pgflinewidth)%-\fboxsep-.5\pgflinewidth
             --
            (#3+\fboxsep+.5\pgflinewidth+\x0,\y2-\fboxsep-.5\pgflinewidth)
            %node[midway,anchor=east] {\ALG@tikzbordertext}
        ;
    \end{tikzpicture}%
}

\newcommand{\ALG@tikzborderpage}[2]{%the whole page gets a border, #1=value of \theALG@tikzborder, #2=value of \ALG@tlm/\ALG@thistlm
    \updatecurrenttextarea
    \setcounter{ALG@tikzborder}{#1}%
    \ALG@drawvline{\currenttextarea.north west}{\currenttextarea.south east}{#2}%
    \addtocounter{ALG@tikzborderpages\theALG@tikzborder}{-1}%
    \ifnum\value{ALG@tikzborderpages\theALG@tikzborder}>1
        \AtBeginShipoutNext{\ALG@tikzborderpage{#1}{#2}}%
    \fi
    \vspace{-0.5\baselineskip}% Compensate for the generated extra space at begin of the page. No idea why exactly this happens.
}

\def\ALG@tikzbordertext{\the\ALG@tlm}
\makeatother
% end vertical rule patch for algorithmicx



% continuation indent patch, slightly extended from https://tex.stackexchange.com/questions/78776/forced-indentation-in-algorithmicx to support multiple paragraphs in one block
\RequirePackage{etoolbox}
\makeatletter
\newlength{\ALG@continueindent}
\setlength{\ALG@continueindent}{2em}
\newcommand*{\ALG@customparshape}{\parshape 2 \leftmargin \linewidth \dimexpr\ALG@tlm+\ALG@continueindent\relax \dimexpr\linewidth+\leftmargin-\ALG@tlm-\ALG@continueindent\relax}
\newcommand*{\ALG@customparshapex}{\parshape 1 \dimexpr\ALG@tlm+\ALG@continueindent\relax \dimexpr\linewidth+\leftmargin-\ALG@tlm-\ALG@continueindent\relax}
\apptocmd{\ALG@beginblock}{\ALG@customparshape\everypar{\ALG@customparshapex}}{}{\errmessage{failed to patch}}
\makeatother
% end continuation indent patch


% user level stuff
\usepackage{amsmath}
\usepackage{lipsum}

% example copied from https://tex.stackexchange.com/questions/130199/how-to-automatically-keep-the-indentation-level-when-a-line-has-to-be-broken

% A command for defining assignments within the algorithmic environment
\newcommand{\Let}[2]{\State #1 $\gets$ #2}


\begin{document}

test in second column
\newpage

\begin{algorithmic}[1]
  \Function{test}{$(x, y)$}%
%  \State Some lines extend \raisebox{1ex}{higher} but we don't like that at the beginning of a block (leaves space above the vertical line).
    \Let{$a$}{some math expression}
    \Let{$b$}{some very very long expression that doesn't fit on one line and is
    even longer and longer \par\noindent and a new paragraph with another very very long expression that doesn't fit on one line}
    \For{each $e$ in a list}
        \Let{$l(e)$}{the length of element $e$}
        \If{some condition on $l(e)$}
            \State{run some complex sub-routine and get the result and this
            description is very very long, long indeed...}
            \Let{$a$}{some math expression}
            \Let{$b$}{some very very long expression that doesn't fit on one
            line and is even longer and longer}
            \If{some other condition}
                \Let{$c$}{another math expression}
                \State \(\begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}\)
            \EndIf
        \EndIf
%        \State \lipsum*[1-9]
    \EndFor
  \EndFunction
\end{algorithmic}

\end{document}

我已经删除了浮动结构,以显示当算法占用多页时这些行仍然看起来合理(取消注释该\lipsum行即可查看)。

输出演示了诸如矩阵之类的高线的问题:

输出

相关内容