我想使用hyperref
包的\autoref{}
命令来引用算法行。为此,我使用这补丁。这确实打印了正确的行数字对于每个引用的标签,但关联当文档中存在多个算法时,指向错误的算法。
更具体地说,链接似乎指向第一个包含带有引用标签的行号的算法。我猜底层标签在不同的算法中并不唯一,因此选择了第一个实例。
编辑:我读过patchcmd
和refstepcounter
,这个问题似乎正是我所想的那样。解决这个问题需要做的不是使用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}
find
将sub
定义中的所有 字符串替换为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