Define aliases for indices

We defined the following command to generate an index for a publication

\newcommand{\markindex}[1]{\index{#1}#1}


In a text, it is however possible that one uses synonyms interleaved (e.g.), abbrevations or shorter versions (e.g. traveling salesman instead of traveling salesman problem) due to the context of the sentence:

A \markindex{graph} consists out of a set of \markindex{nodes} or \markindex{vertices} and a set of \markindex{edges}.


As a result, the compiler generates an index with:

nodes, 1,2,7,9
vertices 1,2,5,6,7

We are looking for a method to define an alias

\indexalias{nodes}{vertices}


Such that not only nodes contains a see vertices entry, but all the page numbers are grouped on conto of vertices. This centralizes data (otherwise it is possible that readers miss the entries of nodes when they look up vertices) and makes it more compact (two references to the same page are "compressed" in one reference).

Is there a package (or an option in \makeidx we've overlooked) for this?

• In my opinion you should stick to call those things either nodes or vertices, not both. So a simple “nodes, see vertices” entry will suffice. – egreg May 15 '14 at 20:32
• This was of course an illustrative example. But for instance sometimes one uses an abbreviation (TSP instead of traveling salesman problem), or traveling salesman instead of traveling salesman problem. – Willem Van Onsem May 15 '14 at 20:54
• Please, make the question clearer, then. – egreg May 15 '14 at 20:55
• see intex package. it is not included in texlive and I haven't tested it, but I like the idea of controlled vocabulary file. See github.com/mtr/intex and raw.githubusercontent.com/mtr/intex/master/latex/intex.pdf for documentation – michal.h21 May 15 '14 at 21:27

I know I'm late for the party, but I ran into this problem recently. For reference, here is my code.

\makeatletter
\def\indexDefineAlias#1#2{%  #1 = alias, #2 = original, the one to display in index
\protected@write\@auxout{}%
{\string\indexalias{#1}{#2}}%
}

\def\indexalias#1#2{%  #1 = alias, #2 = original, the one to display in index
\edef\@tmp@nm{@indexali@\detokenize{#1}}%
\expandafter\gdef\csname\@tmp@nm\endcsname{#2}%
% add here alternative "|<attributes>" to also define aliases for:
%\expandafter\gdef\csname\@tmp@nm|textbf\endcsname{#2|textbf}%
}
\let\@orig@index\index
\def\index#1{%
\edef\@tmp@nm{@indexali@\detokenize{#1}}%
\ifcsname\@tmp@nm\endcsname%
\@orig@index{\csname\@tmp@nm\endcsname}%
\else%
\@orig@index{#1}%
\fi%
}
\makeatother


Use \indexDefineAlias{alias}{original} to define the alias. You need two runs of LaTeX to get the aliases active. Then you can just use \index{} normally with either term and only the original will be shown in the index.

The downside of this code is that aliases are not recognized when the index entry has attributes such as in \index{term|textbf}. You can add the aliases with the attributes manually (\indexDefineAlias{nodes|textbf}{vertices|textbf}), or add the attributes you're interested in the definition of \indexalias as I've marked in a comment.

If you want a "nodes, see vertices" entry you can use as usual \index{nodes|see{vertices}}.

Technical note: the \detokenize is useful if the index entry has custom macros. Even if they are robust, I had trouble with \csname...\endcsname.

The following example defines \markindex with the following variants:

• \markindex{<term>}: \index{<term>}<term>

• \markindex[<term>]{<alias>}: \index{<term>}<alias>, additionally it adds \index{<alias>|see{<term>} the first time it is used.

• \markindex*[<term>]{<alias>}: \index{<term>}<alias>, but \index{...|see{...}} is not added. For example, this is useful, if the <alias> is just a inflection form of <term> or if <term> starts a sentence with its first letter in uppercase.

Example file:

\documentclass{article}
\usepackage{makeidx}
\makeindex

\makeatletter
\newif\ifmarkindexsee
\newcommand*{\markindex}{%
\@ifstar{%
\markindexseefalse
\@dblarg\@markindex
}{%
\markindexseetrue
\@dblarg\@markindex
}%
}
\def\@markindex[#1]#2{%
\index{#1}%
\ifmarkindexsee
\edef\@markindex@A{\detokenize{#1}}%
\edef\@markindex@B{\detokenize{#2}}%
\ifx\@markindex@A\@markindex@B
\else
\edef\MI@see{MI@\@markindex@A ->\@markindex@B}%
\@ifundefined{\MI@see}{%
\index{#2|see{#1}}%
\global\expandafter\let\csname\MI@see\endcsname\@empty
}{}%
\fi
\fi
#2%
}
\makeatother

\newcommand*{\dummypage}[1]{%
\newpage
\setcounter{page}{#1}%
\section{Page #1}%
}

\begin{document}
\dummypage{1}
\markindex[vertices]{nodes}
\markindex{vertices}

\dummypage{2}
\markindex[vertices]{nodes}
\markindex{vertices}

\dummypage{5}
\markindex{vertices}

\dummypage{6}
\markindex{vertices}

\dummypage{7}
\markindex[vertices]{nodes}
\markindex{vertices}

\dummypage{9}
\markindex*[vertices]{Vertices} are
\markindex[vertices]{nodes}

\printindex
\end{document}


Remarks:

• \@ifstar, a LaTeX kernel macro, which checks for a following star.
• \@dblarg, also a LaTeX kernel macro; it duplicates the mandatory argument to the optional argument, if the optional argument is not given. It is used in \section, for example.
• This of course works, the only problem I guess is that the users must do the bookkeeping and it is quite labour-intesive. The answers is appreciated, but I was looking for a more automated solution. – Willem Van Onsem May 19 '14 at 4:48