在多个算法中引用行

在多个算法中引用行

我想使用hyperref包的\autoref{}命令来引用算法行。为此,我使用补丁。这确实打印了正确的行数字对于每个引用的标签,但关联当文档中存在多个算法时,指向错误的算法。

更具体地说,链接似乎指向第一个包含带有引用标签的行号的算法。我猜底层标签在不同的算法中并不唯一,因此选择了第一个实例。

编辑:我读过patchcmdrefstepcounter,这个问题似乎正是我所想的那样。解决这个问题需要做的不是使用refstepcounter行计数器(用于在算法左侧显示行号),而是使用一个额外的行计数器,它跟在算法编号后面,就像小节编号跟在节后面一样。在这种情况下,引用算法 1 中的第 2 行应该会产生“第 1.2 行”。

平均能量损失

\documentclass[a4paper,11pt]{book}

\usepackage{parskip}
\usepackage[noend]{algpseudocode}      % Algorithm syntax
\usepackage[algochapter]{algorithm}    % Algorithm float
\usepackage{hyperref}

%%%
% Add \autoref prefix to algorithm line references (https://tex.stackexchange.com/a/351229/203081)
\makeatletter
\patchcmd{\ALG@step}{\addtocounter{ALG@line}{1}}{\refstepcounter{ALG@line}}{}{}
\newcommand{\ALG@lineautorefname}{line}
\makeatother
%%%

\begin{document}

Correctly points to first: \autoref{line:first}

Incorrectly points to first:  \autoref{line:second}

Correctly points to second: \autoref{line:third}

\newpage 

\begin{algorithm}
    \caption{Algo 1}
    \begin{algorithmic}[1]
        \Function{one}{$x$}
            \State foo \label{line:first}
            \State bar
        \EndFunction
    \end{algorithmic}
\end{algorithm}

\newpage

\begin{algorithm}
    \caption{Algo 2}
    \begin{algorithmic}[1]
        \Function{two}{$y$}
            \State yeet
            \State sike \label{line:second}
            \State rizz \label{line:third}
        \EndFunction
    \end{algorithmic}
\end{algorithm}

\end{document}

行引用

答案1

以下是对为什么会发生这种情况的完整诊断:

  • \patchcmd{definiendum}{find}{sub}findsub定义中的所有 字符串替换为definiendum。在这种情况下:\ALG@step每当算法移动到下一行时都会被调用,因此它\addtocounter{ALG@line}{1}里面有一个。
  • \ref\autoref以 a 的参数作为参数\label,并生成超链接不是到标签所在的位置,但到该\label调用之前设置的最后一个“超级挂钩”的位置。默认情况下,algorithm环境会将挂钩放在其标题栏上,但algorithmic环境不会将挂钩放在其行上。因此,默认情况下,将标签放在行旁边会将它们挂钩到正确的算法,但它们都会刷新到前面的标题栏,而不是挂钩到行。
  • 钩子具有唯一的 ID。当两个钩子具有相同的 ID 时,任何label与第二个钩子挂钩的钩子都会产生指向第一个钩子的链接。
  • \stepcounter将计数器加 1。\refstepcounter作用相同,但是根据计数器的值将钩子放在当前位置,对此钩子的引用将作为计数器的值显示在文本中。
  • 对于章节和小节,请注意小节值会随着每个章节重置,但即使已经有小节 1.1,您仍然可以生成到小节 2.1 的链接;即使在两种情况下小节计数都显示为 .1,钩子 ID 也是不同的。
  • 这种重置是不是ALG@line当一个新的algorithmic开始时会发生什么。相反,它是手动的强制降至 0。结果:它将产生相同的与其他算法一样,钩子 ID 也具有相同的行号。

您应该用以下代码替换\makeatletter... :\makeatother

\newcounter{algoline}[algorithm]
\renewcommand{\thealgoline}{\arabic{algoline}}

\makeatletter
\patchcmd{\ALG@step}{\addtocounter{ALG@line}{1}}{\stepcounter{ALG@line}\refstepcounter{algoline}}{}{}
\newcommand{\algolineautorefname}{line}
\makeatother

它将算法视为节,将行视为其子节。也就是说:当从一个算法移动到下一个算法时,行似乎会重置,但计数器系统会为行 1.1 和行 2.1 的钩子生成一个唯一的 ID。

答案2

感谢@Mew 的分析。

看来我只需要\theHALG@line适当更改一下,用来hyperref生成唯一的标签就可以了。

现在我不需要手动更改它,因为命令\@addtoreset已被重新定义,hyperref因此\theHALG@line现在已正确定义。我猜这(在新算法启动时清除计数器)不会影响的工作algorithmx

总之,用以下代码替换\makeatletter...\makeatother即可:

\makeatletter
\@addtoreset{ALG@line}{algorithm}
\makeatother

相关内容