1

When I use pdflatex to process a book-length document, in chapter 6 a couple of isolated links to theorem-like environments in that same chapter appear printed correctly in the pdf output, but clicking those links takes one to the same-numbered item in a different chapter!

Specifically, the link whose text is "Example 6.9" jumps to Example 1.9, and the link whose text is "Proposition 6.12" jumps to "Proposition 6.12".

The labels of the wrongly jumped-to targets are definitely entirely different from the labels of the intended targets.

What could be wrong?

Alas, so far I cannot produce a MWE. The preamble is split over a dozen separate files.

To help in the diagnosis, below are:

  • extracts from the source where the relevant labels are defined and where they are cross-referenced;

  • corresponding entries in the .aux files; and

  • extracted sections of the preamble files where theorem-like environments are defined and cross-referencing (hyperref, cleveref, crossreftools, etc.) is set up.

Wrong jump #1 - source in chapter 6 correctly prints in pdf as "Example 6.9":

Show that the quotient space $\mathbb{R} /!/ \mathbb{Q}$ of \cref{ex:non-cr-quot-cr} is in fact not a Hausdorff space.

Wrong jump #1 — target, again in chapter 6, is the following (but link jumps to 1.9 instead):

Show that the quotient space $\mathbb{R} /\!/ \mathbb{Q}$ 
of \cref{ex:non-cr-quot-cr} is in fact not a Hausdorff space.

Wrong jump #1 — target, again in chapter 6, is the following (but link jumps to 1.9 instead):

\begin{example}
\label{ex:non-cr-quot-cr}
\index{line with two origins!separation properties@and separation properties}%
\index{line with two origins!quotient space@as quotient space}

The line with two origins ....
\end{example}

Wrong jump #1 — .aux extract:

\@@wrindexm@m{topology2}{Cartesian sum!completely regular space@and completely regular space|hyperpage}{589}
\@writefile{loe}{\contentsline {example}{\ifthmt@listswap \MakeUppercase  {e}xample~6.9\else \numberline {6.9}\MakeUppercase  {e}xample\fi }{590}{example.9}\protected@file@percent }
\newlabel{ex:non-cr-quot-cr}{{\M@TitleReference {6.9}{Completely regular spaces}}{590}{}{example.9}{}}
\newlabel{ex:non-cr-quot-cr@cref}{{[example][9][]6.9}{[1][590][]590}}
\@writefile{lla}{\contentsline {section}{\numberline {\crtrefnumber{ex:non-cr-quot-cr}}ex:non-cr-quot-cr}{590}{example.9}\protected@file@percent }

Wrong jump #2 — source in chapter 6 is correctly printed in pdf as "Proposition 6.12":

Prove \cref{prop:closed-subspace-of-normal}: a closed subspace 
of a normal space is itself normal.

Wrong jump #2 — target, again in chapter 6, is the following (but link jumps instead to 2.12):

\begin{proposition}
\label{prop:closed-subspace-of-normal}    
A closed subspace of a normal space is itself normal.    
\end{proposition}

Wrong jump #2 — .aux extract:

\@@wrindexm@m{topology2}{subspace!normal space@of normal space|(hyperpage}{591}
\@writefile{loe}{\contentsline {proposition}{\numberline {6.12}Proposition}{591}{proposition.12}\protected@file@percent }
\newlabel{prop:closed-subspace-of-normal}{{\M@TitleReference {6.12}{Normal spaces}}{591}{}{proposition.12}{}}
\newlabel{prop:closed-subspace-of-normal@cref}{{[proposition][12][]6.12}{[1][591][]591}}
\@writefile{lla}{\contentsline {section}{\numberline {\crtrefnumber{prop:closed-subspace-of-normal}}prop:closed-subspace-of-normal}{591}{proposition.12}\protected@file@percent }

From the preamble:

%% MATH & THEOREMS
\usepackage{amsmath}
\usepackage{mathtools}
\usepackage{amsthm} 
\RequirePackage{thmtools}

\swapnumbers % Invert numbers/labels

\newcommand{\thmlikefont}{\sffamily\bfseries}

\declaretheoremstyle[
  headfont=\thmlikefont,
  headpunct={\thmlikefont.},
  postheadspace=0.5em,
  notefont=\thmlikefont,
  headformat=\NAME\NUMBER\let\thmt@space\@empty\NOTE,
  bodyfont=\mdseries,
  spaceabove=12pt,spacebelow=12pt,
  hidealllines=true,
  innerleftmargin=8pt,innerrightmargin=8pt,
  postheadhook={%
    \ifx\@empty\thmt@shortoptarg
      \renewcommand\addcontentsline[3]{}
    \fi}
]{thmstyle}
\theoremstyle{thmstyle}

\declaretheorem[name=Theorem,numberwithin=chapter]{theorem}
\newtheorem{proposition}[theorem]{Proposition}

\declaretheoremstyle[
  headfont= \thmlikefont,
  headpunct={\thmlikefont.},
  postheadspace=0.5em,
  notefont=\thmlikefont,
  bodyfont=\normalfont,
  spaceabove=12pt,spacebelow=12pt
]{defstyle}
\declaretheorem[
  style=defstyle,
  numberlike=theorem,
  preheadhook=\renewcommand{\qedsymbol}{$\myDiamond$}\pushQED{\qed},
  postfoothook=\popQED
  ]
{example}

%%  CROSS-REFERENCING
\RequirePackage{xurl}

\usepackage{datetime2} % to satisfy the "\today" in \hypersetup
\DTMusemodule{english}{en-US}

\RequirePackage{hyperxmp} % to add metadata info into pdf
\usepackage{hyperref}
\hypersetup{
  unicode,
  pdfapart=2, pdfaconformance=u,
  bookmarksnumbered,bookmarksopen=true,bookmarksopenlevel=3,
  breaklinks=true,
  colorlinks, citecolor=red, linkcolor=blue, urlcolor=blue,
  linktocpage=true,linktoc=all,
  pdftitle={Topology, Second Edition},
  % ...(other entries re author, publication, etc.)...
   pdfproducer=pdfTeX-1.40.23, %why needed ????????????
}

% Allow link to page with label -- patch by Martin Scharrer
% cf. https://tex.stackexchange.com/a/19416/9237
\let\orig@Hy@EveryPageAnchor\Hy@EveryPageAnchor
\def\Hy@EveryPageAnchor{%
    \begingroup
    \hypersetup{pdfview=Fit}%
    \orig@Hy@EveryPageAnchor
    \endgroup
}
% My commands to use that
% Usage: \crefpagetext{text-to-appar-in-link}{lbl} with usual \label{lbl} for target.
\newcommand{\crefpagetext}[2]{\hyperlink{page.\getpagerefnumber{#2}}{#1} on \cpageref{#2}}
\WithSuffix\newcommand\crefpagetext*[2]{\hyperlink{page.\getpagerefnumber{#2}}{#1}}

\AtBeginDocument{\addtocontents{toc}{\protect\hypersetup{hidelinks}}}

%% Allow ref to section n, not section m.n
% From "trickier version" by Christian Hupfer
% https://tex.stackexchange.com/a/383608/13492
\let\@xp\expandafter
%
% Stripping the dot from the 1.2 -like reference
\def\@@stripdot#1.#2\@nil{#2}
%
% Stripping the memoir stuff from the reference, i.e. \M@TitleReference {1.2}{FOO} and handing #1 (1.2) over to the \@@stripdot macro
\def\@stripdot\M@TitleReference #1#2\@nil{\@@stripdot#1\@nil}
%
%Macro, second level of expansion
\newcommand{\stripdot}[1]{%
  \@xp\@stripdot#1\@nil
}
\newcommand{\crefsec}[1]{%
  % Expand the argument first
  \IfRefUndefinedExpandable{#1}{%
    % Do nothing if #1 is not defined
  }{%
    \hyperlink{\getrefbykeydefault{#1}{anchor}{}}{\@xp\stripdot\@xp{\getrefnumber{#1}}}%
  }%
}

\RequirePackage[nameinlink,noabbrev,capitalize]{cleveref}
\RequirePackage{crossreftools}
% Fix to crossreftools
% https://tex.stackexchange.com/a/512175/13492
\renewcommand{\@@crtextr@ct@ref}[2]{%
  \expandafter\@@@crtextr@ct@ref\expandafter{\detokenize{#2}}{#1}%
}
\newcommand{\@@@crtextr@ct@ref}[2]{%
  \expandafter\ifx\csname r@#1\endcsname\relax
  \crt@refundefined%
  \else
  \expandafter\expandafter\csname crt@ref@splitter@#2\endcsname\csname r@#1\endcsname%
  \fi
}

\crefname{proposition}{Proposition}{Propositions}
\Crefname{proposition}{Proposition}{Propositions}
\crefname{example}{Example}{Examples}
\Crefname{example}{Example}{Examples}

% Added 2020-03-17
% From https://tex.stackexchange.com/questions/1230/reference-name-of-description-list-item-in-latex
\def\namedlabel#1#2{\begingroup
    #2%
    \def\@currentlabel{#2}%
    \phantomsection\label{#1}\endgroup
}

Many other packages are loaded, including babel, but I think the ones shown in the preceding preamble extract are the relevant ones.

Added 2022-04-28 attempted fixes

I tried suggestions from https://tex.stackexchange.com/a/642073/13492, but without success:

  1. Replacing the \newtheorem declarations to corresponding ones from thmtools. Thus I used the following, which does not eliminate the wrong jumps:

    \declaretheorem[name=Theorem, style=thmstyle, numberwithin=chapter]{theorem}
    
    \declaretheorem[name=Proposition, style=thmstyle, numberlike=theorem]{proposition}
    \declaretheorem[name=Definition, style=defstyle, numberlike=theorem]{definition}
    
  2. I was unable to match the git diff file for aliascntr.dtx with the existing version of that aliascntr.dtx in TeXLive 2022.

  3. In addition to the changes indicated in #1, I added the \counterwithin statements from 3:

     \counterwithin{proposition}{chapter}
     \counterwithin{example}{chapter}
    

Now the jumps seem to be correct!

Given the size and complexity of the book and its source files, I need to continue sampling link jumps to verify that all is now well.

3
  • 3
    sorry but you really should know that such snippets are useless. check the log-file for warning about duplicated destinations and resolve them. Apr 25, 2022 at 21:50
  • @UlrikeFischer: How can such a duplicate destination elsewhere affect instances as I report? The labels in question are not duplicated elsewhere in the source.
    – murray
    Apr 26, 2022 at 0:57
  • 1
    Does it help if you replace \newtheorem{proposition}[theorem]{Proposition} with the analogous statement using the thmtools syntax of \declaretheorem....? It makes me nervous that you are mixing the two. (My impression the last time I dug into thmtools code is that they are not exactly equivalents.) Apr 26, 2022 at 3:50

1 Answer 1

1

Looking at the aux file output, I have a suspicion that you are running into the same (or at least very similar) bug that I diagnosed in this previous answer.

While a patch has been checked into the Git repo, a release has not been made onto CTAN (the current version is dated August 2020). If I were you I would try a few different things:

  1. First try to see changing everything to thmtools syntax helps. I am pessimistic that this will solve your problem.
  2. If you feel confident at mucking about with package internals: make a copy of the aliasctr.sty file from thmtools into your working directory, and apply the changes indicated in the Git commit fixing this bug.
  3. Alternatively, if you are not confident mucking about, I would suggest trying the following workaround:
    • Step 1: change the declaration of proposition to thmtools syntax. (This is important, this workaround depends on how \declaretheorem works and will fail with \newtheorem.)
    • Step 2: add, after declaring proposition and example, the following two lines (for an explanation of why this may work, see the first link to my diagnoses above)
    \counterwithin{proposition}{chapter}
    \counterwithin{example}{chapter}
    
  4. Alternatively: you can also rewrite everything using completely just amsthm syntax and not thmtools. The syntax for amsthm is certainly clunkier, but the code does work with cleveref. (I've generally avoided using thmtools myself now.)
10
  • I have doubts that some incompability between cleveref and thmtools affects the destination names. The name is stored with a normal label command and not in the cleveref label. The snippets in the question show the names proposition.12 and example.9 and that is simply not unique as it doesn't contain the chapter number. Apr 26, 2022 at 7:58
  • @UlrikeFischer It is not a incompatibility between cleveref and thmtools per se: the way thmtools handled multiple environments sharing the same counter was buggy. amsthm for example just pointed the counter to the one it is supposed to duplicate. But thmtools internally created a duplicate alias counter, and very crucially, forgets to add the duplicate counter to the reset-by list. So if hyperref is picking up on the proposition counter, it would not know that it would be reset by chapter. Hence the hypertarget is duplicated (missing chapter number). Apr 26, 2022 at 13:11
  • @UlrikeFischer at least, the above is my guess of what is happening, since the duplicated destination is most likely due to a counter being reset outside of the knowledge of hyperref. This is similar to what happened in the cleveref case. I would test it if the OP had provided a MWE that I can play with. Apr 26, 2022 at 13:23
  • I quite believe that there is perhaps a bug. But that doesn't really matter. hyperref tries to make the names unique, but its method is not fool proof (and isn't meant to be). The correct way to resolve something faulty destination names from the point of view of hyperref is to manually define \theH<counter> so that it works and not rely on hyperref's guesses. Apr 26, 2022 at 13:26
  • @UlrikeFischer please do write an answer explaining that. Apr 26, 2022 at 13:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .