相互参照(ref / cref / varioref)

LaTeX は文書を上から下へ一度だけ読みます。ですから 2 ページ目に \ref{fig:leaf} と書いても、その図が 40 ページ目にあるなら番号はまだ存在しません——LaTeX の相互参照(クロスリファレンス)の仕組み全体は、この 参照が対象より先に来る という一点を解くために作られています。答えは驚くほど素朴で、一度目の実行で番号を .aux ファイルに書き留め、二度目の実行で読み返すだけ。このページでは、その二度のコンパイル、途中で現れる太字の ??\label\caption の前に置くと番号がずれる理由、そして cleverefvarioref による改善を順に追います。

\label\ref — 番号を打たずに名前で呼ぶ

相互参照は二つの命令だけで成り立っています。\label{key} は、その地点で 最後に増えたカウンタ の値に key という名札を結び付け、紙面には何も出しません。\ref{key} はその名札が指す 番号だけ を差し込みます。番号を数えるのは LaTeX なので、あなたは一度も数字を打ちません。key は自由な文字列で、図の順序を入れ替えても、節を丸ごと別の章へ移しても、名札さえ付いていれば参照は追随します。手で「図 3」と書いた文書がひとつの移動で総崩れになるのに対し、こちらは何も壊れません。

latex
\section{Introduction}
\label{sec:intro}

\begin{equation}
  \label{eq:euler}
  e^{i\pi} + 1 = 0
\end{equation}

\begin{figure}
  \centering
  \includegraphics{leaf}
  \caption{Vein structure of a leaf}
  \label{fig:leaf}          % after \caption, always
\end{figure}

As shown in Section~\ref{sec:intro}, equation~\eqref{eq:euler}
and Figure~\ref{fig:leaf} agree on page~\pageref{fig:leaf}.

ここで一点、初心者がつまずきやすいところがあります。\ref が返すのは 番号だけ で、「図」「式」「第…節」といった語は付いてきません。語は自分で書く必要があり、しかも番号との間は半角空白ではなく 連結スペース ~(タイ)でつなぐのが定石です。Figure \ref{fig:leaf} と書くと「Figure」で行が終わり「3」だけが次の行に取り残される事故が起きますが、Figure~\ref{fig:leaf} ならそこで改行されません。この「語を手で書く」作業こそが、あとで出てくる \cref\autoref が肩代わりしてくれる部分です。

なぜ 2 回コンパイルするのか — .aux ファイルと ??

相互参照は 1 回のコンパイルでは確定しません\label に出会うたび、LaTeX はその番号とページを本文と同じ基底名の .aux ファイル に書き出します。そして \ref が読めるのは、前回の実行で .aux に書き込まれた情報だけです。ですから初回は参照先の値がどこにも無く、出力には 太字の ?? が現れ、ログには二種類の警告が並びます。この二つはどちらも検索されやすい文言なので、そのまま覚えておくと役に立ちます。

log
LaTeX Warning: Reference `fig:leaf' on page 1 undefined on input line 17.
LaTeX Warning: There were undefined references.
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.

この ?? は事故の副産物ではなく、LaTeX カーネルに 書き込まれた仕様 です。latex.ltx\@setref は、名札が未定義だった場合に \reset@font\bfseries ?? を組み、そのすぐ次の行で「Reference … undefined」の警告を出します。太字なのは、周囲の書体に紛れず一目で見つかるようにするためです。もう一度コンパイルすれば .aux の値が読み込まれ、?? は正しい番号に変わります。番号が前後にずれて参照値が変わるとまた警告が戻るので、警告が消えるまで 繰り返すのが正しい手順です(実務ではたいてい 2 回で足ります)。latexmk はこの繰り返しを自動で回し、Overleaf も裏で複数回処理するため、そこでは ?? を見ること自体まれです。

.aux は普通のテキストファイルなので、開いて中を読めます。名札一つにつき \newlabel の行が一つ書かれ、その中身は 五つのフィールド です。番号、ページ、見出しの文字列、リンク先のアンカー名、そして予備の一つ。三番目があるおかげで \nameref は「タイトルそのもの」を差し込めますし、四番目があるおかげで hyperref はクリック先を決められます。参照が壊れて原因が分からないときは、まず .aux を開いてその行が存在するかを見るのが最短経路です。行ごと消えていれば \label が拾われていない、値が変なら次節の置き場所の問題です。

mydoc.aux
% one line per label: {number}{page}{title}{anchor}{spare}
\newlabel{sec:intro}{{1}{1}{Introduction}{section.1}{}}
\newlabel{fig:leaf}{{2}{3}{Vein structure of a leaf}{figure.2}{}}

\ref が違う番号を返すとき — \label\caption の後に

図の参照が図の番号と一致しない——この症状の原因は、ほぼ例外なく \label の置き場所です。\label は「figure 環境の中にある」という理由で図番号を拾うのではありません。拾うのは 直前に増えたカウンタ の値であり、figure 環境そのものはカウンタを一切増やしません。カウンタを進めるのは \caption です。したがって \begin{figure} の直後に \label を書くと、それは図番号ではなく、その時点で最後に増えていたカウンタ——多くの場合、直前の節や章の番号——を拾ってしまいます。

これは口で言うより実験したほうが早く納得できます。7 番目の節の中に図を一つ置き、\caption の両方に名札を付けて TeX Live 2024 の pdfLaTeX でコンパイルすると、.aux にはこう書かれます——前に置いた名札は 7(節番号)、後に置いた名札は 1(図番号)。しかも警告は一切出ません。番号としてはどちらもありうる値なので、LaTeX には間違いだと判断しようがないのです。エラーで止まってくれないぶん、この事故はレビューをすり抜けて印刷まで届きます。

latex
\section{A}\section{B}\section{C}
\section{D}\section{E}\section{F}\section{G}   % we are now in section 7

\begin{figure}
  \label{fig:before}      % WRONG: no counter stepped yet -> picks up 7
  \centering\rule{2cm}{1cm}
  \caption{A leaf}        % <- this is what steps the figure counter
  \label{fig:after}       % RIGHT: picks up 1
\end{figure}

% .aux after two runs:
%   \newlabel{fig:before}{{7}{1}{}{}{}}
%   \newlabel{fig:after}{{1}{1}{}{}{}}

規則は一つに要約できます。\label は番号を生み出す命令のすぐ後ろに置く。 図と表なら \caption の後(\caption の引数の中に書いてもかまいません)、見出しなら \section などの直後、番号付き数式なら equation 環境の中、箇条書きの項目なら \item の後です。\caption を複数持つ図で名札を一つしか付けないと、どの \caption の後ろに置いたかで指す番号が変わります。それから \label\caption に書ける唯一の妥当な場面は、そもそも \caption を使わない場合だけだと考えて差し支えありません。

\pageref と名札の付け方

番号ではなく ページ を指したいときは \pageref{key} を使います。同じ名札を受け取り、その \label組まれたページの番号 を返すので、Figure~\ref{fig:leaf} on page~\pageref{fig:leaf} のように番号とページを併記できます。.aux\newlabel の二番目のフィールドがそのまま返ってくる、と考えれば構造も腑に落ちるはずです。長い報告書や製本された論文のように、読者が実際にページをめくる文書ほど効きます。

key は好きに付けられますが、種類を表す接頭辞 を添える書き方が広く使われています。sec: fig: tab: eq: ch: lst: といった具合です。効き目は二つ。第一に fig:leaf のように 中身で名付けておけば、図の順序を入れ替えても名札を付け直さずに済みます(fig:3 のような名前を付けると、二枚目を挿入した瞬間に嘘になります)。第二に、\ref{fig:...} を目にした時点で参照先の種類が分かるので、あとで \cref に切り替えるときにも自分の文書を機械的に読み替えられます。

接頭辞指す対象
ch:章(\chapter
sec:節・小節(\section\subsection
fig:図(figure\caption の後)
tab:表(table\caption の後)
eq:番号付き数式(equation などの中)
lst:コードリスト(listings などの \caption の後)

\eqref — 数式番号に括弧を付ける(amsmath)

数式番号は慣習として括弧付きで書きますが(「式 (3) より」)、素の \ref3 としか返しません。amsmath を読み込むと使える \eqref{key} は括弧を補って (3) を返します。ここでの本当の利点は手間ではなく 書体 です。\eqref の括弧は周囲の書体によらず常に立体(直立体)で組まれるので、定理環境のようにイタリックが地の文になっている場所でも括弧だけが傾きません。手で (\ref{eq:euler}) と書くと、まさにその括弧が斜めになります。

cleveref\cref\Cref で語も単複も自動に

cleveref は参照を一段引き上げます。\cref{key} は種類を表す語を自動で前置し(既定は略記の「fig. 1」、noabbrev オプションで「figure 1」)、\Cref{key} はその先頭を大文字にして文頭で使えるようにします。真価は 複数と範囲 です。\cref{fig:a,fig:b,fig:c} のように空白なしのカンマ区切りで渡すと、番号を並べ替えて連結し、語を複数形に直してまで「figs. 1, 2 and 4」のように出力します。しかも番号が連続していれば自動で範囲に畳まれ、上の三つは「figs. 1 to 3」になります。\crefrange{first}{last} は同じ縮約を、両端の名札だけを書いて 得るための命令です。

前置きの語は \crefname{type}{単数}{複数}(先頭大文字版は \Crefname)で定義し直せます。日本語化もこれで行い、たとえば \crefname{figure}{図}{図} のように単数・複数とも同じ語を与えます。文書全体で常に大文字にしたければ capitalise オプションを付けて読み込みます。逆に、語は要らず番号だけほしい場面——括弧の中や表のセルなど——では \labelcref{key} を使えば素の \ref と同じものが得られます。

読み込み順序には絶対の決まりがあります。cleverefhyperrefvariorefamsmath のいずれよりも後cleverefhyperref が定義したものを検出して自分の命令を組み立てるので、逆順では成立しません。ありがたいことに、これは黙って壊れるのではなく、TeX Live 2024 同梱版の cleveref.sty\begin{document} の時点で順序を検査し、下のようにはっきり止まります。ただし varioref も併用する場合は別で、cleveref のマニュアルは varioref → hyperref → cleveref の順を指定したうえで、順序を誤ると出力にもログにも警告が出ないまま参照が全く別の対象を指しうる、と注意しています。

latex
\usepackage{varioref}
\usepackage{hyperref}
\usepackage{cleveref}   % always last of the three

% If cleveref is loaded before hyperref, TeX Live 2024 stops with:
%   ! Package cleveref Error: cleveref must be loaded after hyperref!.
%   Package load order is wrong: load cleveref *after* hyperref.

\cref{fig:a,fig:b,fig:c}       % figs. 1 to 3   (consecutive: compressed)
\cref{eq:euler,eq:max}         % eqs. (1) and (4)
\Cref{sec:intro} explains ...  % Section 1 explains ...
\labelcref{fig:a}              % 1   (number only, like \ref)

% with \usepackage[noabbrev]{cleveref} the same lines give
%   figures 1 to 3 / equations (1) and (4)

varioref — 「次のページの図」と書き分ける

製本された文書では、機械的に「12 ページの図 3」と書くより、近ければ「次のページの図 3」、見開きの反対側なら「向かいのページの図 3」と書けたほうが自然です。varioref\vref{key}\ref と同じ番号を出しつつ、参照元と参照先の ページ関係を見て 案内の語句を足します。同じページなら何も足しません。ページだけを案内したいときは \vpageref{key} を使い、二つの省略可能引数で、同じページに来た場合の語句と、別ページのときの前置きをそれぞれ指定できます。

この賢さには代償があります。\vref の出力は組版の結果(どのページに落ちたか)に依存し、その出力の長さがまた改ページの位置を動かしうるので、値が落ち着くまで 追加のコンパイル が必要になることがあります。ログに「Rerun to get cross-references right」が出続けるときは、たいていこれが原因です。cleveref と併用すると \vref は cleveref の書式で組まれるようになるので、両方使うなら順序(varioref → hyperref → cleveref)を守ったうえで、文書全体を \cref 系に寄せておくのが混乱が少なくて済みます。

latex
\usepackage{varioref}

See~\vref{fig:leaf}.
%   same page : See figure 3.
%   next page : See figure 3 on the next page.
%   far away  : See figure 3 on page 12.

The data is summarised \vpageref[above][]{tab:data}.

どれを選ぶか迷ったら、文書全体を cleveref に寄せる のが実務的な答えです。種類の語も単複も複数参照も範囲も自動で面倒を見てくれるので、図~\ref{tab:...} のように「図」と「表」を取り違える種類の間違いが原理的に起きません。\ref\pageref は仕組みを理解するうえで欠かせませんし、\eqref は数式で、\vref は製本物で、それぞれ今も現役です。次の表は、どれが何を出力するかの一覧です。

命令出力提供元
\label{key}直前のカウンタに名札を付ける(紙面には何も出ない)LaTeX 標準
\ref{key}番号だけ(例: 3)LaTeX 標準
\pageref{key}その名札が組まれたページ番号LaTeX 標準
\eqref{key}括弧付きの式番号(例: (3))。括弧は常に立体amsmath
\autoref{key}種類の語+番号、全体がリンク(例: Figure 3)hyperref
\nameref{key}見出しのタイトル文字列そのものhyperref
\vref{key}番号+ページ案内(次のページに、など)varioref
\cref{key}種類の語+番号。複数・範囲・単複を自動処理cleveref
\Cref{key}\cref の先頭大文字版(文頭用)cleveref
\crefrange{a}{b}連続範囲(例: figures 1 to 3)cleveref
\labelcref{key}番号だけ(種類の語を付けない \crefcleveref