![algorithmicx 中的垂直线问题](https://linux22.com/image/267138/algorithmicx%20%E4%B8%AD%E7%9A%84%E5%9E%82%E7%9B%B4%E7%BA%BF%E9%97%AE%E9%A2%98.png)
我使用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
我想将命令翻译成我的语言。对于常见命令,翻译不会破坏垂直线。
\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
如何修复?
当我使用高度大于高度线的大公式时,垂直线会中断。
\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
。因此,唯一能想到的解决方案是tikz
和zpos
。我改编了来自的代码在页边空白处用线标记条件版本对于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&\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
行即可查看)。
输出演示了诸如矩阵之类的高线的问题: