Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

For some reason I do not understand, cleverefproduces wrong references to line numbers of listings produces with the algorithm2e package. I hope that I did not miss a simple solution ...

My example is the following:

\documentclass[paper=A4, fontsize=11pt]{scrbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[linesnumbered]{algorithm2e}
\usepackage{hyperref}
\usepackage{cleveref}

\begin{document}

\begin{algorithm}
Do something\;
Do something else\;\label{line}
\end{algorithm}

line~\ref{line} vs.\ \cref{line}.
\end{document}

The output (which you can also check online) is

Example output

The \ref command works as expected (and refers to line 2) but the \cref command always refers to line 1 (no matter how many lines there are and which line I try to reference).

Does anybody know a solution to this problem?

share|improve this question
    
I compiled your MWE and both refer to line 1 (except cleveref doesn't seem to know lines). But shouldn't you be ending your lines by `\` so there actually is a linebreak? –  Anke Mar 18 '13 at 14:03
    
It seems that the order in which one loads the algorithm2e and cleveref packes decides whether cleveref know what a line is. I added a link to an online LaTeX processor, which produces the same output. So far, using \; always worked for me. –  Dan Mar 18 '13 at 14:10
    
cleveref has to be loaded after hyperref, which has to come after everything else, so I don't see how you would be able to change the order there. I don't know what the difference between this online compiler and mine is, but I don't see why yours knows lines with the above MWE, while mine doesn't, or why yours refers to different lines, while mine refers to the same (line 1...) –  Anke Mar 18 '13 at 14:59
    
You may have discovered an incompatibility between the cleveref and algorithm2e packages, possibly introduced when the algorithm2e package was last updated, in Jan. 2013. I'd encourage you to contact the author of the cleveref package to make him aware of this issue. (The cleveref package was last updated in Sept. 2012...) You may find his contact information on the title page of the manual of the cleveref package. –  Mico Mar 18 '13 at 16:06
add comment

3 Answers

You found an oversight in the cleveref package. First, algorithm2e numbers the lines with the AlgoLine counter, and cleveref does not track that. So we need a

\crefalias{AlgoLine}{line}

to get that sorted.

Next, cleveref hacks into the \label command to write another label for its own use. In your example, the .aux contains

\newlabel{line}{{3}{1}{}{AlgoLine.1.3}{}}
\newlabel{line@cref}{{[line][1][]1}{1}}

The second line is written by cleveref. The offending part here is {[line][1][]1}, which is actually the content of \cref@currentlabel. Why is it wrong? While \label looks at \@currentlabel, cleveref uses its own \cref@currentlabel to determine what is been labeled. In order to keep that up to date, cleveref hacks into \refstepcounter, and updates \cref@currentlabel there. This works fine when algorithm2e is used without hyperref, but when hyperref is also loaded, the AlgoLine counter is updated with \stepcounter, and cleveref does not hack into that! This also means that cleveref will fail on all counters that are not (only) manipulated with \refstepcounter.

The solution is to also hack into \stepcounter, and update \cref@currentlabel there, too. The code for doing so is the same as for \refstepcounter. The complete code is then

\documentclass[paper=A4, fontsize=11pt]{scrbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[linesnumbered]{algorithm2e}
\usepackage{hyperref}
\usepackage{cleveref}

\crefalias{AlgoLine}{line}%

\makeatletter
\let\cref@old@stepcounter\stepcounter
\def\stepcounter#1{%
  \cref@old@stepcounter{#1}%
  \cref@constructprefix{#1}{\cref@result}%
  \@ifundefined{cref@#1@alias}%
    {\def\@tempa{#1}}%
    {\def\@tempa{\csname cref@#1@alias\endcsname}}%
  \protected@edef\cref@currentlabel{%
    [\@tempa][\arabic{#1}][\cref@result]%
    \csname p@#1\endcsname\csname the#1\endcsname}}
\makeatother

\begin{document}
\begin{algorithm}
Do something\;
Do more\;
Do something else\;\label{line}
\end{algorithm}

line~\ref{line} vs.\ \cref{line}
\end{document}
share|improve this answer
    
Very nice! Just one point, though: Are you sure the issue is due to an oversight of the cleveref package? Could it, alternatively, be due to a change introduced when the algorithm2e package was last updated? The reason I raise this possibility is that the cleveref package (incarnation of Sept. 2012) claims to support the algorithm2e package -- see section 14.6.9. on p. 106 of the extended user guide. Cleveref executes, inter alia, \crefalias{algocfline}{line} for this purpose. This makes me wonder if algorithm2e recently renamed the counter algocfline to AlgoLine... –  Mico Mar 18 '13 at 17:42
    
@Mico This might very well be. However, tracking counters by only monitoring \refstepcounter is fragile. By the way, the algocfline counter is still there, but it seems it is not used anymore. –  mafp Mar 18 '13 at 19:04
add comment

mafp's solution is a bad idea, and should be avoided. Hacking \stepcounter is definitely the wrong thing to do, as it's used to step all kinds of counters unrelated to cross-references. Cross-reference counters ought to always be stepped by \refstepcounter, which additionally takes care of setting \@currentlabel appropriately. Thus "only monitoring \refstepcounter" is precisely the right thing to do. Most cross-referencing-related packaged (hyperref, varioref...) work this way.

Unfortunately, when hyperref is loaded, algorithm2e by-passes both \refstepcounter and \H@refstepcounter (hyperref's version of the same), for reasons of its own (related to avoiding creating duplicate hyperlink anchors, I believe). This is an unfortunate choice of implementation, since by-passing the standard cross-reference machinery means packages like cleveref have to maintain fragile, specially-crafted support for algorithm2e. But that's LaTeX2e for you.

With hyperref loaded, algorithm2e has to take care of setting \@currentlabel itself (since it by-passes \refstepcounter). The correct solution is to modify algorithm2e so that it sets \cref@currentlabel at the same time as \@currentlabel. The latest version of cleveref (0.18.8) contains a fix for this.

It would be helpful if people reported bugs like this to the package author, instead of just posting them to stackexchange and using whatever ugly work-arounds are suggested in the replies. That way bugs get fixed in the package itself, and everyone benefits.

share|improve this answer
2  
Welcome to TeX.SE! It's great to have you on this site! –  Mico Mar 22 '13 at 17:02
    
Why so angry? Did I step on your toes somehow? –  mafp Mar 22 '13 at 17:16
1  
@mafp I wasn't angry at all - sorry if that's the way it came across. I just wanted to point out that hacking \refstepcounter is a bad idea, and should be avoided. (Trust me, as cleveref author, I know the kind of mess this gets you into :) –  Toby Cubitt May 2 '13 at 3:04
add comment

I found a simple solution for the incompatibility of hyperref+algorithm2e line numbering. Just use \nllabel instead of \label. Worked for me. Credits to Karthik: http://martinharrigan.blogspot.com.br/2007/11/using-hyperref-and-algorithm2e-line.html

share|improve this answer
    
Welcome to TeX.sx! Please consider to add more detail so that your post becomes a self-contained answer. –  lockstep Mar 25 '13 at 18:24
    
Have you tested this? Using \nllabel yields the same result as using \label (tested on ShareLaTeX). –  Werner Mar 25 '13 at 18:30
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.