Smile for the Camera: a new cybercrime short story ebook.

Gallery: glossaries performance

Image of sample document

Documents that use the glossaries package can take a long time to build. This page compares the performance of the various methods that can be used with just the base glossaries package and with the extension package glossaries-extra.

If you’re wondering what kind of document would require over 1,000 entries, the bib2gls user manual has over 4,500 entries. The user manual for glossaries-extra v1.49 has over 2,600 entries. Each command and option described in those documents is a glossary entry. If you click on a command it will take you to the relevant place in the document where that command is defined (a “standalone” definition), but you can also look up the command’s summary and syntax in the list in the back matter for a quick reminder or look up the location list in the index (glossaries). Similarly for the options.

The tests described here were compiled with glossaries.sty v4.49, glossaries-extra.sty v1.48 and bib2gls v3.0 (pending at the time of writing). Some of the examples may not work with earlier versions.

The test files were generated using Perl scripts. The first, mkentries, writes n instances of \newglossaryentry{entryidx}{name={word,description={sample idx}}} to STDOUT, where idx is an integer (0 to n−1) and word is a randomly generated word.

#!/usr/bin/perl -w

use strict;
use warnings;
use Data::Random::WordList;
use List::Util qw/shuffle/;

if ($#ARGV != 0)
{
   die "Syntax: $0 <number>\n";
}

my $count = $ARGV[0];

my $wl = new Data::Random::WordList( wordlist => '/usr/share/dict/words');

my @rand_words = shuffle($wl->get_words($count));

$wl->close();

for (my $idx = 0; $idx < $count; $idx++)
{
   my $word = $rand_words[$idx];

   $word=~s/([\\\&#%_\{\}\$])/\\$1/g;

   $word=~s/\^/\\textasciicircum /g;
   $word=~s/\^/\\textasciitilde /g;

   print "\\newglossaryentry{entry$idx}{name={$word},description={sample $idx}}\n";
}

1;

The test file entries-1000.tex was generated using:

mkentries 1000 > entries-1000.tex

The first five lines are:

\newglossaryentry{entry0}{name={silverback},description={sample 0}}
\newglossaryentry{entry1}{name={urbaneness},description={sample 1}}
\newglossaryentry{entry2}{name={twice-taken},description={sample 2}}
\newglossaryentry{entry3}{name={exoskeletal},description={sample 3}}
\newglossaryentry{entry4}{name={Dorsy},description={sample 4}}

There are three entries that start with a hyphen (which can be found with grep 'name={-' entries-1000.tex):

\newglossaryentry{entry447}{name={-hippus},description={sample 447}}
\newglossaryentry{entry606}{name={-el},description={sample 606}}
\newglossaryentry{entry730}{name={-fuge},description={sample 730}}

The file only contains ASCII characters. This was converted to .bib format for the bib2gls tests using:

convertgls2bib entries-1000.tex entries-1000.bib

The file entries-1000.bib starts with:

% Encoding: UTF-8
@entry{entry0,
  name = {silverback},
  description = {sample 0}
}

@entry{entry1,
  name = {urbaneness},
  description = {sample 1}
}

@entry{entry2,
  name = {twice-taken},
  description = {sample 2}
}

@entry{entry3,
  name = {exoskeletal},
  description = {sample 3}
}

@entry{entry4,
  name = {Dorsy},
  description = {sample 4}
}

The encoding line identifies the file as UTF-8, although it only contains ASCII characters. (This isn’t a problem as ASCII is a subset of Unicode.)

There’s a similar Perl script, mkabbreviations, to create random abbreviations:

#!/usr/bin/perl -w

use strict;
use warnings;
use Data::Random::WordList;
use List::Util qw/shuffle/;

if ($#ARGV != 0)
{
   die "Syntax: $0 <number>\n";
}

my $count = $ARGV[0];
  
my $wl = new Data::Random::WordList( wordlist => '/usr/share/dict/words');

my @rand_words = shuffle($wl->get_words(3*$count));

$wl->close();

my $wordidx = 0;

for (my $idx = 0; $idx < $count; $idx++)
{
   my $word1 = $rand_words[$wordidx++];
   my $word2 = $rand_words[$wordidx++];
   my $word3 = $rand_words[$wordidx++];

   my $word = "$word1 $word2 $word3";

   my $abbreviation = uc(substr $word1, 0, 1).uc(substr $word2, 0, 1).uc(substr $word3, 0, 1);

   $word=~s/([\\\&#%_\{\}\$])/\\$1/g;
   $abbreviation=~s/([\\\&#%_\{\}\$])/\\$1/g;

   $word=~s/\^/\\textasciicircum /g;
   $abbreviation=~s/\^/\\textasciicircum /g;
   $word=~s/\^/\\textasciitilde /g;
   $abbreviation=~s/\^/\\textasciitilde /g;

   print "\\newacronym{abbrv$idx}{$abbreviation}{$word}\n";
}

1;

The file acronyms-1000.tex was created using:

./mkabbreviations 1000 > acronyms-1000.tex

The file starts:

\newacronym{abbrv0}{CMO}{Cuyab mercurialism oversaturates}
\newacronym{abbrv1}{BAJ}{bemoaningly aburban jackassism}
\newacronym{abbrv2}{RHS}{rend horsts stormward}
\newacronym{abbrv3}{IFS}{intercommon foliocellosis scription}
\newacronym{abbrv4}{OCP}{otter Celanese powderize}

The file abbreviations-1000.tex is a copy of acronyms-1000.tex with \newacronym replaced with \newabbreviation. The file starts:

\newabbreviation{abbrv0}{CMO}{Cuyab mercurialism oversaturates}
\newabbreviation{abbrv1}{BAJ}{bemoaningly aburban jackassism}
\newabbreviation{abbrv2}{RHS}{rend horsts stormward}
\newabbreviation{abbrv3}{IFS}{intercommon foliocellosis scription}
\newabbreviation{abbrv4}{OCP}{otter Celanese powderize}

The file abbreviations-1000.tex was converted to abbreviations-1000.bib using:

convertgls2bib abbreviations-1000.tex abbreviations-1000.bib

The first few entries are:

% Encoding: UTF-8
@abbreviation{abbrv0,
  short = {CMO},
  long = {Cuyab mercurialism oversaturates}
}

@abbreviation{abbrv1,
  short = {BAJ},
  long = {bemoaningly aburban jackassism}
}

@abbreviation{abbrv2,
  short = {RHS},
  long = {rend horsts stormward}
}

@abbreviation{abbrv3,
  short = {IFS},
  long = {intercommon foliocellosis scription}
}

@abbreviation{abbrv4,
  short = {OCP},
  long = {otter Celanese powderize}
}

To test UTF-8 support, entries-1000.tex was copied and the first few entries were changed to words starting with UTF-8 characters. This file was saved as entries-utf8-1000.tex. The first few lines are:

\newglossaryentry{entry0}{name={Øresund},description={sample 0}}
\newglossaryentry{entry1}{name={Þríhyrningsvatn},description={sample 1}}
\newglossaryentry{entry2}{name={Ängelholm},description={sample 2}}
\newglossaryentry{entry3}{name={ætherial},description={sample 3}}
\newglossaryentry{entry4}{name={œsophagus},description={sample 4}}
\newglossaryentry{entry5}{name={Łobez},description={sample 5}}
\newglossaryentry{entry6}{name={Ćmielów},description={sample 6}}
\newglossaryentry{entry7}{name={Żelechów},description={sample 7}}
\newglossaryentry{entry8}{name={Ångström},description={sample 8}}

The remaining lines are unchanged. This file was converted to entries-utf8-1000.bib using:

convertgls2bib entries-utf8-1000.tex entries-utf8-1000.bib

For the symbol examples, the file greek.tex contains Greek symbols defined (indirectly) with \newglossaryentry. The first few lines provide some commands definitions:

\providecommand{\Beta}{B}
\providecommand{\Digamma}{F}
\providecommand{\Eta}{H}
\providecommand{\omicron}{o}
\providecommand{\Omicron}{O}
\providecommand{\Kappa}{K}
\providecommand{\mtx}[1]{\mathbf{#1}}

This provides math-greek commands missing from the LaTeX kernel (\Beta, \Omicron, etc) and also a semantic command to format symbols representing matrices (\mtx). You may prefer different definitions for these commands, such as

\providecommand{\Kappa}{\mathrm{K}}
\providecommand{\mtx}[1]{\pmb{#1}}

Such minor font modifications are irrelevant to the tests performed here (as long as the changes are within these custom commands and aren’t added to the name field). The glossaries-extra-bib2gls package (provided with glossaries-extra v1.27+ and automatically loaded by the record option) provides the missing math-greek commands using \providecommand, so those definitions can be used instead if that package has been loaded.

There’s also a convenient command \newsymbol{label}{symbol}{description}{topic} used to define each symbol.

\providecommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{name={#2},description={#3},user1={#4}}%
}

For example:

\newsymbol{alpha}{\ensuremath{\alpha}}{angular acceleration}{physics}

\newsymbol{beta}{\ensuremath{\beta}}{thermodynamic beta}{statistical mechanics}

\newsymbol{Beta}{\ensuremath{\Beta(x,y)}}{Euler beta function}{functions}

The \sortart command, defined as

\providecommand{\sortart}[2]{#1 #2}

is used in descriptions that start with an article (‘the’, ‘a’, ‘an’). For example:

\newsymbol{lambda}{\ensuremath{\lambda}}{\sortart{an}{eigenvalue}}{linear algebra}

The equivalent bib2gls file can be obtained using:

convertgls2bib greek.tex greek.bib

This creates the file greek.bib containing @entry definitions (convertgls2bib is able to parse the provided definition of \newsymbol). This just needs to have the custom commands added in @preamble, but I made some extra modifications for convenience: the user1 field was converted to a custom topic field using a global search and replace (s/user1/topic), and all instances of @entry were replaced with @symbol (s/@entry/@symbol).

After these edits, the file greek.bib starts with:

% Encoding: UTF-8

@preamble{"\providecommand{\Beta}{B}
\providecommand{\Digamma}{F}
\providecommand{\Eta}{H}
\providecommand{\omicron}{o}
\providecommand{\Omicron}{O}
\providecommand{\mtx}[1]{\mathbf{#1}}
\providecommand{\sortart}[2]{#1 #2}"}

@symbol{alpha,
  topic = {physics},
  name = {\ensuremath{\alpha}},
  description = {angular acceleration}
}

@symbol{beta,
  topic = {statistical mechanics},
  name = {\ensuremath{\beta}},
  description = {thermodynamic beta}
}

@symbol{Beta,
  topic = {functions},
  name = {\ensuremath{\Beta(x,y)}},
  description = {Euler beta function}
}

The custom topic field will be ignored by bib2gls unless defined or aliased. The math-greek commands may be omitted from @preamble when the document is compiled with glossaries-extra v1.27+ as they’re provided by glossaries-extra-bib2gls. Since \providecommand is used, these definitions will be ignored if the example documents here are built with glossaries-extra v1.27+.

The cross-reference examples use the file xrentries.tex which was created by a slightly modified Perl script (mkxrentries) adapted from mkentries:

#!/usr/bin/perl -w

use strict;
use warnings;
use Data::Random::WordList;
use List::Util qw/shuffle/;

if ($#ARGV != 0)
{
   die "Syntax: $0 <number>\n";
}

my $count = $ARGV[0];
  
my $wl = new Data::Random::WordList( wordlist => '/usr/share/dict/words');

my @rand_words = shuffle($wl->get_words($count));

$wl->close();

for (my $idx = 0; $idx < $count; $idx++)
{
   my $word = $rand_words[$idx];

   $word=~s/([\\\&#%_\{\}\$])/\\$1/g;

   $word=~s/\^/\\textasciicircum /g;
   $word=~s/\^/\\textasciitilde /g;

   my $desc = "sample $idx";

   if ($idx%4 == 3)
   {
      my $rand_idx = int(rand($idx));

      $desc .= " ref \\gls{xrentry$rand_idx}";
   }

   print "\\newglossaryentry{xrentry$idx}{name={$word},description={$desc}}\n";
}

1;
This adds a cross-reference in the description field every fourth entry. The file xrentries.tex was then created with:
mkxrentries 6000 > xrentries.tex
Note that I haven’t used the see field, as this would automatically trigger indexing and is therefore inappropriate for large files that contain entries that may not be required (unless you are using bib2gls, which has a different way of dealing with the cross-reference fields).

The bib2gls cross-reference examples require the corresponding file xrentries.bib which was created with:

convertgls2bib xrentries.tex xrentries.bib

Each document (that can be fully compiled) has an associated bash script (called builddoc1 etc) to perform the complete build so that the process can be timed using the GNU time command. For example, the script builddoc1a contains:

#!/usr/bin/bash

pdflatex -jobname test-doc1a test-doc1
makeglossaries-lite test-doc1a
pdflatex -jobname test-doc1a test-doc1

(The documents that can’t compile without error aren’t timed.) For simplicity, the build processes listed in each test below omits -jobname and the hash bang line.

The bash script that times all the test documents is simply:

#!/usr/bin/bash

function build
{
  filename=$1

  /usr/bin/time -f "$filename:\t%e\t%E" --append --output=$logfile $filename  || exit $?
}

logfile='runtest.log'

rm -f $logfile
touch $logfile

bib2gls --version || exit $?
xindy --version || exit $?

rm -f test-*.{pdf,aux,log,ist,xdy,gls,glo,glg,acr,acn,alg,gls-abr,glo-abr,glg-abr,glstex}

for file in builddoc*; do
 [ -e "$file" ] || continue
 build $file
done

This creates a file called runtest.log that contains all the build times shown in this page. (The tests were run on a 64 bit Linux machine with TeX Live 2021.) The temporary files are all removed (if present) before running the tests, so the build times listed here are for the first complete build. If a document is modified, the subsequent build time may change as information from the temporary files created by the previous build is now available on the first LaTeX call of the new build.

The initial bib2gls --version call ensures that bib2gls and Java are correctly installed before running the tests. Additionally, the first instance of a Java application always takes slightly longer than subsequent calls, which would cause unpredictable results for the first bib2gls test depending on whether the tests were run before or after any other document builds performed since logging in.

Similarly the xindy --version call ensures that xindy and Perl are correctly installed. (makeindex doesn’t have an equivalent switch, as far as I can tell, but it’s a compiled application that should be present in all modern TeX distributions.)

1. Alphabetical Order (All Selected)

The first set of tests order the entries alphabetically. All entries are selected (using \glsaddall or, for the bib2gls examples, selection=all). The build times are summarised in Table 1. Tests 1.1, 1.2, 1.3 and 1.4 compare calling makeindex implicitly via makeglossaries (Test 1.1), makeglossaries-lite (Test 1.2) and the shell escape (Test 1.3), and calling makeindex explicitly (Test 1.4). Similarly, Tests 1.5, 1.6 and 1.7 compare calling xindy implicitly via makeglossaries (Test 1.5) and makeglossaries-lite (Test 1.6) and explicitly (Test 1.7). The remaining tests involving makeindex or xindy just use the makeglossaries Perl script, as that’s the recommended method and the time difference is negligible.

The glossaries-extra extension package increases the build time fractionally, but it’s so small that it can be outweighed by minor fluctuations in processing times if the tests are rerun.

The fastest method is with makeindex. For the makeindex methods (using makeglossaries), the document build time is approximately 3 seconds for regular entries (entries-1000.tex; Test 1.1, 0:02.91), 3.5 seconds for regular entries with glossaries-extra (entries-1000.tex; Test 1.9, 0:03.55), 4 seconds–5 seconds for acronyms (acronyms-1000.tex; Test 1.13, 0:04.91, and Test 1.14, 0:04.21), and 7 seconds for acronyms with glossaries-extra (acronyms-1000.tex; Test 1.19, 0:07.30) and 6.5 seconds for abbreviations with glossaries-extra (abbreviations-1000.tex; Test 1.20, 0:06.62).

The second fastest method is with bib2gls (which requires glossaries-extra.sty) taking approximately 4 seconds for the regular entries (entries-1000.bib; Test 1.12, 0:03.79) and approximately 5 seconds for the abbreviations (abbreviations-1000.bib; Test 1.23, 0:05.24).

The third fastest method is using xindy taking approximately 4 seconds for the regular entries (entries-1000.tex; Test 1.5, 0:04.33), 5 seconds for regular entries with glossaries-extra (entries-1000.tex; Test 1.10, 0:05.04), 5.5 seconds for acronyms (acronyms-1000.tex; Test 1.16, 0:05.53), and 8 seconds for abbreviations with glossaries-extra (abbreviations-1000.tex; Test 1.21, 0:07.81).

There isn’t a great deal of difference in the build times for makeindex, xindy and bib2gls (just a matter of seconds). The slowest method by far is using TeX to sort and collate (\makenoidxglossaries and \printnoidxglossary), which takes approximately 11 minutes (Test 1.8, 11:04.64, and Test 1.11, 11:04.58).

Note that with just the base glossaries.sty package, it’s marginally faster to use the newer acronym implementation triggered with \setacronymstyle than to use the older acronym implementation (where \setacronymstyle is omitted), except when using TeX to sort and collate. With the glossaries-extra package it’s faster to use \newabbreviation than \newacronym (which is redefined to internally use \newabbreviation).

Table 1: Summary (Alphabetical Order, All Selected)
Test Build time (minutes:​seconds) PDF
glossaries.sty, \newglossaryentry and makeindex
1.1 makeglossaries (makeindex): 1000 entries 0:02.91 (PDF)
1.2 makeglossaries-lite (makeindex): 1000 entries 0:02.85 (PDF)
1.3 automake (makeindex): 1000 entries 0:02.93 (PDF)
1.4 makeindex: 1000 entries 0:02.83 (PDF)
glossaries.sty, \newglossaryentry and xindy
1.5 makeglossaries (xindy): 1000 entries 0:04.33 (PDF)
1.6 makeglossaries-lite (xindy): 1000 entries 0:04.34 (PDF)
1.7 xindy: 1000 entries 0:04.36 (PDF)
glossaries.sty, \newglossaryentry and no external tool
1.8 \makenoidxglossaries: 1000 entries 11:04.64 (PDF)
glossaries-extra.sty and \newglossaryentry or @entry
1.9 glossaries-extra.sty and makeglossaries (makeindex): 1000 entries 0:03.55 (PDF)
1.10 glossaries-extra.sty and makeglossaries (xindy): 1000 entries 0:05.04 (PDF)
1.11 glossaries-extra and \makenoidxglossaries: 1000 entries 11:04.58 (PDF)
1.12 glossaries-extra and bib2gls: 1000 entries 0:03.79 (PDF)
glossaries.sty and \newacronym
1.13 makeglossaries (makeindex): 1000 acronyms 0:04.91 (PDF)
1.14 \setacronymstyle and makeglossaries (makeindex): 1000 acronyms 0:04.21 (PDF)
1.15 makeglossaries (xindy): 1000 acronyms 0:06.23 (PDF)
1.16 \setacronymstyle and makeglossaries (xindy): 1000 acronyms 0:05.53 (PDF)
1.17 \makenoidxglossaries: 1000 acronyms 10:45.19 (PDF)
1.18 \setacronymstyle and \makenoidxglossaries: 1000 acronyms 10:45.80 (PDF)
glossaries-extra.sty and \newacronym or \newabbreviation or @abbreviation
1.19 glossaries-extra.sty and makeglossaries (makeindex): 1000 acronyms 0:07.30 (PDF)
1.20 glossaries-extra.sty and makeglossaries (makeindex): 1000 abbreviations 0:06.62 (PDF)
1.21 glossaries-extra.sty and makeglossaries (xindy): 1000 abbreviations 0:07.81 (PDF)
1.22 glossaries-extra.sty and \makenoidxglossaries: 1000 abbreviations 10:49.93 (PDF)
1.23 bib2gls: 1000 abbreviations 0:05.24 (PDF)

1.1 makeglossaries (makeindex): 1000 entries

This example uses the test file entries-1000.tex. The document code is:

\documentclass{article}

\usepackage{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build (builddoc1) is:

pdflatex test-doc1
makeglossaries test-doc1
pdflatex test-doc1

The total build time was 0:02.91 (PDF).

1.2 makeglossaries-lite (makeindex): 1000 entries

This example uses the same document as in Test 1.1 but the build process uses the makeglossaries-lite Lua script instead of the makeglossaries Perl script:

pdflatex test-doc1
makeglossaries-lite test-doc1
pdflatex test-doc1

The total build time was 0:02.85 (PDF).

1.3 automake (makeindex): 1000 entries

This example uses the automake option to run makeindex through the shell escape.

\documentclass{article}

\usepackage[automake]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is just

pdflatex test-doc1c
pdflatex test-doc1c

The total build time was 0:02.93 (PDF).

1.4 makeindex: 1000 entries

This example uses the same document as in Test 1.1 but the build process calls makeindex directly:

pdflatex test-doc1
makeindex -s test-doc1.ist -t test-doc1.glg -o test-doc1.gls test-doc1.glo
pdflatex test-doc1

The total build time was 0:02.83 (PDF).

1.5 makeglossaries (xindy): 1000 entries

This example uses xindy instead. There’s just a minor modification to the document code (the package option xindy):

\documentclass{article}

\usepackage[xindy]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process uses the makeglossaries Perl script to call xindy:

pdflatex test-doc2
makeglossaries test-doc2
pdflatex test-doc2

The total build time was 0:04.33 (PDF).

1.6 makeglossaries-lite (xindy): 1000 entries

This example uses the same document as in Test 1.5 but the build process uses the makeglossaries-lite Lua script instead of the makeglossaries Perl script:

pdflatex test-doc2
makeglossaries-lite test-doc2
pdflatex test-doc2

The total build time was 0:04.34 (PDF).

1.7 xindy: 1000 entries

This example uses the same document as in Test 1.5 but the build process calls xindy directly:

pdflatex test-doc2
xindy -L english -I xindy -M test-doc2 -t test-doc2.glg -o test-doc2.gls test-doc2.glo
pdflatex test-doc2

The total build time was 0:04.36 (PDF).

1.8 \makenoidxglossaries: 1000 entries

This example uses TeX to sort and collate. The document code is now:

\documentclass{article}

\usepackage{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process does require any external tools:

pdflatex test-doc3
pdflatex test-doc3

The total build time was 11:04.64 (PDF).

1.9 glossaries-extra.sty and makeglossaries (makeindex): 1000 entries

This example is like Test 1.1 but loads the extension package glossaries-extra. The extra build time comes from the additional code provided by the extension package. (Remember that glossaries-extra automatically loads glossaries, so there’s the load time from glossaries plus the load time from glossaries-extra and the additional time to process the extra hooks etc.)

The document code only needs a minor modification (the required package):

\documentclass{article}

\usepackage{glossaries-extra}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build uses makeglossaries:

pdflatex test-doc4
makeglossaries test-doc4
pdflatex test-doc4

The total build time was 0:03.55 (PDF). Compared with the build time of 0:02.91 from Test 1.1, the extra resources from loading glossaries-extra.sty add less than a second to the total document build time.

1.10 glossaries-extra.sty and makeglossaries (xindy): 1000 entries

This example uses xindy instead. There’s just a minor modification to the document code (the package option xindy):

\documentclass{article}

\usepackage[xindy]{glossaries-extra}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process uses the makeglossaries Perl script to call xindy:

pdflatex test-doc5
makeglossaries test-doc5
pdflatex test-doc5

The total build time was 0:05.04 (PDF).

1.11 glossaries-extra.sty and \makenoidxglossaries: 1000 entries

This example uses TeX to sort and collate. The document code is now:

\documentclass{article}

\usepackage{glossaries-extra}

\makenoidxglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process does require any external tools:

pdflatex test-doc6
pdflatex test-doc6

The total build time was 11:04.58 (PDF).

1.12 glossaries-extra.sty and bib2gls: 1000 entries

This example uses bib2gls, which can only be used with the extension package glossaries-extra. The document is slightly different:

\documentclass{article}

\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000},selection=all]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc7
bib2gls test-doc7
pdflatex test-doc7

The total build time was 0:03.79 (PDF). Unlike the previous examples, the list has no locations as there are no records. With the other methods, \glsaddall indexes every defined entry (without generating any text), so there’s a corresponding location. This command doesn’t work with bib2gls, so selection=all is used instead, which simply instructs bib2gls to select all entries, even if they haven’t been recorded (indexed) in the document.

1.13 makeglossaries (makeindex): 1000 acronyms

This example uses the test file acronyms-1000.tex. The document code is:

\documentclass{article}

\usepackage{glossaries}

\makeglossaries
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc8
makeglossaries test-doc8
pdflatex test-doc8

The total build time was 0:04.91 (PDF).

1.14 \setacronymstyle and makeglossaries (makeindex): 1000 acronyms

This is a minor modification to the previous test that sets the long-short style. This switches to the newer abbreviation code in the base package (but this isn’t the same as the abbreviation code provided by glossaries-extra).

\documentclass{article}

\usepackage{glossaries}

\makeglossaries

\setacronymstyle{long-short}
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc8a
makeglossaries test-doc8a
pdflatex test-doc8a

The total build time was 0:04.21 (PDF).

1.15 makeglossaries (xindy): 1000 acronyms

This example is like Test 1.13 but uses xindy instead of makeindex:

\documentclass{article}

\usepackage[xindy]{glossaries}

\makeglossaries
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc9
makeglossaries test-doc9
pdflatex test-doc9

The total build time was 0:06.23 (PDF).

1.16 \setacronymstyle and makeglossaries (xindy): 1000 acronyms

This example is like Test 1.14 but uses xindy instead of makeindex:

\documentclass{article}

\usepackage[xindy]{glossaries}

\makeglossaries

\setacronymstyle{long-short}
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc9a
makeglossaries test-doc9a
pdflatex test-doc9a

The total build time was 0:05.53 (PDF).

1.17 \makenoidxglossaries: 1000 acronyms

This example is like Test 1.13 but uses TeX to sort and collate:

\documentclass{article}

\usepackage{glossaries}

\makenoidxglossaries
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The document build is:

pdflatex test-doc10
pdflatex test-doc10

The total build time was 10:45.19 (PDF).

1.18 \setacronymstyle and \makenoidxglossaries: 1000 acronyms

This example is like Test 1.17 but uses \setacronymstyle:

\documentclass{article}

\usepackage{glossaries}

\makenoidxglossaries

\setacronymstyle{long-short}
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The document build is:

pdflatex test-doc10a
pdflatex test-doc10a

The total build time was 10:45.80 (PDF).

1.19 glossaries-extra.sty and makeglossaries (makeindex): 1000 acronyms

This uses glossaries-extra and acronyms-1000.tex. Since the abbreviations are defined using \newacronym the style needs to be set with \setabbreviationstyle[acronym]{long-short}:

\documentclass{article}

\usepackage{glossaries-extra}

\makeglossaries

\setabbreviationstyle[acronym]{long-short}
\loadglsentries{acronyms-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc11
makeglossaries test-doc11
pdflatex test-doc11

The total build time was 0:07.30 (PDF).

1.20 glossaries-extra.sty and makeglossaries (makeindex): 1000 abbreviations

This uses glossaries-extra and abbreviations-1000.tex. Since the terms are now defined using \newabbreviation the style doesn’t need to be set as the default is long-short:

\documentclass{article}

\usepackage{glossaries-extra}

\makeglossaries

\loadglsentries{abbreviations-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc12
makeglossaries test-doc12
pdflatex test-doc12

The total build time was 0:06.62 (PDF). This is fractionally shorter than the previous test (0:07.30), which used \newacronym rather than \newabbreviation. (Remember that glossaries-extra.sty redefines \newacronym to internally use \newabbreviation, so there’s slightly more code to process with \newacronym than directly using \newabbreviation.) The remaining glossaries-extra examples use \newabbreviation or (with bib2gls) @abbreviation.

1.21 glossaries-extra.sty and makeglossaries (xindy): 1000 abbreviations

This example is like Test 1.20 but uses xindy instead of makeindex:

\documentclass{article}

\usepackage[xindy]{glossaries-extra}

\makeglossaries

\loadglsentries{abbreviations-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc13
makeglossaries test-doc13
pdflatex test-doc13

The total build time was 0:07.81 (PDF).

1.22 glossaries-extra.sty and \makenoidxglossaries: 1000 abbreviations

This example is like Test 1.20 but uses TeX to sort and collate:

\documentclass{article}

\usepackage{glossaries-extra}

\makenoidxglossaries

\loadglsentries{abbreviations-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The document build is:

pdflatex test-doc14
pdflatex test-doc14

The total build time was 10:49.93 (PDF).

1.23 bib2gls: 1000 abbreviations

This example is like Test 1.20 but uses bib2gls and abbreviations-1000.bib:

\documentclass{article}

\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={abbreviations-1000},selection=all]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc15
bib2gls test-doc15
pdflatex test-doc15

The total build time was 0:05.24 (PDF).

2. Groups

These tests are much like the above but they compare the build time associated with group formation in the glossary. To simplify the comparisons, only the regular entries (ASCII entries-1000.tex or entries-1000.bib and UTF-8 entries-utf8-1000.tex or entries-utf8-1000.bib) are compared with the index verses the indexgroup glossary styles. The other style packages that are normally loaded (such as glossary-list.sty) are skipped, which shaves a few milliseconds off the document build. Only glossary-tree.sty is required to provide the index and indexgroup styles, but with bib2gls (which requires glossaries-extra.sty) the glossaries-extra-stylemods package is also loaded (via the stylemods option).

The index style doesn’t show group headings, but it still visually separates the groups unless the nogroupskip option is used. With bib2gls, use nogroupskip in the argument of \printunsrtglossary if you have multiple glossaries where only some of them use this option, otherwise call bib2gls with --nogroup (which is the default if --group or -g is omitted) if grouping should be omitted for all glossaries.

Note that makeindex isn’t designed for UTF-8 and the document in Test 2.5 fails to compile as a result. For the ASCII tests, makeindex is still the fastest with a build time of approximately 3 seconds.

The second fastest method is bib2gls with a build time of approximately 4 seconds.

The third fastest method is xindy with a build time of approximately 4 seconds.

The slowest method is again using TeX to sort (\makenoidxglossaries) with a build time of around 11 minutes.

Overall, the difference in build time introduced by adding the group skips and group headings is insignificant compared to the total build.

Table 2: Summary (index vs indexgroup)
Test Build time (minutes:​seconds) PDF
glossaries.sty and makeindex
2.1 index, nogroupskip and makeglossaries (makeindex): 1000 ASCII entries 0:02.81 (PDF)
2.2 index and makeglossaries (makeindex): 1000 ASCII entries 0:02.79 (PDF)
2.3 indexgroup and makeglossaries (makeindex): 1000 ASCII entries 0:02.84 (PDF)
2.4 index and makeglossaries (makeindex): 1000 UTF-8 entries 0:02.83 (PDF)
2.5 indexgroup and makeglossaries (makeindex): 1000 UTF-8 entries Failed
glossaries.sty and xindy
2.6 index, nogroupskip and makeglossaries (xindy): 1000 ASCII entries 0:04.31 (PDF)
2.7 index and makeglossaries (xindy): 1000 ASCII entries 0:04.30 (PDF)
2.8 indexgroup and makeglossaries (xindy): 1000 ASCII entries 0:04.28 (PDF)
2.9 index and makeglossaries (xindy): 1000 UTF-8 entries 0:04.33 (PDF)
2.10 indexgroup and makeglossaries (xindy): 1000 UTF-8 entries 0:04.32 (PDF)
glossaries.sty and \makenoidxglossaries
2.11 index, nogroupskip and \makenoidxglossaries: 1000 ASCII entries 11:04.81 (PDF)
2.12 index and \makenoidxglossaries: 1000 ASCII entries 11:01.93 (PDF)
2.13 indexgroup and \makenoidxglossaries: 1000 ASCII entries 11:02.35 (PDF)
2.14 index and \makenoidxglossaries: 1000 UTF-8 entries 11:10.91 (PDF)
2.15 indexgroup and \makenoidxglossaries: 1000 UTF-8 entries 11:07.92 (PDF)
glossaries-extra.sty and bib2gls
2.16 index and bib2gls --nogroup: 1000 ASCII entries 0:03.60 (PDF)
2.17 index and bib2gls --group: 1000 ASCII entries 0:03.75 (PDF)
2.18 indexgroup and bib2gls --group: 1000 ASCII entries 0:03.77 (PDF)
2.19 index and bib2gls --group: 1000 UTF-8 entries 0:03.89 (PDF)
2.20 indexgroup and bib2gls --group: 1000 UTF-8 entries 0:03.80 (PDF)

2.1 index style, nogroupskip and makeglossaries (makeindex): 1000 ASCII entries

This test is like Test 1.1 but it sets the index style, implements nogroupskip and omits loading the unrequired style packages:


The document build is:

pdflatex test-doc16a
makeglossaries test-doc16a
pdflatex test-doc16a

The total build time was 0:02.81 (PDF). The entries starting with a hyphen are listed first followed immediately by the ‘A’ group:

-el sample 606. 1
-fuge sample 730. 1
-hippus sample 447. 1
Abassin sample 997. 1
abesse sample 347. 1

There are no gaps between the letter groups.

2.2 index style and makeglossaries (makeindex): 1000 ASCII entries

This test is like Test 2.1 but it doesn’t use nogroupskip:

\documentclass{article}

\usepackage[nolong,nosuper,nolist,style=index]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc16
makeglossaries test-doc16
pdflatex test-doc16

The total build time was 0:02.79 (PDF). The entries starting with a hyphen are listed first followed by a vertical gap separating them from the ‘A’ letter group:

-el sample 606. 1
-fuge sample 730. 1
-hippus sample 447. 1

Abassin sample 997. 1
abesse sample 347. 1

2.3 indexgroup style and makeglossaries (makeindex): 1000 entries

This test is like Test 2.2 but it uses the indexgroup style.

\documentclass{article}

\usepackage[nolong,nosuper,nolist,style=indexgroup]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc17
makeglossaries test-doc17
pdflatex test-doc17

The total build time was 0:02.84 (PDF). The entries starting with a hyphen have the group title ‘Symbols’. The remaining letter groups all have the corresponding upper case letter as the title.

2.4 index style and makeglossaries (makeindex): 1000 UTF-8 entries

This test is like Test 2.2 but it uses the UTF-8 test file entries-utf8-1000.tex:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[nolong,nosuper,nolist,style=index]{glossaries}

\makeglossaries
\loadglsentries{entries-utf8-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

Note that the document requires UTF-8 support. The document build is:

pdflatex test-doc18
makeglossaries test-doc18
pdflatex test-doc18

The total build time was 0:02.83 (PDF). As with the previous two tests, the words starting with a hyphen are listed at the start. The words starting with extended characters are in three groups after ‘Z’:

Ängelholm sample 2. 1
Ångström sample 8. 1
Øresund sample 0. 1
Þríhyrningsvatn sample 1. 1
ætherial sample 3. 1

Ćmielów sample 6. 1

Łobez sample 5. 1
œsophagus sample 4. 1
Żelechów sample 7. 1

This is due to makeindex not supporting UTF-8. The sorting is performed according to the character octets. Ä (0xC3 0x84), Å (0xC3 0x85), Ø (0xC3 0x98), Þ (0xC3 0x9E) and æ (0xC3 0xA6) all start with the octet 0xC3, which makeindex treats as the letter group. Similarly Ć (0xC4 0x86) is treated as belonging to the 0xC4 letter group, and Ł (0xC5 0x81), œ (0xC5 0x93) and Ż (0xC5 0xBB) are treated as belonging to the 0xC5 letter group.

makeindex is only appropriate for ASCII sort keys. While it may be able to handle Latin-1, it doesn’t recognise alphabets (which vary according to language).

2.5 indexgroup style and makeglossaries (makeindex): 1000 UTF-8 entries

This test is like Test 2.4 but it uses the indexgroup style instead:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[nolong,nosuper,nolist,style=indexgroup]{glossaries}

\makeglossaries
\loadglsentries{entries-utf8-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build in theory is:

pdflatex test-doc19
makeglossaries test-doc19
pdflatex test-doc19

The build fails on the second pdflatex call with the error:

! Missing \endcsname inserted.
<to be read again> 
                   \protect 
l.2012 \glsgroupheading{�}
                          \relax \glsresetentrylist %

This is due to makeindex treating a single UTF-8 character as two octets. The first octet is written to the group heading command, which LaTeX can’t parse as it’s invalid. (The inputenc package makes this octet active as part of its UTF-8 support. It expects the second octet, which is used as an argument.) Even if the document was modified to use fontspec and XeLaTeX or LuaLaTeX the build will still fail as the code created by makeindex is corrupt. (It’s still corrupt in the previous test, but it’s not noticed by the non-Unicode LaTeX engine.)

2.6 index style and makeglossaries (xindy): 1000 ASCII entries

This test is like Test 2.1 but it uses xindy:

\documentclass{article}

\usepackage[xindy,nolong,nosuper,nolist,style=index,nogroupskip]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process is:

pdflatex test-doc20a
makeglossaries test-doc20a
pdflatex test-doc20a

The total build time was 0:04.31 (PDF). The sort method ignores hyphens, so ‘-el’ is listed between ‘efs’ and ‘Elaeis’, ‘-fuge’ is listed between ‘frutage’ and ‘full-roed’, and ‘-hippus’ is listed between ‘hinderers’ and ‘hirst’.

2.7 index style and makeglossaries (xindy): 1000 ASCII entries

This test is like Test 2.2 but it uses xindy:

\documentclass{article}

\usepackage[xindy,nolong,nosuper,nolist,style=index]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process is:

pdflatex test-doc20
makeglossaries test-doc20
pdflatex test-doc20

The total build time was 0:04.30 (PDF). The ordering is the same as the previous test but there are vertical gaps between the letter groups.

2.8 indexgroup style and makeglossaries (xindy): 1000 ASCII entries

This test is like Test 2.7 but it uses the indexgroup style instead:

\documentclass{article}

\usepackage[xindy,nolong,nosuper,nolist,style=indexgroup]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process is:

pdflatex test-doc21
makeglossaries test-doc21
pdflatex test-doc21

The total build time was 0:04.28. (PDF). Again the hyphens are ignored during the sorting. There are only alphabetical letter groups (no symbol group), with each group headed by the corresponding upper case letter.

2.9 index style and makeglossaries (xindy): 1000 UTF-8 entries

This test is like Test 2.7 but it uses the UTF-8 file entries-utf8-1000.tex:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[xindy,nolong,nosuper,nolist,style=index]{glossaries}

\makeglossaries
\loadglsentries{entries-utf8-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process is:

pdflatex test-doc22
makeglossaries test-doc22
pdflatex test-doc22

The total build time was 0:04.33 (PDF). This performs much better than makeindex. The document doesn’t use any language packages, so makeglossaries calls xindy using the options:

xindy -L english -C utf8 -I xindy -M "test-doc22" -t "test-doc22.glg" -o "test-doc22.gls" "test-doc22.glo"

This doesn’t recognise the characters Ć, Ł and Ż as letters, according to xindy’s English rule, so the words starting with these characters are placed at the start, before the ‘A’ letter group:

Ćmielów sample 6. 1
Łobez sample 5. 1
Żelechów sample 7. 1

The thorn (Þ) letter group is placed after ‘Z’ on the last page. The entries starting with Ä and Å are placed in the ‘O’ letter group:

obia sample 743. 1
obliger sample 144. 1
Ängelholm sample 2. 1
obnounce sample 864. 1
Ångström sample 8. 1
ochidore sample 204. 1
œsophagus sample 4. 1
Øresund sample 0. 1
of-fact sample 899. 1
ogenetic sample 261. 1

These characters typically don’t occur in English words, but proper names like Ängelholm and Ångström would normally be placed in the ‘A’ letter group for documents written in English. A different ordering is obtained with different language modules. For example:

xindy -L general -C utf8 -I xindy -M "test-doc22" -t "test-doc22.glg" -o "test-doc22.gls" "test-doc22.glo"
or
xindy -L swedish -C utf8 -I xindy -M "test-doc22" -t "test-doc22.glg" -o "test-doc22.gls" "test-doc22.glo"

2.10 indexgroup style and makeglossaries (xindy): 1000 UTF-8 entries

This test is like Test 2.9 but it uses the indexgroup style:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[xindy,nolong,nosuper,nolist,style=indexgroup]{glossaries}

\makeglossaries
\loadglsentries{entries-utf8-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The build process is:

pdflatex test-doc23
makeglossaries test-doc23
pdflatex test-doc23

The total build time was 0:04.32 (PDF). The unrecognised characters Ć, Ł and Ż are in the group headed ‘default’, but the thorn (Þ) letter group is correctly headed.

2.11 index style, nogroupskip and \makenoidxglossaries: 1000 ASCII entries

This test is like Test 2.1 but it uses TeX to perform the sorting:

\documentclass{article}

\usepackage[nolong,nosuper,nolist,style=index,nogroupskip]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process is:

pdflatex test-doc24a
pdflatex test-doc24a

The total build time was 11:04.81 (PDF). The glossary starts with the entries that have an initial hyphen followed by the ‘A’ letter group (with no gap):

-el sample 606. 1
-fuge sample 730. 1
-hippus sample 447. 1
Abassin sample 997. 1
abesse sample 347. 1

2.12 index style and \makenoidxglossaries: 1000 ASCII entries

This test is like Test 2.2 but it uses TeX to perform the sorting:

\documentclass{article}

\usepackage[nolong,nosuper,nolist,style=index]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process is:

pdflatex test-doc24
pdflatex test-doc24

The total build time was 11:01.93 (PDF). The glossary starts with the entries that have an initial hyphen followed by a vertical gap separating them from the ‘A’ letter group:

-el sample 606. 1
-fuge sample 730. 1
-hippus sample 447. 1

Abassin sample 997. 1
abesse sample 347. 1

2.13 indexgroup style and \makenoidxglossaries: 1000 ASCII entries

This test is like Test 2.12 but it uses the indexgroup style:

\documentclass{article}

\usepackage[nolong,nosuper,nolist,style=indexgroup]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process is:

pdflatex test-doc25
pdflatex test-doc25

The total build time was 11:02.35 (PDF). The entries with the initial hyphen have the group label ‘Symbols’.

2.14 index style and \makenoidxglossaries: 1000 UTF-8 entries

This test is like Test 2.12 but it uses the UTF-8 test file entries-utf8-1000.tex:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[nolong,nosuper,nolist,style=index]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-utf8-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process is:

pdflatex test-doc26
pdflatex test-doc26

The total build time was 11:10.91 (PDF). The accented characters were sorted according to the unaccented version, so ‘Ängelholm’ is listed between ‘anesthetizing’ and ‘angelologic’. The æ ligature is treated as ‘ae’ and the œ ligature is treated as ‘oe’, so ‘ætherial’ is listed between ‘aeropulse’ and ‘aftercrop’, and ‘œsophagus’ is listed between ‘ochidore’ and ‘of-fact’. This method is not language-sensitive.

2.15 indexgroup style and \makenoidxglossaries: 1000 UTF-8 entries

This test is like Test 2.14 but it uses the indexgroup style:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[nolong,nosuper,nolist,style=indexgroup]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-utf8-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The build process is:

pdflatex test-doc27
pdflatex test-doc27

The total build time was 11:07.92 (PDF). The letter group headings are as for Test 2.13.

2.16 index style and bib2gls --nogroup: 1000 ASCII entries

This example is like Test 2.2 but it uses bib2gls, which means that glossaries-extra.sty is required. The document suppresses the loading of all style packages with nostyles and then uses stylemods=tree to load glossary-tree.sty (which provides the tree-like styles, including index and indexgroup) via the glossaries-extra-stylemods package, which additionally patches the styles. Since bib2gls is being used, the test file is entries-1000.bib:

\documentclass{article}

\usepackage[record,nostyles,stylemods=tree,style=index]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000},selection=all]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The build process is:

pdflatex test-doc28
bib2gls test-doc28
pdflatex test-doc28

The total build time was 0:03.60 (PDF). Unlike the earlier tests with index, which had an untitled gap between letter groups, this document doesn’t show any visible separation between letter groups, even though the default nogroupskip=false is on, because bib2gls is called without the --group (or -g) switch.

As with xindy the hyphens are ignored when sorting, so again ‘-el’ is listed between ‘efs’ and ‘Elaeis’, ‘-fuge’ is listed between ‘frutage’ and ‘full-roed’, and ‘-hippus’ is listed between ‘hinderers’ and ‘hirst’.

2.17 index style and bib2gls --group: 1000 ASCII entries

This uses the same document as Test 2.16 but calls bib2gls with --group:

pdflatex test-doc28
bib2gls --group test-doc28
pdflatex test-doc28

The total build time was 0:03.75 (PDF). The document now has a vertical gap (but no title) between letter groups.

2.18 indexgroup style and bib2gls --group: 1000 ASCII entries

This is like Test 2.17 but it uses the indexgroup style:

\documentclass{article}

\usepackage[record,nostyles,stylemods=tree,style=indexgroup]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000},selection=all]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc29
bib2gls --group test-doc29
pdflatex test-doc29

The total build time was 0:03.77 (PDF). Each group is now headed with the corresponding upper case letter.

2.19 index style and bib2gls --group: 1000 UTF-8 entries

This is like Test 2.17 but it uses the UTF-8 test file entries-utf8-1000.bib:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[record,nostyles,stylemods=tree,style=index]{glossaries-extra}

\GlsXtrLoadResources[src={entries-utf8-1000},selection=all]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc30
bib2gls --group test-doc30
pdflatex test-doc30

The total build time was 0:03.89 (PDF). Since no sort option has been set in \GlsXtrLoadResources and no language package has been loaded, bib2gls uses my default locale, which is en-GB, so the words are ordered according to the English alphabet (‘æ’ is treated as ‘ae’, ‘œ’ is treated as ‘oe’, ‘Þ’ is treated as ‘th’, ‘Å’ and ‘Ä’ are treated as ‘A’, ‘Ć’ is treated as ‘C’, and ‘Ż’ is treated as ‘Z’). The foreign (relative to the locale) letters ‘Ø’ and ‘Ł’ (which are considered unmodified characters rather than accented letters) are placed in a miscellaneous group at the end.

Different ordering can be obtained using different locales, for example:

\GlsXtrLoadResources[sort=sv,src={entries-utf8-1000},selection=all]

Alternatively, you can provide a custom rule or use a different sort method.

2.20 indexgroup style and bib2gls --group: 1000 UTF-8 entries

This is like Test 2.19 but it uses the indexgroup style:

\documentclass{article}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[record,nostyles,stylemods=tree,style=indexgroup]{glossaries-extra}

\GlsXtrLoadResources[src={entries-utf8-1000},selection=all]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc31
bib2gls --group test-doc31
pdflatex test-doc31

The total build time was 0:03.80 (PDF). The ordering is the same as for Test 2.19. The miscellaneous group at the end is assigned a title taken from the first entry in that group. The other groups are all headed with the corresponding upper case letter.

3. Alphabetical Order (Subset)

The example documents in this section test the indexing capabilities. Only a sub-set of the 1000 entries are used in the document. The first 20 entries are referenced twice on page 1, the first 10 are referenced on page 2, the first 5 are referenced on page 3, the first 3 are referenced on page 4, the first 2 are referenced on page 5, and finally the first 20 are again referenced on page 6. Similarly for the acronyms/abbreviations. This tests the indexing method’s ability to collate locations, and compares the efficiency of maintaining a large file containing many accumulated terms that may not be required.

A second set of tests omit the location list for comparison. This is done through the nonumberlist package option for all four methods (makeindex, xindy, \makenoidxglossaries and bib2gls) and also through the save-locations=false option for an additional test with bib2gls. There’s no significant difference for a test set of this size.

For convenience, a test command is defined in all the example documents:

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}

This does \gls{label} where the label is formed from the first argument followed by the index. So on the first iteration of \test{entry}{20}, the label is entry0, on the second iteration the label is entry1, and so on.

The document build times are summarised in Table 3. The fastest method is now with bib2gls, where the build time is under 2.5 seconds.

The next fastest methods, both with build times of around 5.5 seconds, are using TeX (\makenoidxglossaries), which is usually the slowest method, and using makeindex. However, the TeX method can’t form ranges so, for example, three-page locations are listed as ‘1, 2, 3’ whereas with all the other methods they’re concatenated into ‘1—3’. (Similarly for the larger ranges.)

The slowest method is with xindy, where the build time is approximately 7.5 seconds.

The reason for the significant improvement with bib2gls, overtaking makeindex, is due to bib2gls only writing the definitions of the entries that are actually required in the document (20 instances of \longnewglossaryentry and 20 instances of \newabbreviation in this case). With the other methods, all 2000 terms (1000 instances of \newglossaryentry and 1000 instances of \newacronym) are defined (in terms of defining the internal control sequences that store all relevant information). The build process for bib2gls is as follows:

So, in these examples, the second LaTeX call is performing only 20 instances of \longnewglossaryentry and 20 instances of \newabbrevation, whereas with the other methods both the first and second LaTeX call performs 1000 instances of \newglossaryentry and 1000 instances of \newacronym.

Therefore, although bib2gls has to parse all 1000 instances of @entry and 1000 instances of @abbreviation when it reads the .bib files, and so takes longer to run than makeindex or xindy, the associated LaTeX calls with bib2gls take less time and consume fewer resources.

Table 3: Summary (Alphabetical Order, Subset Referenced)
Test Build time (minutes:​seconds) PDF
location list included
3.1 makeglossaries (makeindex): 20/1000 (entries and acronyms) 0:05.84 (PDF)
3.2 makeglossaries (xindy): 20/1000 (entries and acronyms) 0:07.65 (PDF)
3.3 \makenoidxglossaries: 20/1000 (entries and acronyms) 0:05.64 (PDF)
3.4 bib2gls: 20/1000 (entries and abbreviations) 0:02.57 (PDF)
location list omitted
3.5 nonumberlist and makeglossaries (makeindex): 20/1000 (entries and acronyms) 0:05.89 (PDF)
3.6 nonumberlist and makeglossaries (xindy): 20/1000 (entries and acronyms) 0:07.64 (PDF)
3.7 nonumberlist and \makenoidxglossaries: 20/1000 (entries and acronyms) 0:05.63 (PDF)
3.8 nonumberlist and bib2gls: 20/1000 (entries and acronyms) 0:02.57 (PDF)
3.9 save-locations=false and bib2gls: 20/1000 (entries and acronyms) 0:02.62 (PDF)

3.1 makeglossaries (makeindex): 20/1000 (entries and acronyms)

This example uses makeindex (via makeglossaries). The acronym option is used create a list for the acronyms. Both lists are displayed using \printglossaries. For convenience a loop is used to automate the references for testing.

\documentclass{article}

\usepackage[acronym]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc32
makeglossaries test-doc32
pdflatex test-doc32

The total build time was 0:05.84 (PDF).

3.2 makeglossaries (xindy): 20/1000 (entries and acronyms)

This example is like Test 3.1 but uses xindy instead.

\documentclass{article}

\usepackage[acronym,xindy]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc33
makeglossaries test-doc33
pdflatex test-doc33

The total build time was 0:07.65 (PDF).

3.3 \makenoidxglossaries: 20/1000 (entries and acronyms)

This example is like Test 3.1 but uses TeX to sort and collate.

\documentclass{article}

\usepackage[acronym]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printnoidxglossaries
\end{document}

The document build is:

pdflatex test-doc34
pdflatex test-doc34

The total build time was 0:05.64 (PDF).

3.4 bib2gls: 20/1000 (entries and abbreviations)

This example is like Test 3.1 but uses bib2gls, which means using glossaries-extra.sty and the test files entries-1000.bib and abbreviations-1000.bib. The glossaries-extra package defaults to the nopostdot package option, which suppresses the automatic sentence terminating dot after the description implemented by the predefined glossary styles. This is reactivated with the postdot option to clarify where the description ends (since all the descriptions in the test entries end with a number, which can easily be confused with the locations).

\documentclass{article}

\usepackage[abbreviations,record,postdot]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000}]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc35
bi2gls --group test-doc35
pdflatex test-doc35

The total build time was 0:02.57 (PDF).

3.5 nonumberlist and makeglossaries (makeindex): 20/1000 (entries and acronyms)

This example is like Test 3.1 but the location list is suppressed with nonumberlist:

\documentclass{article}

\usepackage[acronym,nonumberlist]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc36
makeglossaries test-doc36
pdflatex test-doc36

The total build time was 0:05.89 (PDF).

3.6 nonumberlist and makeglossaries (xindy): 20/1000 (entries and acronyms)

This example is like Test 3.2 but the location list is suppressed with nonumberlist:

\documentclass{article}

\usepackage[acronym,xindy,nonumberlist]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc37
makeglossaries test-doc37
pdflatex test-doc37

The total build time was 0:07.64 (PDF).

3.7 nonumberlist and \makenoidxglossaries: 20/1000 (entries and acronyms)

This example is like Test 3.3 but the location list is suppressed with nonumberlist:

\documentclass{article}

\usepackage[acronym,nonumberlist]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printnoidxglossaries
\end{document}

The document build is:

pdflatex test-doc38
pdflatex test-doc38

The total build time was 0:05.63 (PDF).

3.8 nonumberlist and bib2gls: 20/1000 (entries and acronyms)

This example is like Test 3.4 but the location list is suppressed with nonumberlist:

\documentclass{article}

\usepackage[abbreviations,record,postdot,nonumberlist]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000}]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc39
bib2gls --group test-doc39
pdflatex test-doc39

The total build time was 0:02.57 (PDF).

3.9 save-locations=false and bib2gls: 20/1000 (entries and acronyms)

This example is like Test 3.8 but the locations are omitted with save-locations=false instead of nonumberlist:

\documentclass{article}

\usepackage[abbreviations,record,postdot]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000},
 save-locations=false]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc40
bib2gls --group test-doc40
pdflatex test-doc40

The total build time was 0:02.62 (PDF).

4. Order of Definition (All Entries)

The example documents in this section all test the build time for all entries sorted according to definition. In this case, the presence of UTF-8 characters is irrelevant as they don’t contribute to the sort order, so the tests here are only with the regular ASCII entries (entries-1000.tex or entries-1000.bib).

With \printnoidxglossary, \printunsrtglossary and bib2gls, there’s no actual sorting as the entries are already in the correct order. With makeindex and xindy, sorting is a part of their function, so the package option sort=def changes the way the sort field is initialised. Instead of being formed from the value of the name field, it’s assigned a numeric value, which is incremented with every definition. This means that both makeindex and xindy will assign all the entries to the ‘Numbers’ group (which becomes evident if the document uses a glossary style, such as indexgroup, that shows the group headings). For example, with the package option sort=def:

\newglossaryentry{entry0}{name={silverback},description={sample 0}}
\newglossaryentry{entry1}{name={urbaneness},description={sample 1}}

is equivalent to:

\newglossaryentry{entry0}{name={silverback},description={sample 0},
 sort={000001}}
\newglossaryentry{entry1}{name={urbaneness},description={sample 1},
 sort={000002}}

If you explicitly use the sort field then that will override this numeric assignment and the entries will no longer be ordered according to definition.

For ease of comparison, the closest matching results from Table 1 are reproduced at the end of Table 4. There’s no equivalent to Test 4.4 in the earlier sections, as that method can only be used when all defined entries need to be listed in order of definition (regardless of whether or not the entries have been used in the document).

The fastest (around 2 seconds) is Test 4.4, which also benefits from having the simplest document build (only one LaTeX call is required). The other methods are all faster than the corresponding alphabetical sort method. The most significant is Test 4.3 (\makenoidxglossaries) with a build time of approximately 3.5 seconds compared with the corresponding Test 1.8, which had a build time of around 11 minutes.

Table 4: Summary (Order of Definition)
Test Build time (minutes:​seconds) PDF
4.1 makeglossaries (makeindex): 1000 entries 0:02.91 (PDF)
4.2 makeglossaries (xindy): 1000 entries 0:04.36 (PDF)
4.3 \makenoidxglossaries: 1000 entries 0:03.58 (PDF)
4.4 glossaries-extra, sort=none and \printunsrtglossary: 1000 entries 0:01.93 (PDF)
4.5 glossaries-extra and bib2gls: 1000 entries 0:03.45 (PDF)
Reproduced from Table 1:
1.1 makeglossaries (makeindex): 1000 entries 0:02.91 (PDF)
1.5 makeglossaries (xindy): 1000 entries 0:04.33 (PDF)
1.8 \makenoidxglossaries: 1000 entries 11:04.64 (PDF)
1.12 glossaries-extra and bib2gls: 1000 entries 0:03.79 (PDF)

4.1 makeglossaries (makeindex): 1000 entries

This example is like Test 1.1 but it uses the sort=def package option.

\documentclass{article}

\usepackage[sort=def]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc41
makeglossaries test-doc41
pdflatex test-doc41

The total build time was 0:02.91 (PDF). (Compared with the build time of 0:02.91 for Test 1.1.)

4.2 makeglossaries (xindy): 1000 entries

This example is like Test 1.5 but it uses the sort=def package option.

\documentclass{article}

\usepackage[xindy,sort=def]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printglossary
\end{document}

The document build is:

pdflatex test-doc42
makeglossaries test-doc42
pdflatex test-doc42

The total build time was 0:04.36 (PDF). (Compared with the build time of 0:04.33 for Test 1.5.)

4.3 \makenoidxglossaries: 1000 entries

This example is like Test 1.8 but it uses the sort=def package option.

\documentclass{article}

\usepackage[sort=def]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\glsaddall

\begin{document}
Test document with random words.

\printnoidxglossary
\end{document}

The document build is:

pdflatex test-doc43
pdflatex test-doc43

The total build time was 0:03.58 (PDF). (Compared with the build time of 11:04.64 for Test 1.8.)

4.4 \printunsrtglossary and sort=none: 1000 entries

There’s no direct equivalent to this test in Section 1. This method uses glossaries-extra.sty with the package option sort=none. No external tool is used. The list is displayed using \printunsrtglossary, which is designed to iterate over all defined entries, in the order of definition. (This behaviour is taken advantage of by bib2gls, which only writes the definitions of the required terms, and writes them in the required order.)

\documentclass{article}

\usepackage[sort=none]{glossaries-extra}

\loadglsentries{entries-1000}

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The sort=none option disables the assignment of the sort field if omitted. In this case, the assignment is a redundant operation as that field isn’t required. Only a single LaTeX call is needed for this document, so the build process is simply:

pdflatex test-doc44

The total build time was 0:01.93 (PDF).

4.5 glossaries-extra and bib2gls: 1000 entries

This example is like Test 1.12 but it uses the sort=none resource option (not the similarly named package option).

\documentclass{article}

\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000},selection=all,sort=none]

\begin{document}
Test document with random words.

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc45
bib2gls test-doc45
pdflatex test-doc45

The total build time was 0:03.45 (PDF). (Compared with the build time of 0:03.79 for Test 1.12.)

5. Order of Use (Subset)

The sort=use option sorts according to use, that is according to the first instance that each entry is indexed in the document, using commands like \gls or \glsadd. Note that \glsaddall iterates over all entries, in the order they were added to their associated glossary, which means that simply changing, say, Test 4.1 so that sort=def is replaced by sort=use will result in the same order. With bib2gls, you can’t have both sort=use and selection=all in the same resource set as these options are incompatible.

For comparison purposes, these tests are modifications of the documents from Section 3, which only index 20 entries and 20 abbreviations. The closest matching results from Table 3 are reproduced at the end of Table 5. The loop used in the test command is reversed so that the entries aren’t indexed in the order of definition:

\newcommand{\test}[2]{%
  \entryindex=#2\relax
  \loop
   \advance\entryindex by -1\relax
   \gls{#1\number\entryindex}.
  \ifnum\entryindex>0
  \repeat
}

As with ordering by definition, both \printnoidxglossary and bib2gls simply iterate over a list that’s already in the required order (in both cases obtained by parsing the aux file), so no actual sorting is performed. With makeindex and xindy, again the sort field (if not explicitly set) is set to a numerical value. In this case, the assignment isn’t performed until the first time an entry is indexed.

As in Section 3 (and for similar reasons), the fastest method is bib2gls with a build time of around 2.5 seconds. The second fastest is using TeX (\makenoidxglossaries) with a build time of around 5.5 seconds. The third fastest is makeindex with a build time of approximately 5.5 seconds, and last is xindy with a build time of approximately 6 seconds.

Table 5: Summary (Order of Use)
Test Build time (minutes:​seconds) PDF
5.1 makeglossaries (makeindex): 20/1000 entries and acronyms 0:05.64 (PDF)
5.2 makeglossaries (xindy): 20/1000 entries and acronyms 0:06.27 (PDF)
5.3 \makenoidxglossaries: 20/1000 entries and acronyms 0:05.41 (PDF)
5.4 bib2gls: 20/1000 entries and abbreviations 0:02.58 (PDF)
Reproduced from Table 3:
3.1 makeglossaries (makeindex): 20/1000 entries and acronyms 0:05.84 (PDF)
3.2 makeglossaries (xindy): 20/1000 entries and acronyms 0:07.65 (PDF)
3.3 \makenoidxglossaries: 20/1000 entries and acronyms 0:05.64 (PDF)
3.4 bib2gls: 20/1000 entries and acronyms 0:02.57 (PDF)

5.1 makeglossaries (makeindex): 20/1000 entries and acronyms

This example is like Test 3.1 except that it uses the sort=use option and the loop is reversed:

\documentclass{article}

\usepackage[acronym,sort=use]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=#2\relax
  \loop
   \advance\entryindex by -1\relax
   \gls{#1\number\entryindex}.
  \ifnum\entryindex>0
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc46
makeglossaries test-doc46
pdflatex test-doc46

The total build time was 0:05.64 (PDF). (Compared with the build time of 0:05.84 for Test 3.1.)

5.2 makeglossaries (xindy): 20/1000 entries and acronyms

This example is like Test 3.2 except that it uses the sort=use option and the loop is reversed:

\documentclass{article}

\usepackage[acronym,xindy,sort=use]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=#2\relax
  \loop
   \advance\entryindex by -1\relax
   \gls{#1\number\entryindex}.
  \ifnum\entryindex>0
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc47
makeglossaries test-doc47
pdflatex test-doc47

The total build time was 0:06.27 (PDF). (Compared with the build time of 0:07.65 for Test 3.2.)

5.3 \makenoidxglossaries: 20/1000 entries and acronyms

This example is like Test 3.3 except that it uses the sort=use option and the loop is reversed:

\documentclass{article}

\usepackage[acronym,sort=use]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=#2\relax
  \loop
   \advance\entryindex by -1\relax
   \gls{#1\number\entryindex}.
  \ifnum\entryindex>0
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printnoidxglossaries
\end{document}

The document build is:

pdflatex test-doc48
pdflatex test-doc48

The total build time was 0:05.41 (PDF). (Compared with the build time of 0:05.64 for Test 3.3.)

5.4 bib2gls: 20/1000 entries and abbreviations

This example is like Test 3.4 except that it uses the sort=use resource option and the loop is reversed:

\documentclass{article}

\usepackage[abbreviations,record,postdot]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000},sort=use]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=#2\relax
  \loop
   \advance\entryindex by -1\relax
   \gls{#1\number\entryindex}.
  \ifnum\entryindex>0
  \repeat
}
\begin{document}
\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc49
bib2gls test-doc49
pdflatex test-doc49

Note that there’s no concept of a letter group with sort=use, so the --group switch is omitted. The total build time was 0:02.58 (PDF). (Compared with the build time of 0:02.57 for Test 3.4.)

6. Symbols

While minimizing the overall document build time is desirable, a sensible ordering of entries is also important. However symbols can be problematic for some of the sorting methods. The examples in this section use either greek.tex or greek.bib. Each entry is referenced in the document (with \gls) in a random order. These references are all in the file symbol-refs.tex which was created using:

grep '^\\newsymbol' greek.tex | sed 's/\\newsymbol{\([a-zA-Z]*\)}{.*/\\gls{\1}./' | shuf > symbol-refs.tex

This file can then simply be included in the document using:

\input{symbol-refs}

Each indexing method is tested in its ability to sort the entries according to the name field (which contains the code to display the appropriate symbol, such as \ensuremath{\alpha}), the label (a unique string used to identify each entry), the description (which contains a short phrase, sometimes starting with ‘the’ or ‘a’), and the topic (assigned to the user1 field). In addition, each indexing method has an example that adjusts the entry definition so that each symbol is a child entry with the topic as the parent.

For comparison, each method is also ordered by definition and by first use in the document. Unsurprisingly there’s no difference in the resulting order, respectively, across the different methods for each of these two cases, but the build time varies.

The sort by label method is quite straight-forward as all methods in this case are comparing simple ASCII text. There’s a slight difference in order with \makenoidxglossaries, which puts lower case before upper case, and with bib2gls, which wasn’t invoked with the --group switch and so didn’t provide distinct letter groups. In all cases the ordering, while matching the requirement to sort by label, is sub-optimal. A different naming scheme for the labels might produce a better result, however this can conflict with the need to provide memorable labels for convenience when referencing entries in the document.

In the case of ordering by the name field, xindy fails with a non-zero exit code as it strips all commands and braces, which means that many of the entries have a sort value that degenerates to an empty string. If you want to use xindy with entries where the name only contains control sequences then you must provide an appropriate sort value for those entries.

The advantage with bib2gls is that it is able to convert commands like \ensuremath{\alpha} into the closest matching Unicode characters from the Mathematical Greek Italic block. There are two tests with bib2gls for the order by name comparison. The first (Test 6.22) uses the rule for my default locale (sort=en-GB). Since this rule doesn’t include any of the Greek letters, it orders them by their Unicode values, which means that Ϝ (capital digamma) comes first, followed by the capital mathematical Greek letters, followed by the lower case mathematical Greek letters.

The second bib2gls test for sort by name (Test 6.23) uses a custom rule that makes use of \glsxtrMathItalicGreekIrules, provided by glossaries-extra-bib2gls, which is a rule block for an ordering of the mathematical Greek letters that includes digamma between epsilon and zeta. This test produces the best ordering in terms of a common ordering of mathematical Greek letters.

Sometimes there’s no agreed ordering of symbols. In the examples in this section, the Greek alphabet is the obvious order, but for more general symbols, it’s sometimes useful to be able to order by the description instead. So the tests include order by description to illustrate how this can be done with the various indexing methods. The introduction of a custom command (\sortart) helps to exclude a leading article from the description (for example, ‘an eigenvalue’ is sorted according to just ‘eigenvalue’).

Phrases and compound words cause a problem for \makenoidxglossaries and so using TeX to sort results in the worst ordering when sorting by description.

One of the descriptions contains a word with an extended Latin character (Möbius), which causes a problem for makeindex. The best results for ordering by description is with xindy and bib2gls, although bib2gls orders an apostrophe before a word break so ‘Riemann’s’ comes before ‘Riemann’. (It’s easy enough to switch this order with the setting break-marker={_}.)

Ordering by topic again involves just a simple ASCII comparison, and again \makenoidxglossaries performs worst due to its problems with word (as opposed to letter) ordering. The best method is bib2gls which able to form topic groups instead of the default letter groups. This provides the best visual effect, as the other methods don’t show the topic which results in non-intuitive sub-blocks.

The hierarchical tests programmatically create a parent entry from the topic. This is possible due to the topic value (stored in the user1 field) only containing ASCII letters and spaces, which are suitable for label formation (within the context of \newglossaryentry). In the case of bib2gls, the parent entries must be provided in a .bib file, but the labelify resource option (together with field-alias) provides a convenient way of converting the custom topic field into a suitable parent field.

Table 6: Summary (Symbols)
Test Build time (minutes:​seconds) PDF
makeindex
6.1 makeglossaries (makeindex): symbols (sort by name) 0:01.26 (PDF)
6.2 makeglossaries (makeindex): symbols (sort by label) 0:01.23 (PDF)
6.3 makeglossaries (makeindex): symbols (sort by description) 0:01.24 (PDF)
6.4 makeglossaries (makeindex): symbols (sort by topic) 0:01.24 (PDF)
6.5 makeglossaries (makeindex): symbols (topic hierarchy) 0:01.28 (PDF)
6.6 makeglossaries (makeindex): symbols (order of definition) 0:01.24 (PDF)
6.7 makeglossaries (makeindex): symbols (order of use) 0:01.24 (PDF)
xindy
6.8 makeglossaries (xindy): symbols (sort by name) Failed
6.9 makeglossaries (xindy): symbols (sort by label) 0:01.57 (PDF)
6.10 makeglossaries (xindy): symbols (sort by description) 0:01.56 (PDF)
6.11 makeglossaries (xindy): symbols (sort by topic) 0:01.58 (PDF)
6.12 makeglossaries (xindy): symbols (sort by hierarchy) 0:01.62 (PDF)
6.13 makeglossaries (xindy): symbols (order of definition) 0:01.57 (PDF)
6.14 makeglossaries (xindy): symbols (order of use) 0:01.56 (PDF)
\makenoidxglossaries
6.15 \makenoidxglossaries: symbols (sort by name) 0:03.60 (PDF)
6.16 \makenoidxglossaries: symbols (sort by label) 0:01.49 (PDF)
6.17 \makenoidxglossaries: symbols (sort by description) 0:01.53 (PDF)
6.18 \makenoidxglossaries: symbols (sort by topic) 0:01.64 (PDF)
6.19 \makenoidxglossaries: symbols (topic hierarchy) 0:02.26 (PDF)
6.20 \makenoidxglossaries: symbols (order of definition) 0:01.13 (PDF)
6.21 \makenoidxglossaries: symbols (order of use) 0:01.14 (PDF)
bib2gls
6.22 bib2gls: symbols (sort by name, sort=en-GB) 0:02.05 (PDF)
6.23 bib2gls: symbols (sort by name, sort=custom) 0:02.09 (PDF)
6.24 bib2gls: symbols (sort by label) 0:02.07 (PDF)
6.25 bib2gls: symbols (sort by description) 0:02.08 (PDF)
6.26 bib2gls: symbols (sort by topic) 0:02.10 (PDF)
6.27 bib2gls: symbols (topic hierarchy) 0:02.11 (PDF)
6.28 bib2gls: symbols (order of definition) 0:02.05 (PDF)
6.29 bib2gls: symbols (order of use) 0:02.05 (PDF)

6.1 makeglossaries (makeindex): symbols (sort by name)

The document code for this example is:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

(The use of geometry is simply to fit the entire document onto a single page for convenience, although a few of the later tests extend to two pages.)

The document build process is:

pdflatex test-doc50
makeglossaries test-doc50
pdflatex test-doc50

The total build time was 0:01.26 (PDF). The resulting list of symbols is in the following order:

𝛣(x, y) Euler beta function. 1
𝛥 Laplace operator. 1
Ϝ digamma function. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛤(n) gamma function. 1
𝛫 Kappa number. 1
𝛺 the omega constant. 1
𝛰 big O notation. 1
𝛷 magnetic flux. 1
𝛱 osmotic pressure. 1
𝛹 water potential. 1
𝛳 Theta decay. 1
𝛶 upsilon meson. 1
𝛯 Riemann’s original xi-function. 1
𝛼 angular acceleration. 1
𝛽 thermodynamic beta. 1
𝜒 chromatic number. 1
𝛿 Kronecker delta. 1
𝜖 small positive quantity. 1
𝜂 refractive index. 1
𝛾 Lorentz factor. 1
𝜄 inclusion map. 1
𝜅 curvature. 1
𝜆 an eigenvalue. 1
𝚲 diagonal matrix of eigenvalues. 1
𝚺 covariance matrix. 1
𝜇(n) Möbius function. 1
𝜈 kinematic viscosity. 1
𝜔 angular velocity. 1
𝜊 small o notation. 1
𝜙 the golden ratio. 1
𝜋 Archimedes’ constant. 1
𝜓(m)(z) polygamma function. 1
𝜌 density. 1
𝜎 standard deviation. 1
𝜏 torque. 1
𝜃i the ith statistical model parameter. 1
𝜐 frequency. 1
𝜛 angular frequency. 1
𝜗(x) first Chebyshev function. 1
𝜃⃗ the vector of statistic model parameters. 1
𝜉(s) Riemann’s xi-function. 1
𝜁(s) Riemann zeta function. 1

The reason for this order is due to makeindex not recognising LaTeX commands. So, for example, \ensuremath{\alpha} is interpreted by makeindex as the sequence of 19 characters: \ e n s u r e m a t h { \ a l p h a }. This sequence starts with a non-letter and so it’s deemed a symbol from makeindex’s point of view. (If the treegroup style had been chosen, the entries would have all been listed under ‘Symbols’.) Since all the entries start with the 13 characters \ e n s u r e m a t h { \ , the order is determined from the 14th character onwards. For example, ‘B’ comes before ‘L’, so \ensuremath{\Beta(x,y)} comes before \ensuremath{\Lambda}.

Note that the sorting is now case-sensitive: makeindex recognises three types of entry: words (which start with an alphabetic character), numbers (solely contains the digits 0, …, 9) and symbols (everything else). Words are sorted according to a case-insensitive string comparator, numbers are sorted numerically and symbols are sorted according to a case-sensitive string comparator. Therefore \ensuremath{\alpha} comes after \ensuremath{\Xi}.

The symbols representing matrices (\ensuremath{\mtx{\Lambda}} and \ensuremath{\mtx{\Sigma}}) include the semantic markup, which affects the sorting, so \ensuremath{\mtx{\Lambda}} comes after \ensuremath{\lambda} because ‘m’ comes after ‘l’. Similar for the vector \ensuremath{\vec{\theta}}.

It’s mostly a fairly reasonable order and shows the advantage of providing the missing Greek commands like \Alpha. Without this, \ensuremath{O} would end up before \ensuremath{\Delta} (since ‘O’ comes before ‘\’). They are at least ordered according to the corresponding word (‘alpha’, ‘beta’, …) even if this isn’t according to the Greek alphabetical order (where omega comes after psi). The matrices and vector interfere with this order as a result of the extra markup.

6.2 makeglossaries (makeindex): symbols (sort by label)

This example is a slightly modified version of Test 6.1:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#1},name={#2},description={#3}}%
}

\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

This defines \newsymbol in a slightly different way. The sort key is explicitly set to the label (provided in the first argument). The provided definition of \newsymbol in the greek.tex file is now ignored since \newsymbol already been defined in the document before that file was input.

This new definition of \newsymbol removes the markup from the sort value, so from makeindex’s point of view the terms are now words (‘alpha’, ‘beta’, ‘Beta’, …) which, if the labels are sensible, provides a more intuitive order. The two symbols that are a little off are varpi (𝜛) and vartheta (𝜗). A better naming scheme for the labels would produce a better result.

The document build process is:

pdflatex test-doc51
makeglossaries test-doc51
pdflatex test-doc51

The total build time was 0:01.23 (PDF). The resulting order is now:

𝛼 angular acceleration. 1

𝛣(x, y) Euler beta function. 1
𝛽 thermodynamic beta. 1

𝜒 chromatic number. 1

𝛥 Laplace operator. 1
𝛿 Kronecker delta. 1
Ϝ digamma function. 1

𝜖 small positive quantity. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝜂 refractive index. 1

𝛤(n) gamma function. 1
𝛾 Lorentz factor. 1

𝜄 inclusion map. 1

𝛫 Kappa number. 1
𝜅 curvature. 1

𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1

𝜇(n) Möbius function. 1

𝜈 kinematic viscosity. 1

𝛺 the omega constant. 1
𝜔 angular velocity. 1
𝛰 big O notation. 1
𝜊 small o notation. 1

𝛷 magnetic flux. 1
𝜙 the golden ratio. 1
𝛱 osmotic pressure. 1
𝜋 Archimedes’ constant. 1
𝛹 water potential. 1
𝜓(m)(z) polygamma function. 1

𝜌 density. 1

𝚺 covariance matrix. 1
𝜎 standard deviation. 1

𝜏 torque. 1
𝛳 Theta decay. 1
𝜃⃗ the vector of statistic model parameters. 1
𝜃i the ith statistical model parameter. 1

𝛶 upsilon meson. 1
𝜐 frequency. 1

𝜛 angular frequency. 1
𝜗(x) first Chebyshev function. 1

𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1

𝜁(s) Riemann zeta function. 1

Note that in this example the document extends beyond one page as the list is now separated into letter groups (some of which only contain one or two terms). If the treegroup style was used instead, the letter groups would become clearer with alpha in the ‘A’ letter group, beta and Beta in the ‘B’ letter group, chi in the ‘C’ letter group, and so on. When the list contains only small groups like this, it’s generally better to use nogroupskip.

6.3 makeglossaries (makeindex): symbols (sort by description)

Test 6.2 shows the advantage of defining a command like \newsymbol. In this test, instead of setting the sort value to the label, it’s set to the description instead:

\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#3},name={#2},description={#3}}%
}

The entries containing \sortart need care. The sort key is sanitized by default so this command will appear in the sort field parsed by makeindex and, as demonstrated in Test 6.1, this will be interpreted as a symbol starting with a backslash character. The sanitizesort=false package option will allow the sort field to expand. If \sortart is initially defined to ignore its first argument and then redefined after the sort field has been set, then the leading article can be omitted from the sort field. This means that, for example,

\newsymbol{lambda}{\ensuremath{\lambda}}{\sortart{an}{eigenvalue}}{linear algebra}

is now equivalent to:

\newglossaryentry{lambda}{
 sort={eigenvalue},
 name={\ensuremath{\lambda}},
 description={\sortart{an}{eigenvalue}}
}

The description field isn’t expanded on definition by default, so \sortart just needs to be redefined before the description is displayed in the glossary.

There are two potential pitfalls here: the description may contain fragile commands (which would need protecting) and a long sort value can exceed makeindex’s buffer. Fortunately, neither of these problems occur with this example. Note that the description for thetai includes $i$th within the first part of \sortart:

\newsymbol{thetai}{\ensuremath{\theta_i}}
{\sortart{the $i$th}{statistical model parameter}}
{quantities}

This means that the sort value will be just ‘statistical model parameter’ so it’s placed in the ‘S’ letter group. If $i$th is moved to the start of the second argument, the entry would end up in the ‘Symbols’ group (since $ is not a letter).

The complete document code is:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sanitizesort=false,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc51a
makeglossaries test-doc51a
pdflatex test-doc51a

The total build time was 0:01.24 (PDF). The list of symbols is now ordered as follows:

𝛼 angular acceleration. 1
𝜛 angular frequency. 1
𝜔 angular velocity. 1
𝜋 Archimedes’ constant. 1

𝛰 big O notation. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1

𝜒 chromatic number. 1
𝚺 covariance matrix. 1
𝜅 curvature. 1

𝜌 density. 1
𝚲 diagonal matrix of eigenvalues. 1
Ϝ digamma function. 1

𝜆 an eigenvalue. 1
𝛣(x, y) Euler beta function. 1

𝜗(x) first Chebyshev function. 1
𝜐 frequency. 1

𝛤(n) gamma function. 1
𝜙 the golden ratio. 1

𝜄 inclusion map. 1

𝛫 Kappa number. 1
𝜈 kinematic viscosity. 1
𝛿 Kronecker delta. 1

𝛥 Laplace operator. 1
𝛾 Lorentz factor. 1

𝜇(n) Möbius function. 1
𝛷 magnetic flux. 1

𝛺 the omega constant. 1
𝛱 osmotic pressure. 1

𝜓(m)(z) polygamma function. 1

𝜂 refractive index. 1
𝜁(s) Riemann zeta function. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1

𝜊 small o notation. 1
𝜖 small positive quantity. 1
𝜎 standard deviation. 1
𝜃i the ith statistical model parameter. 1

𝛽 thermodynamic beta. 1
𝛳 Theta decay. 1
𝜏 torque. 1

𝛶 upsilon meson. 1

𝜃⃗ the vector of statistic model parameters. 1

𝛹 water potential. 1

Note the odd ordering of ‘Möbius function’ and ‘magnetic flux’. Both sort values start with the same letter (ignoring case), so the order is based on the next letter, but one of the terms has an extended Latin character as the second letter, which makeindex interprets as two characters (obtained from the two octets of the UTF-8 character). Instead of comparing ‘ö’ with ‘a’, makeindex is comparing the non-letter 0xC3 (the first octet of ö) with the letter ‘a’.

6.4 makeglossaries (makeindex): symbols (sort by topic)

The topic argument hasn’t been needed so far. This example modifies Test 6.3 so that the sort value is formed from topic, description:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sanitizesort=false,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#4, #3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc51b
makeglossaries test-doc51b
pdflatex test-doc51b

The total build time was 0:01.24 (PDF). The list of symbols is now ordered as follows:

𝛰 big O notation. 1
𝜊 small o notation. 1

𝛱 osmotic pressure. 1

𝛳 Theta decay. 1
𝜛 angular frequency. 1
Ϝ digamma function. 1
𝛣(x, y) Euler beta function. 1
𝜗(x) first Chebyshev function. 1
𝛤(n) gamma function. 1
𝛿 Kronecker delta. 1
𝜇(n) Möbius function. 1
𝜓(m)(z) polygamma function. 1
𝜁(s) Riemann zeta function. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1

𝜋 Archimedes’ constant. 1
𝜅 curvature. 1
𝜒 chromatic number. 1

𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1

𝜏 torque. 1

𝛥 Laplace operator. 1

𝛼 angular acceleration. 1
𝜔 angular velocity. 1
𝜐 frequency. 1
𝜈 kinematic viscosity. 1
𝛾 Lorentz factor. 1
𝛷 magnetic flux. 1
𝛶 upsilon meson. 1
𝛹 water potential. 1

𝜌 density. 1
𝜙 the golden ratio. 1
𝛫 Kappa number. 1
𝛺 the omega constant. 1
𝜂 refractive index. 1
𝜖 small positive quantity. 1
𝜃i the ith statistical model parameter. 1
𝜃⃗ the vector of statistic model parameters. 1

𝜄 inclusion map. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛽 thermodynamic beta. 1
𝚺 covariance matrix. 1
𝜎 standard deviation. 1

The default group skip creates odd blocks. The topics ‘finance’, ‘functions’ and ‘fluid dynamics’ all belong to the ‘F’ letter group, so they are clumped together. Similarly ’geometry’ and ‘graph theory’ belong to the ‘G’ letter group, and ‘set theory’, ‘statistical mechanics’ and ‘statistics’ belong to the ‘S’ letter group.

The UTF-8 character no longer causes a problem as the sort values for ‘Möbius function’ and ‘magnetic flux’ are now ‘functions, Möbius function’ and ‘physics, magnetic flux’.

6.5 makeglossaries (makeindex): symbols (topic hierarchy)

This example modifies Test 6.4 to improve the grouping. This takes advantage of the fact that all the topics in the example don’t contain any non-expandable or fragile commands. This means that the topic argument may be used as a label. The \newsymbol command now creates an entry for the topic and defines the symbol entry as a child entry:

\newcommand{\newsymbol}[4]{%
 \provideglossaryentry{#4}{name={#4},description={\nopostdesc}}%
 \newglossaryentry{#1}{parent={#4},sort={#3},name={#2},description={#3}}%
}

The use of \provideglossaryentry means that each topic entry is only defined once. If it has already been defined, \provideglossaryentry does nothing. The sub-entries are sorted by description (as in Test 6.3)

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sanitizesort=false,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \provideglossaryentry{#4}{name={#4},description={\nopostdesc}}%
 \newglossaryentry{#1}{parent={#4},sort={#3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc51c
makeglossaries test-doc51c
pdflatex test-doc51c

The total build time was 0:01.28 (PDF). The list of symbols is now ordered as follows:

asymptotic notation
𝛰 big O notation. 1
𝜊 small o notation. 1

biology

𝛱 osmotic pressure. 1

finance

𝛳 Theta decay. 1
fluid dynamics
𝜛 angular frequency. 1
functions
Ϝ digamma function. 1
𝛣(x, y) Euler beta function. 1
𝜗(x) first Chebyshev function. 1
𝛤(n) gamma function. 1
𝛿 Kronecker delta. 1
𝜇(n) Möbius function. 1
𝜓(m)(z) polygamma function. 1
𝜁(s) Riemann zeta function. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1

geometry

𝜋 Archimedes’ constant. 1
𝜅 curvature. 1
graph theory
𝜒 chromatic number. 1

linear algebra

𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1

mechanics

𝜏 torque. 1

operators

𝛥 Laplace operator. 1

physics

𝛼 angular acceleration. 1
𝜔 angular velocity. 1
𝜐 frequency. 1
𝜈 kinematic viscosity. 1
𝛾 Lorentz factor. 1
𝛷 magnetic flux. 1
𝛶 upsilon meson. 1
𝛹 water potential. 1

quantities

𝜌 density. 1
𝜙 the golden ratio. 1
𝛫 Kappa number. 1
𝛺 the omega constant. 1
𝜂 refractive index. 1
𝜖 small positive quantity. 1
𝜃i the ith statistical model parameter. 1
𝜃⃗ the vector of statistic model parameters. 1

set theory

𝜄 inclusion map. 1
statistical mechanics
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛽 thermodynamic beta. 1
statistics
𝚺 covariance matrix. 1
𝜎 standard deviation. 1

Again, the default group skip option creates an odd effect, although it’s less jarring now that the topics are visible in the list.

6.6 makeglossaries (makeindex): symbols (order of definition)

This example is like Test 6.1 but lists symbols according to the order of definition:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sort=def,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc51d
makeglossaries test-doc51d
pdflatex test-doc51d

The total build time was 0:01.24 (PDF). The resulting list of symbols is in the following order:

𝛼 angular acceleration. 1
𝛽 thermodynamic beta. 1
𝛣(x, y) Euler beta function. 1
𝛤(n) gamma function. 1
𝛾 Lorentz factor. 1
𝛥 Laplace operator. 1
𝛿 Kronecker delta. 1
𝜖 small positive quantity. 1
Ϝ digamma function. 1
𝜁(s) Riemann zeta function. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝜂 refractive index. 1
𝛳 Theta decay. 1
𝜃i the ith statistical model parameter. 1
𝜃⃗ the vector of statistic model parameters. 1
𝜗(x) first Chebyshev function. 1
𝜄 inclusion map. 1
𝛫 Kappa number. 1
𝜅 curvature. 1
𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1
𝜇(n) Möbius function. 1
𝜈 kinematic viscosity. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1
𝛰 big O notation. 1
𝜊 small o notation. 1
𝛱 osmotic pressure. 1
𝜋 Archimedes’ constant. 1
𝜛 angular frequency. 1
𝜌 density. 1
𝚺 covariance matrix. 1
𝜎 standard deviation. 1
𝜏 torque. 1
𝛶 upsilon meson. 1
𝜐 frequency. 1
𝛷 magnetic flux. 1
𝜙 the golden ratio. 1
𝜒 chromatic number. 1
𝛹 water potential. 1
𝜓(m) (z) polygamma function. 1
𝛺 the omega constant. 1
𝜔 angular velocity. 1

This ordering is quite reasonable, but only because I happened to define the symbols in a reasonable order.

6.7 makeglossaries (makeindex): symbols (order of use)

This example is like Test 6.6 but lists symbols according to the order of use:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sort=use,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc51e
makeglossaries test-doc51e
pdflatex test-doc51e

The total build time was 0:01.24 (PDF). The resulting list of symbols is in the following order:

𝜔 angular velocity. 1
𝜐 frequency. 1
Ϝ digamma function. 1
𝛿 Kronecker delta. 1
𝜓(m) (z) polygamma function. 1
𝜃i the ith statistical model parameter. 1
𝛫 Kappa number. 1
𝜏 torque. 1
𝜉(s) Riemann’s xi-function. 1
𝜊 small o notation. 1
𝛶 upsilon meson. 1
𝜛 angular frequency. 1
𝜆 an eigenvalue. 1
𝛣(x, y) Euler beta function. 1
𝜌 density. 1
𝚺 covariance matrix. 1
𝜁(s) Riemann zeta function. 1
𝛼 angular acceleration. 1
𝜅 curvature. 1
𝜒 chromatic number. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛽 thermodynamic beta. 1
𝜖 small positive quantity. 1
𝛤(n) gamma function. 1
𝛥 Laplace operator. 1
𝜗(x) first Chebyshev function. 1
𝜇(n) Möbius function. 1
𝛳 Theta decay. 1
𝛹 water potential. 1
𝜄 inclusion map. 1
𝜈 kinematic viscosity. 1
𝛾 Lorentz factor. 1
𝛯 Riemann’s original xi-function. 1
𝛱 osmotic pressure. 1
𝛺 the omega constant. 1
𝛷 magnetic flux. 1
𝜋 Archimedes’ constant. 1
𝚲 diagonal matrix of eigenvalues. 1
𝜙 the golden ratio. 1
𝜎 standard deviation. 1
𝜂 refractive index. 1
𝛰 big O notation. 1
𝜃⃗ the vector of statistic model parameters. 1

6.8 makeglossaries (xindy): symbols (sort by name)

This example is like Test 6.1 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process should be:

pdflatex test-doc52
makeglossaries test-doc52
pdflatex test-doc52

However, xindy fails in this case. The actual xindy call (executed by makeglossaries) is:

xindy -L english -I xindy -M "test-doc52" -t "test-doc52.glg" -o "test-doc52.gls" "test-doc52.glo"

This fails with a fairly cryptic error message:

ERROR: CHAR: index 0 should be less than the length of the string

This is one of the messages that makeglossaries checks for when xindy fails, and it reports the problem:

Sort key required for entries only containing command names.

The makeglossaries script then tries to parse the .glo file to determine which sort values are problematic:

Attempting to determine which entries have problem sort keys.
Parsing 'test-doc52.glo'

In this case 32 problematic entries where found, which is almost all of the entries defined in greek.tex. These are then listed. For brevity, only the first two are reproduced below:

31 problematic entries found:

Label: 'gamma'. Sort value : '\\ensuremath {\\gamma }'
(Try adding sort={gamma} to the definition.)
Label: 'beta'. Sort value : '\\ensuremath {\\beta }'
(Try adding sort={beta} to the definition.)

This diagnostic function isn’t available with makeglossaries-lite and is the one of the reasons why makeglossaries is the recommended script.

The problem stems from the fact that xindy strips LaTeX commands and braces from the sort value so, for example, \emph{duck} becomes simply duck. This is usually quite useful, but it becomes a problem when the sort value only contains commands, as with \ensuremath{\alpha}. Once the markup is stripped, the sort value becomes empty, which is what triggers the error. The solution is suggested by makeglossaries: add a suitable sort value, which is done in Test 6.9 below.

6.9 makeglossaries (xindy): symbols (sort by label)

This example is like Test 6.2 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#1},name={#2},description={#3}}%
}

\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc53
makeglossaries test-doc53
pdflatex test-doc53

The total build time was 0:01.57 (PDF). This produces the same order as Test 6.2.

6.10 makeglossaries (xindy): symbols (sort by description)

This example is like Test 6.3 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,sanitizesort=false,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc54
makeglossaries test-doc54
pdflatex test-doc54

The total build time was 0:01.56 (PDF). This produces a similar order as Test 6.3, but not identical:

𝛼 angular acceleration. 1
𝜛 angular frequency. 1
𝜔 angular velocity. 1
𝜋 Archimedes’ constant. 1

𝛰 big O notation. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1

𝜒 chromatic number. 1
𝚺 covariance matrix. 1
𝜅 curvature. 1

𝜌 density. 1
𝚲 diagonal matrix of eigenvalues. 1
Ϝ digamma function. 1

𝜆 an eigenvalue. 1
𝛣(x, y) Euler beta function. 1

𝜗(x) first Chebyshev function. 1
𝜐 frequency. 1

𝛤(n) gamma function. 1
𝜙 the golden ratio. 1

𝜄 inclusion map. 1

𝛫 Kappa number. 1
𝜈 kinematic viscosity. 1
𝛿 Kronecker delta. 1

𝛥 Laplace operator. 1
𝛾 Lorentz factor. 1

𝛷 magnetic flux. 1

𝜇(n) Möbius function. 1
𝛺 the omega constant. 1
𝛱 osmotic pressure. 1

𝜓(m)(z) polygamma function. 1

𝜂 refractive index. 1
𝜁(s) Riemann zeta function. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1

𝜊 small o notation. 1
𝜖 small positive quantity. 1
𝜎 standard deviation. 1
𝜃i the ith statistical model parameter. 1

𝛽 thermodynamic beta. 1
𝛳 Theta decay. 1
𝜏 torque. 1

𝛶 upsilon meson. 1

𝜃⃗ the vector of statistic model parameters. 1

𝛹 water potential. 1

The difference is in the ordering of ‘magnetic flux’ and ‘Möbius function’. In this case, xindy has produced a more sensible order than makeindex.

6.11 makeglossaries (xindy): symbols (sort by topic)

This example is like Test 6.4 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,sanitizesort=false,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#4, #3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc55
makeglossaries test-doc55
pdflatex test-doc55

The total build time was 0:01.58 (PDF). The order is the same as for Test 6.4.

6.12 makeglossaries (xindy): symbols (topic hierarchy)

This example is like Test 6.5 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,sanitizesort=false,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \provideglossaryentry{#4}{name={#4},description={\nopostdesc}}%
 \newglossaryentry{#1}{parent={#4},sort={#3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc56
makeglossaries test-doc56
pdflatex test-doc56

The total build time was 0:01.62 (PDF). The order is the same as for Test 6.5.

6.13 makeglossaries (xindy): symbols (order of definition)

This example is like Test 6.6 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,sort=def,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc57
makeglossaries test-doc57
pdflatex test-doc57

The total build time was 0:01.57 (PDF). The order is the same as for Test 6.6.

6.14 makeglossaries (xindy): symbols (order of use)

This example is like Test 6.7 but it uses xindy:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[xindy,sort=use,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makeglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printglossary
\end{document}

The document build process is:

pdflatex test-doc58
makeglossaries test-doc58
pdflatex test-doc58

The total build time was 0:01.56 (PDF). The order is the same as for Test 6.7.

6.15 \makenoidxglossaries: symbols (sort by name)

This example is like Test 6.1 but it uses TeX to sort and collate. Note the need for the sanitizesort package option. This is usually on by default but \makeidxnoglossaries changes the default to sanitizesort=false (unless explicitly overridden). This allows certain commands (such as \" and \c) to be stripped or (for example, \ae and \oe) replaced. While this worked for documents like Test 2.14, it doesn’t work when the name key contains other commands. Without the sanitizesort option, the document in this example would generate the error:
! Improper alphabetic constant.
<to be read again> 
                   \protect 

By sanitizing the sort value, \ensuremath{\alpha} is interpreted as the sequence of 19 characters \ e n s u r e m a t h { \ a l p h a }, and so on, as makeindex does in Test 6.1.

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sanitizesort,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc59
pdflatex test-doc59

The total build time was 0:03.60 (PDF). The order is the same as for Test 6.1.

6.16 \makenoidxglossaries: symbols (sort by label)

This example is like Test 6.2 but it uses TeX to sort and collate. There’s no need for the sanitizesort option in this case as the labels don’t contain any commands.
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries

\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#1},name={#2},description={#3}}%
}

\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc60
pdflatex test-doc60

The total build time was 0:01.49 (PDF). The resulting order is almost the same except that lower case comes before upper case within each letter group:

𝛼 angular acceleration. 1

𝛽 thermodynamic beta. 1
𝛣(x, y) Euler beta function. 1

𝜒 chromatic number. 1

𝛿 Kronecker delta. 1
𝛥 Laplace operator. 1
Ϝ digamma function. 1

𝜖 small positive quantity. 1
𝜂 refractive index. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1

𝛾 Lorentz factor. 1
𝛤(n) gamma function. 1

𝜄 inclusion map. 1

𝜅 curvature. 1
𝛫 Kappa number. 1

𝜆 an eigenvalue. 1
𝚲 diagonal matrix of eigenvalues. 1

𝜇(n) Möbius function. 1

𝜈 kinematic viscosity. 1

𝜔 angular velocity. 1
𝛺 the omega constant. 1
𝜊 small o notation. 1
𝛰 big O notation. 1

𝜙 the golden ratio. 1
𝛷 magnetic flux. 1
𝜋 Archimedes’ constant. 1
𝛱 osmotic pressure. 1
𝜓(m)(z) polygamma function. 1
𝛹 water potential. 1

𝜌 density. 1

𝜎 standard deviation. 1
𝚺 covariance matrix. 1

𝜏 torque. 1
𝜃⃗ the vector of statistic model parameters. 1
𝛳 Theta decay. 1
𝜃i the ith statistical model parameter. 1

𝜐 frequency. 1
𝛶 upsilon meson. 1

𝜛 angular frequency. 1
𝜗(x) first Chebyshev function. 1

𝜉(s) Riemann’s xi-function. 1
𝛯 Riemann’s original xi-function. 1

𝜁(s) Riemann zeta function. 1

6.17 \makenoidxglossaries: symbols (sort by description)

This example is like Test 6.3 but it uses TeX to sort an collate. In this case there’s no need for the sanitizesort=false option as it’s automatically implemented by \makenoidxglossaries.
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc61
pdflatex test-doc61

The total build time was 0:01.53 (PDF). The resulting order is almost the same as in Test 6.3 but there are some differences.

𝛼 angular acceleration. 1
𝜛 angular frequency. 1
𝜔 angular velocity. 1
𝜋 Archimedes’ constant. 1

𝛰 big O notation. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1

𝜒 chromatic number. 1
𝚺 covariance matrix. 1
𝜅 curvature. 1

𝜌 density. 1
𝚲 diagonal matrix of eigenvalues. 1
Ϝ digamma function. 1

𝜆 an eigenvalue. 1
𝛣(x, y) Euler beta function. 1

𝜗(x) first Chebyshev function. 1
𝜐 frequency. 1

𝛤(n) gamma function. 1
𝜙 the golden ratio. 1

𝜄 inclusion map. 1

𝛫 Kappa number. 1
𝜈 kinematic viscosity. 1
𝛿 Kronecker delta. 1

𝛥 Laplace operator. 1
𝛾 Lorentz factor. 1

𝛷 magnetic flux. 1
𝜇(n) Möbius function. 1

𝛺 the omega constant. 1
𝛱 osmotic pressure. 1

𝜓(m)(z) polygamma function. 1

𝜂 refractive index. 1
𝛯 Riemann’s original xi-function. 1
𝜁(s) Riemann zeta function. 1
𝜉(s) Riemann’s xi-function. 1

𝜖 small positive quantity. 1
𝜊 small o notation. 1
𝜎 standard deviation. 1
𝜃i the ith statistical model parameter. 1

𝛽 thermodynamic beta. 1
𝛳 Theta decay. 1
𝜏 torque. 1

𝛶 upsilon meson. 1

𝜃⃗ the vector of statistic model parameters. 1

𝛹 water potential. 1

The first difference is in the ordering of ‘magnetic flux’ and ‘Möbius function’. This method strips accents so ‘Möbius function’ ends up as ‘Mobius function’ in the sort value. There are two other differences: in the ordering of ‘Riemann’s original x-function’, ‘Riemann zeta function’ and ‘Riemann’s xi-function’ and in the ordering of ‘small positive quantity’ and ‘small o notation’. A better order is obtained using:

\printnoidxglossary[sort=letter]

which suggests something faulty in the default word order sort with \printnoidxglossary.

6.18 \makenoidxglossaries: symbols (sort by topic)

This example is like Test 6.4 but it uses TeX to sort an collate. As with the previous example, there’s no need for the sanitizesort=false option as it’s automatically implemented by \makenoidxglossaries.
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \newglossaryentry{#1}{sort={#4, #3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc62
pdflatex test-doc62

The total build time was 0:01.64 (PDF). The list of symbols is now ordered as follows:

𝛰 big O notation. 1
𝜊 small o notation. 1

𝛱 osmotic pressure. 1

𝛳 Theta decay. 1
𝜛 angular frequency. 1
𝛯 Riemann’s original xi-function. 1
𝜇(n) Möbius function. 1
𝜗(x) first Chebyshev function. 1
𝛤(n) gamma function. 1
𝜁(s) Riemann zeta function. 1
𝛣(x, y) Euler beta function. 1
𝜉(s) Riemann’s xi-function. 1
𝜓(m)(z) polygamma function. 1
𝛿 Kronecker delta. 1
Ϝ digamma function. 1

𝜋 Archimedes’ constant. 1
𝜅 curvature. 1
𝜒 chromatic number. 1

𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1

𝜏 torque. 1

𝛥 Laplace operator. 1

𝛷 magnetic flux. 1
𝛾 Lorentz factor. 1
𝜈 kinematic viscosity. 1
𝛹 water potential. 1
𝛼 angular acceleration. 1
𝛶 upsilon meson. 1
𝜐 frequency. 1
𝜔 angular velocity. 1

𝜃⃗ the vector of statistic model parameters. 1
𝜂 refractive index. 1
𝜙 the golden ratio. 1
𝛺 the omega constant. 1
𝜖 small positive quantity. 1
𝜌 density. 1
𝛫 Kappa number. 1
𝜃i the ith statistical model parameter. 1

𝜄 inclusion map. 1
𝛽 thermodynamic beta. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝜎 standard deviation. 1
𝚺 covariance matrix. 1

As with the previous example, the faulty word comparator used by default with \printnoidxglossary. A better order is again obtained using:

\printnoidxglossary[sort=letter]

6.19 \makenoidxglossaries: symbols (topic hierarchy)

This example is like Test 6.5 but it uses TeX to sort an collate:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries

\newcommand{\sortart}[2]{#2}
\newcommand{\newsymbol}[4]{%
 \provideglossaryentry{#4}{name={#4},description={\nopostdesc}}%
 \newglossaryentry{#1}{parent={#4},sort={#3},name={#2},description={#3}}%
}

\loadglsentries{greek}
\renewcommand{\sortart}[2]{#1 #2}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc63
pdflatex test-doc63

The total build time was 0:02.26 (PDF). The list of symbols is now ordered as follows:

asymptotic notation
𝛰 big O notation. 1
𝜊 small o notation. 1

biology

𝛱 osmotic pressure. 1

finance

𝛳 Theta decay. 1
fluid dynamics
𝜛 angular frequency. 1
functions
Ϝ digamma function. 1
𝛣(x, y) Euler beta function. 1
𝜗(x) first Chebyshev function. 1
𝛤(n) gamma function. 1
𝛿 Kronecker delta. 1
𝜇(n) Möbius function. 1
𝜓(m)(z) polygamma function. 1
𝛯 Riemann’s original xi-function. 1
𝜁(s) Riemann zeta function. 1
𝜉(s) Riemann’s xi-function. 1

geometry

𝜋 Archimedes’ constant. 1
𝜅 curvature. 1
graph theory
𝜒 chromatic number. 1

linear algebra

𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1

mechanics

𝜏 torque. 1

operators

𝛥 Laplace operator. 1

physics

𝛼 angular acceleration. 1
𝜔 angular velocity. 1
𝜐 frequency. 1
𝜈 kinematic viscosity. 1
𝛾 Lorentz factor. 1
𝛷 magnetic flux. 1
𝛶 upsilon meson. 1
𝛹 water potential. 1

quantities

𝜌 density. 1
𝜙 the golden ratio. 1
𝛫 Kappa number. 1
𝛺 the omega constant. 1
𝜂 refractive index. 1
𝜖 small positive quantity. 1
𝜃i the ith statistical model parameter. 1
𝜃⃗ the vector of statistic model parameters. 1

set theory

𝜄 inclusion map. 1
statistical mechanics
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛽 thermodynamic beta. 1
statistics
𝚺 covariance matrix. 1 𝜎 standard deviation. 1

Again the word ordering is inappropriate with the Riemann functions.

6.20 \makenoidxglossaries: symbols (order of definition)

This example is like Test 6.6 but it uses TeX to sort an collate, although there isn’t any actual sorting in this case as the order is obtained from an internal list.
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sort=def,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc64
pdflatex test-doc64

The total build time was 0:01.13 (PDF). The ordering is the same as for Test 6.6.

6.21 \makenoidxglossaries: symbols (order of use)

This example is like Test 6.7 but it uses TeX to sort an collate, but again no actual sorting is performed.
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[sort=use,nolist,nolong,nosuper,style=tree]{glossaries}

\pagestyle{empty}

\makenoidxglossaries
\loadglsentries{greek}

\begin{document}

\input{symbol-refs}

\printnoidxglossary
\end{document}

The document build process is:

pdflatex test-doc65
pdflatex test-doc65

The total build time was 0:01.14 (PDF). The ordering is the same as for Test 6.7.

6.22 bib2gls: symbols (sort by name, sort=en-GB)

Each bib2gls entry type has a designated field to use if the sort field is omitted (which is typically the case and is recommended practice with bib2gls).

The general @entry type of definition falls back on the name field, which is consistent with the behaviour of \newglossaryentry, but @symbol falls back on the label, which is consistent with the behaviour of \glsxtrnewsymbol.

So, to sort @symbol entries by name, you need to either use symbol-sort-fallback=name to change the fallback or switch the field used for sorting with sort-field=name, which will sort all entries by the name field regardless of whether they have been defined using @symbol or @entry or any other entry type. The first approach is best if you have a mixture of entry types (such as @symbol and @abbreviation), as different types may require different fallback values (for example, you may want abbreviations to fall back on the long field).

Since I used glossaries-extra v1.27 to build the bib2gls examples here, the missing Greek commands (\Beta etc) are provided by glossaries-extra-bib2gls so the definitions in @preamble are ignored. This means that these characters appear slightly differently in this document to the earlier examples as the definitions now use \mathrm for the upper case letters.

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src={greek},symbol-sort-fallback=name]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build process is:

pdflatex test-doc66
bib2gls test-doc66
pdflatex test-doc66

The total build time was 0:02.05 (PDF). The resulting list of symbols is in the following order:

Ϝ digamma function. 1
𝛣(x, y) Euler beta function. 1
𝛤(n) gamma function. 1
𝛥 Laplace operator. 1
𝛨(t) Boltzmann’s 𝛨-Theorem. 1
𝛫 Kappa number. 1
𝚲 diagonal matrix of eigenvalues. 1
𝛯 Riemann’s original xi-function. 1
𝛰 big O notation. 1
𝛱 osmotic pressure. 1
𝛳 Theta decay. 1
𝚺 covariance matrix. 1
𝛶 upsilon meson. 1
𝛷 magnetic flux. 1
𝛹 water potential. 1
𝛺 the omega constant. 1
𝛼 angular acceleration. 1
𝛽 thermodynamic beta. 1
𝛾 Lorentz factor. 1
𝛿 Kronecker delta. 1
𝜁(s) Riemann zeta function. 1
𝜂 refractive index. 1
𝜃⃗ the vector of statistic model parameters. 1
𝜃i the ith statistical model parameter. 1
𝜄 inclusion map. 1
𝜅 curvature. 1
𝜆 an eigenvalue. 1
𝜇(n) Möbius function. 1
𝜈 kinematic viscosity. 1
𝜉(s) Riemann’s xi-function. 1
𝜊 small o notation. 1
𝜋 Archimedes’ constant. 1
𝜌 density. 1
𝜎 standard deviation. 1
𝜏 torque. 1
𝜐 frequency. 1
𝜒 chromatic number. 1
𝜓(m)(z) polygamma function. 1
𝜔 angular velocity. 1
𝜖 small positive quantity. 1
𝜗(x) first Chebyshev function. 1
𝜙 the golden ratio. 1
𝜛 angular frequency. 1

Remember that if the sort resource option (supplied in \GlsXtrLoadResources) is missing, then bib2gls will use a rule-based locale sort. Since the document doesn’t have any language setting, bib2gls uses the default locale for the Java Virtual Machine (which is usually the operating system’s default locale), so for me this is equivalent to using:

\GlsXtrLoadResources[sort={en-GB},src={greek},symbol-sort-fallback=name]

A clue to how bib2gls sorts can be found in the glstex file that it creates. Each entry definition includes the sort field as determined by bib2gls. This field has no use in the document, as it’s only used by bib2gls, but it’s provided for informational purposes.

For example, the symbol with the label zeta had name={\ensuremath{\zeta(s)}} in the greek.bib file. The sort value obtained from this is shown in the glstex file:

sort={𝜁|s|}

The bib2gls transcript (.glg) file contains another clue:

texparserlib: {}\ensuremath{\zeta(s)} -> 𝜁(s)

bib2gls uses the TeX Parser Library to interpret LaTeX commands. Lines starting with texparserlib: in the transcript file indicate the result of a conversion performed by the interpreter. In this case, it shows that bib2gls has determined through the TeX Parser Library that the closest Unicode match for \ensuremath{\zeta(s)} is 𝜁(s).

The parentheses are replaced with the pipe (vertical bar) symbol as a result of the default word-order action used by the locale or rule-based sort methods (such as sort=en-GB).

The TeX Parser Library recognises most of the LaTeX kernel commands that can be represented as Unicode characters (such as \zeta). It also recognises the missing Math-Greek commands so, for example, \ensuremath{\Beta} is converted to the Mathematical Italic Capital Beta 𝛣 (0x1D6E3), not the Basic Latin B. Since \Beta is already defined from bib2gls’s point of view, the definition of \Beta provided in the @preamble has no effect on bib2gls (since it’s defined with \providecommand), but the @preamble definition is written to the glstex file to ensure that LaTeX recognises \Beta when the document is compiled.

Since the en-GB rule doesn’t include Greek or Math-Greek characters, they are sorted according to their Unicode values. So digamma Ϝ (0x03DC) is listed first, followed by the Mathematical Italic Capital Greek letters, followed by the Mathematical Italic small Greek letters. Font information is stripped so, although bib2gls can detect the definition of \mtx from @preamble, the font change introduced by \mathbf is ignored. However, combining accents aren’t ignored, as seen with the theta entry:

texparserlib: {}\ensuremath{\vec{\theta}} -> 𝜃⃗

The result consists of two Unicode characters: 0x1D703 (Mathematic Italic Small Theta) and 0x20D7 (Combining Right Arrow Above). In this case, the sort rule ignores the combining diacritic.

Note that if I had simply used the Latin B, H, O and o explicitly in the name, instead of providing the missing commands (\Beta, \Eta, \Omicron and \omicron), those entries would be listed first, since they are recognised as valid letter groups by the rule.

One final observation, the name field has had an empty brace inserted at the front, which is the reason for the transcript messages:

Inserting empty group in front of \ensuremath to protect it from mfirstuc.

This is done to protect the field against any first letter upper-casing that might be performed by a glossary style or the use of commands like \Gls. These lines are just messages not warnings and can be ignored or you can switch off this action with --no-mfirstuc-math-protection. The presence of this empty group doesn’t affect the sorting when the TeX parser is used.

6.23 bib2gls: symbols (sort by name, sort=custom)

This is like Test 6.22 but it uses a custom rule, which is set with sort=custom and sort-rule=rule. For convenience, I’ve used one of the common rule commands provided with glossaries-extra.sty v1.27. If you have an older version the rule would need to be written explicitly in terms of \string\u hex or \glshex hex.
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[sort={custom},
 sort-rule={\glsxtrspacerules
  ;\glsxtrcombiningdiacriticrules
  ,\glsxtrhyphenrules
  <\glsxtrgeneralpuncrules
  <\glsxtrdigitrules
  <\glsxtrGeneralLatinIrules
  <\glsxtrMathItalicGreekIrules},
 src={greek},symbol-sort-fallback=name]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

Be careful if you use a group style, such as treegroup, as the group title is obtained from the Unicode character at the start of the sort value. Your document will need support for these characters.

The document build process is:

pdflatex test-doc67
bib2gls test-doc67
pdflatex test-doc67

The total build time was 0:02.09 (PDF).

The rule here is:

If you prefer to have digamma before or after all the other Greek letters you can use <\glsxtrUpDigamma <\glsxtrMathItalicGreekIIrules or <\glsxtrMathItalicGreekIIrules <\glsxtrUpDigamma instead of <\glsxtrMathItalicGreekIrules.

The resulting list of symbols is in the following order:

𝛼 angular acceleration. 1
𝛽 thermodynamic beta. 1
𝛣(x, y) Euler beta function. 1
𝛾 Lorentz factor. 1
𝛤(n) gamma function. 1
𝛥 Laplace operator. 1
𝛿 Kronecker delta. 1
𝜖 small positive quantity. 1
Ϝ digamma function. 1
𝜁(s) Riemann zeta function. 1
𝜂 refractive index. 1
𝛨(t) Boltzmann’s 𝛨-Theorem. 1
𝛳 Theta decay. 1
𝜃⃗ the vector of statistic model parameters. 1
𝜗(x) first Chebyshev function. 1
𝜃i the ith statistical model parameter. 1
𝜄 inclusion map. 1
𝛫 Kappa number. 1
𝜅 curvature. 1
𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1
𝜇(n) Möbius function. 1
𝜈 kinematic viscosity. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1
𝛰 big 𝛰 notation. 1
𝜊 small o notation. 1
𝛱 osmotic pressure. 1
𝜋 Archimedes’ constant. 1
𝜛 angular frequency. 1
𝜌 density. 1
𝚺 covariance matrix. 1
𝜎 standard deviation. 1
𝜏 torque. 1
𝛶 upsilon meson. 1
𝜐 frequency. 1
𝛷 magnetic flux. 1
𝜙 the golden ratio. 1
𝜒 chromatic number. 1
𝛹 water potential. 1
𝜓(m)(z) polygamma function. 1
𝛺 the omega constant. 1
𝜔 angular velocity. 1

Note that the variants have been gathered appropriately, so the variant theta (𝜗) is with the regular upper and lower case theta (𝛳 and 𝜃). Similarly, the variant pi (𝜛) is with the regular upper and lower case pi (𝛱 and 𝜋). In each case, the different versions of the letter are considered identical from the rule’s point of view. So 𝛳, 𝜃 and 𝜗 are treated as the same character.

The TeX parser treats ^ (or \sp) and _ (or \sb) slightly differently to \textsuperscript and \textsubscript. In text-mode, if the subscript or superscript can be completely represented in Unicode, then the Unicode characters are used. For example, \textsuperscript{(42)} will be converted to ⁽⁴²⁾ (0x207D, 0x2074, 0x00B2, 0x207E) whereas \textsuperscript{(4,2)} will be converted to <sup>(4,2)</sup> (and the markup is then stripped by bib2gls).

In math-mode (if MathJax output is off, which it always is with bib2gls), then the <sup> and <sub> tags will always be used. The resulting string returned by the TeX parser always has the markup stripped, so \ensuremath{\theta_i} is translated to 𝜃<sup>i</sup> and ends up as just 𝜃i. If any of the entries contain code that could end up as subscript or superscript characters, then these would need to be incorporated into the rule.

6.24 bib2gls: symbols (sort by label)

This is like Test 6.2 but it uses bib2gls. Since the default fallback for the sort field is the label for @symbol entries, this example is quite simple:
\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src={greek}]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build process is:

pdflatex test-doc68
bib2gls test-doc68
pdflatex test-doc68

The total build time was 0:02.07 (PDF). This has the same ordering as for Test 6.2, but in this case there are no group separators since the --group switch wasn’t used.

6.25 bib2gls: symbols (sort by description)

This is like Test 6.3 but it uses bib2gls. In this case, instead of changing symbol-sort-fallback the field used for sorting is set with sort-field. The definition of \sortart is provided for use in the document, but it would be better to supply an alternative definition just for bib2gls’s use that omits the first argument.

There are a number of different ways to achieve this. The examples in the bib2gls manual have separate .bib files for different command definitions. So there’s a file nointerpret-preamble.bib that provides commands for use in the document that should be ignored by bib2gls and there’s a file interpret-preamble.bib that provides commands for use by bib2gls that shouldn’t be defined in the document.

In order to adopt this approach, the @preamble code would need to be moved out of greek.bib and into a new file nointerpret-preamble.bib (which contains nothing else). Another file, interpret-preamble.bib just needs the line:

@preamble{"\providecommand{\sortart}[2]{#2}"}

The other definitions aren’t required. The Greek commands like \Beta are already defined in the TeX parser. The custom command \mtx simply applies a font change, so it’s not needed by bib2gls. Unknown commands are ignored, so \mtx{\Lambda} will be treated as \Lambda, which is the end result in Test 6.22 and Test 6.23. (Besides, this example is sorting by description and none of the descriptions contain \mtx.)

The document would then have two instances of \GlsXtrLoadResources. The first ensures that the definitions required by the document are provided:

\GlsXtrLoadResources[src=nointerpret-preamble,
 interpret-preamble=false]

The interpret-preamble=false prevents bib2gls from parsing the definitions. The second instance provides the definition needed by bib2gls:

\GlsXtrLoadResources[src={interpret-preamble,greek},
 sort-field=description]

Since the command is defined using \providecommand it won’t override the previous definition. You can instruct bib2gls to omit the command definitions from the glstex file if you want using write-preamble=false, but in this case it’s not essential.

Since the above method would require editing greek.bib, I decided to use a different approach here. In this case, I still have a file called interpret-preamble.bib which just contains:

@preamble{"\providecommand{\sortart}[2]{#2}"}

This needs to be loaded before greek.bib to ensure that bib2gls picks up the definition, but the definition shouldn’t be written to the glstex file:

\GlsXtrLoadResources[src=interpret-preamble,
 write-preamble=false]

The next resource set can load greek.bib. Since \sortart is now a recognised command, bib2gls will ignore the second definition (since it’s defined with \providecommand). Since none of the other commands are needed by bib2gls, it’s simplest to instruct bib2gls to skip the preamble-parsing step. (It will still write the preamble commands to the glstex file.)

The complete document is:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src=interpret-preamble,
 write-preamble=false]

\GlsXtrLoadResources[src={greek},
 interpret-preamble=false,
 sort-field=description
]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build process is:

pdflatex test-doc69
bib2gls --group test-doc69
pdflatex test-doc69

The total build time was 0:02.08 (PDF).

Note that in this case I’ve used the --group switch, which divides the list into (unheaded) letter groups. For headed letter groups, the style needs to be changed (for example, style=treegroup).

The ordering is slightly different from Test 6.3, Test 6.10 and Test 6.17:

𝛼 angular acceleration. 1
𝜛 angular frequency. 1
𝜔 angular velocity. 1
𝜋 Archimedes’ constant. 1

𝛰 big O notation. 1
𝛨(t) Boltzmann’s 𝛨-theorem. 1

𝜒 chromatic number. 1
𝚺 covariance matrix. 1
𝜅 curvature. 1

𝜌 density. 1
𝚲 diagonal matrix of eigenvalues. 1
Ϝ digamma function. 1

𝜆 an eigenvalue. 1
𝛣(x, y) Euler beta function. 1

𝜗(x) first Chebyshev function. 1
𝜐 frequency. 1

𝛤(n) gamma function. 1
𝜙 the golden ratio. 1

𝜄 inclusion map. 1

𝛫 Kappa number. 1
𝜈 kinematic viscosity. 1
𝛿 Kronecker delta. 1

𝛥 Laplace operator. 1
𝛾 Lorentz factor. 1

𝛷 magnetic flux. 1
𝜇(n) Möbius function. 1

𝛺 the omega constant. 1
𝛱 osmotic pressure. 1

𝜓(m)(z) polygamma function. 1

𝜂 refractive index. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1
𝜁(s) Riemann zeta function. 1

𝜊 small o notation. 1
𝜖 small positive quantity. 1
𝜎 standard deviation. 1
𝜃i the ith statistical model parameter. 1

𝛽 thermodynamic beta. 1
𝛳 Theta decay. 1
𝜏 torque. 1

𝛶 upsilon meson. 1

𝜃⃗ the vector of statistic model parameters. 1

𝛹 water potential. 1

The difference between this and the xindy version (Test 6.10) is in the ordering of the Riemann functions. The default break-at=word setting replaces word boundaries with | so the sort values (which can be found in the file test-doc69-1.glstex) are:

sort={Riemann's|original|xi-function|}
sort={Riemann's|xi-function|}
sort={Riemann|zeta|function|}

The en-GB rule orders the pipe character (|) after the apostrophe character (') so Riemann| comes after Riemann'. The ordering can be altered by changing the break marker to a character that comes before apostrophe in the rule. For example:

\GlsXtrLoadResources[src={greek},
 interpret-preamble=false,
 break-marker={_},
 sort-field=description
]

(Alternatively, you could provide a custom rule but it’s usually simpler to just change the marker.)

6.26 bib2gls: symbols (sort by topic)

So far the topic field has been ignored by bib2gls. This example aliases it to the group field. Note that this field may only contain content that can form a label. That is, it can’t contain any special characters or unexpandable commands. Fortunately, the topic field only contains ASCII letters and spaces, so it’s acceptable content. (If it did contain any problematic content, you can just add labelify=group to strip any non-label content.)

The sorting is performed according to the topic (group) followed by the description. This is done with sort-field=group (to sort by the group field) combined with sort-suffix=description, which appends the description to the sort field.

The document just requires a minor modification to Test 6.25:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=treegroup]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src=interpret-preamble,
 write-preamble=false]

\GlsXtrLoadResources[src={greek},
 interpret-preamble=false,
 field-aliases={topic=group},
 sort-field=group,
 sort-suffix=description
]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build process is:

pdflatex test-doc70
bib2gls --group test-doc70
pdflatex test-doc70

The total build time was 0:02.10 (PDF). The order is:

asymptotic notation

𝛰 big O notation. 1
𝜊 small o notation. 1

biology

𝛱 osmotic pressure. 1

finance

𝛳 Theta decay. 1

fluid dynamics

𝜛 angular frequency. 1

functions

Ϝ digamma function. 1
𝛣(x, y) Euler beta function. 1
𝜗(x) first Chebyshev function. 1
𝛤(n) gamma function. 1
𝛿 Kronecker delta. 1
𝜇(n) Möbius function. 1
𝜓(m)(z) polygamma function. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1
𝜁(s) Riemann zeta function. 1

geometry

𝜋 Archimedes’ constant. 1
𝜅 curvature. 1

graph theory

𝜒 chromatic number. 1

linear algebra

𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1

mechanics

𝜏 torque. 1

operators

𝛥 Laplace operator. 1

physics

𝛼 angular acceleration. 1
𝜔 angular velocity. 1
𝜐 frequency. 1
𝜈 kinematic viscosity. 1
𝛾 Lorentz factor. 1
𝛷 magnetic flux. 1
𝛶 upsilon meson. 1
𝛹 water potential. 1

quantities

𝜌 density. 1
𝜙 the golden ratio. 1
𝛫 Kappa number. 1
𝛺 the omega constant. 1
𝜂 refractive index. 1
𝜖 small positive quantity. 1
𝜃i the ith statistical model parameter. 1
𝜃⃗ the vector of statistic model parameters. 1

set theory

𝜄 inclusion map. 1

statistical mechanics

𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛽 thermodynamic beta. 1

statistics

𝚺 covariance matrix. 1
𝜎 standard deviation. 1

Note that this creates custom groups, so it doesn’t have the odd clumping effect from topics starting with the same letter. Remember that the group value is a label. The title can be changed using \glsxtrsetgrouptitle{label}{title}. For example:

\glsxtrsetgrouptitle{fluid dynamics}{Fluid Dynamics}

6.27 bib2gls: symbols (topic hierarchy)

One weakness of bib2gls is that you can’t programmatically define entries, so it’s not possible to do something like:

\newcommand{\newsymbol}[4]{%
 \provideglossaryentry{#4}{name={#4},description={\nopostdesc}}%
 \newglossaryentry{#1}{parent={#4},sort={#3},name={#2},description={#3}}%
}

Although it’s possible to create a second entry using dual entry formats, such as @dualabbreviationentry, more complicated multi-definitions like the above aren’t supported. However, it’s still possible to provide a bib2gls version of Test 6.5 by providing an extra .bib file. This is less convenient as it means that the parent entries need defining, but this method doesn’t require any modifications to the greek.bib file. The file topics.bib was created using

grep topic greek.bib | sed -r 's/  topic = \{(.*)\},/@index{\1}/' | sort | uniq > topics.bib

Spaces aren’t permitted in label names in the .bib format, so topics with a compound title needed editing:

@index{asymptotic-notation,
  name={asymptotic notation}
}

@index{fluid-dynamics,
  name={fluid dynamics}
}
@index{graph-theory,
 name={graph theory}
}
@index{linear-algebra,
 name={linear algebra}
}
@index{set-theory,
  name={set theory}
}
@index{statistical-mechanics,
  name={statistical mechanics}
}

I also added the encoding comment at the start of the file (although in this case it’s not strictly necessary as the file only contains ASCII characters). You can download the final topics.bib.

The aim here is to alias the topic fields in greek.bib to the parent field, but the space in the compound names needs to be replaced with a hyphen in order to match the labels in topics.bib. As from version 1.2 of bib2gls, you can use the resource option labelify to convert the contents of a field into a string suitable for use as a label. This will first try to interpret the value if certain special characters are detected in it (not applicable in this example), and will then apply any substitutions indicated by labelify-replace and finally remove any content that can’t be included in a label (such as special characters). If fontspec isn’t detected in the document’s .log file, then non-ASCII characters will additionally be decomposed and non-ASCII content stripped.

This means that to convert

topic = {fluid dynamics}

into

parent = {fluid-dynamics}

I need the resource options:

 field-aliases={topic=parent},
 labelify={parent},
 labelify-replace={{ }{-}}

The complete document is:

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src=interpret-preamble,
 write-preamble=false]

\GlsXtrLoadResources[src={topics,greek},
 interpret-preamble=false,
 field-aliases={topic=parent},
 labelify={parent},
 labelify-replace={{ }{-}},
 symbol-sort-fallback=description
]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build is:

pdflatex test-doc71
bib2gls test-doc71
pdflatex test-doc71

The total build time was 0:02.11 (PDF).

I haven’t used the --group switch so there are no separations between letter groups (because there aren’t any distinct groups). The entries defined with @index (the top-level topics) are sorted by the name field (which defaults to the label if omitted). The entries defined with @symbol (the symbol sub-entries) fall back on the description field (identified by symbol-sort-fallback).

The order is:

asymptotic notation
𝛰 big O notation. 1
𝜊 small o notation. 1
biology
𝛱 osmotic pressure. 1
finance
𝛳 Theta decay. 1
fluid dynamics
𝜛 angular frequency. 1
functions
Ϝ digamma function. 1
𝛣(x, y) Euler beta function. 1
𝜗(x) first Chebyshev function. 1
𝛤(n) gamma function. 1
𝛿 Kronecker delta. 1
𝜇(n) Möbius function. 1
𝜓(m)(z) polygamma function. 1
𝛯 Riemann’s original xi-function. 1
𝜉(s) Riemann’s xi-function. 1
𝜁(s) Riemann zeta function. 1
geometry
𝜋 Archimedes’ constant. 1
𝜅 curvature. 1
graph theory
𝜒 chromatic number. 1
linear algebra
𝚲 diagonal matrix of eigenvalues. 1
𝜆 an eigenvalue. 1
mechanics
𝜏 torque. 1
operators
𝛥 Laplace operator. 1
physics
𝛼 angular acceleration. 1
𝜔 angular velocity. 1
𝜐 frequency. 1
𝜈 kinematic viscosity. 1
𝛾 Lorentz factor. 1
𝛷 magnetic flux. 1
𝛶 upsilon meson. 1
𝛹 water potential. 1
quantities
𝜌 density. 1
𝜙 the golden ratio. 1
𝛫 Kappa number. 1
𝛺 the omega constant. 1
𝜂 refractive index. 1
𝜖 small positive quantity. 1
𝜃i the ith statistical model parameter. 1
𝜃⃗ the vector of statistic model parameters. 1
set theory
𝜄 inclusion map. 1
statistical mechanics
𝛨(t) Boltzmann’s 𝛨-theorem. 1
𝛽 thermodynamic beta. 1
statistics
𝚺 covariance matrix. 1
𝜎 standard deviation. 1

6.28 bib2gls: symbols (order of definition)

This example orders the symbols according to the order of definition, which is implemented with the sort=none resource option.

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src={greek},sort=none]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build process is:

pdflatex test-doc72
bib2gls test-doc72
pdflatex test-doc72

The total build time was 0:02.05 (PDF). The order is the same as for Test 6.6.

6.29 bib2gls: symbols (order of use)

This example orders the symbols according to first use in the document, which is implemented with the sort=use resource option.

\documentclass{article}

\usepackage[a4paper,margin=5mm]{geometry}
\usepackage[record,nostyles,stylemods={tree},style=tree]{glossaries-extra}

\pagestyle{empty}

\GlsXtrLoadResources[src={greek},sort=use]

\begin{document}

\input{symbol-refs}

\printunsrtglossary
\end{document}

The document build process is:

pdflatex test-doc73
bib2gls test-doc73
pdflatex test-doc73

The total build time was 0:02.05 (PDF). The order is the same as for Test 6.7.

7. Alphabetical Order With Cross-References (Subset)

These tests are similar to those in Section 3 (location list included) but the entries are all selected from the file xrentries.tex or, with bib2gls, xrentries.bib. Note that there are some cross-reference trails in these files. For example, xrentry655 references xrentry415, xrentry415 references xrentry15, and xrentry15 references xrentry13.

In the first set of tests, the document references 32 entries in the main matter, but once all cross-referenced entries are added, there are a total of 39 entries in the glossary.

In the second set of tests, the document references 4000 entries in the main matter, but once all cross-referenced entries are added, there are a total of 4207 entries in the glossary.

With bib2gls, the cross-references can be picked up when the bib file is parsed, and those entries will added as dependencies of the entries that have been recorded (indexed) in the document. However, it won’t be possible to obtain the locations associated with those cross-referenced entries until they themselves have been recorded. This means that if you required location lists, you will need a second bib2gls+LaTeX in the document build. If you don’t require location lists, or if you don’t require location lists for the entries that are only referenced within the glossary, then you will only need one bib2gls call.

Location lists can be suppressed with the nonumberlist package option, or you can instruct bib2gls not to bother saving locations with the save-locations=false resource option. To prevent locations within the glossary from being added to the location lists, you can change the default format to glsignore at the start of the glossary. For example:

\GlsXtrSetDefaultNumberFormat{glsignore}
\printunsrtglossaries

With the other indexing options, the cross-references will only be indexed once the description in which they are contained is displayed in the glossary. This means that you will have to repeatedly rebuild the document until all cross-references are present. The test documents use hyperref, which will generate a warning when the document build is incomplete as there will be hyperlinks to undefined targets. For example:

pdfTeX warning (dest): name{glo:xrentry0} has been referenced but does not exist, replaced by a fixed one

The other indexing options will also be problematic if you want to suppress locations that are indexing within the glossary (but retain the locations in the main matter). In this case, using format=glsignore will result in an invisible location and, if there’s more that one location in the list, spurious commas or en-dashes. Switching off indexing in the glossary (using the noindex option, provided by glossaries-extra), won’t work as then the entries that are only referenced in the glossary won’t be indexed and so won’t appear in the glossary.

The results are summarized in Table 6. The fastest method is to use bib2gls with the location suppressed in the glossary. This only requires one bib2gls call. The document build was approximately 4 seconds for 32/6000, and approximately 25 seconds for 4000/6000. Using two bib2gls calls to allow locations from references within the glossary took approximately 7 seconds for 32/6000 and 53 seconds for 4000/6000.

The other methods were significantly slower. For the smaller 32/6000 tests, makeindex and \makenoidxglossaries were comparable (55 seconds for makeindex and 54 seconds for \makenoidxglossaries), and the slowest method was with xindy, which took approximately 65 seconds.

For the larger 4000/6000 tests, makeindex took approximately 53 seconds. The xindy test document required special handling to deal with duplicate sort values. The total build time took approximately 73 seconds. Worst of all, by far, was \makenoidxglossaries, which doesn’t scale well, and took over 12 hours and had to be aborted.

Table 6: Summary (Alphabetical Order, Subset with Cross-References)
Test Build time (minutes:​seconds) PDF
32/6000
7.1 makeglossaries (makeindex) 0:54.51 (PDF)
7.2 makeglossaries (xindy) 1:04.61 (PDF)
7.3 \makenoidxglossaries 0:53.86 (PDF)
7.4 bib2gls 0:06.98 (PDF)
7.5 bib2gls (no glossary locations) 0:03.93 (PDF)
4000/6000
7.6 makeglossaries (makeindex) 0:53.27 (PDF)
7.7 makeglossaries (xindy) 1:12.82 (PDF)
7.8 \makenoidxglossaries aborted at 12h 24m (PDF)
7.9 bib2gls 0:53.17 (PDF)
7.10 bib2gls (no glossary locations) 0:25.11 (PDF)

7.1 makeglossaries (makeindex): cross-references (minimum 32/6000)

This example uses makeindex (via makeglossaries). There is only one list, which is displayed with \printglossaries. For convenience a loop is used to automate the references for testing. This will create 32 references within the main matter, but once the glossary is present, there will be additional references in the back matter.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makeglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printglossaries
\end{document}
The bash script (builddoc74) used to build this document (test-doc74.tex) uses a while loop that tests the transcript file for the undefined hypertarget warning, but there’s a cap on the number of iterations to prevent the build process going on indefinitely in the event that some modification to the document doesn’t accidentally introduce a hyperlink that will never be defined.
#!/usr/bin/bash

N=0;
pdflatex test-doc74
while grep -q "pdfTeX warning (dest): name{glo:" "test-doc74.log" ; do
  let N=N+1
  if [ $N -ge 20 ]
  then
    echo "Exceeded maximum number of iterations" 1>&2
    exit 1
  fi
  makeglossaries test-doc74
  pdflatex test-doc74
done
echo "N:" $N

In this case, a total of four iterations are needed to fully resolve all references. This is equivalent to:

pdflatex test-doc74
makeglossaries test-doc74
pdflatex test-doc74
makeglossaries test-doc74
pdflatex test-doc74
makeglossaries test-doc74
pdflatex test-doc74
makeglossaries test-doc74
pdflatex test-doc74

The total build time was 0:54.51 (PDF).

7.2 makeglossaries (xindy): cross-references (minimum 32/6000)

This example is as Test 7.1 but uses xindy instead of makeindex. The document is almost the same as in the other example, except for the xindy package option.

\usepackage[xindy]{glossaries}

As before, a total of four iterations are needed to fully resolve all references:

pdflatex test-doc75
makeglossaries test-doc75
pdflatex test-doc75
makeglossaries test-doc75
pdflatex test-doc75
makeglossaries test-doc75
pdflatex test-doc75
makeglossaries test-doc75
pdflatex test-doc75

The total build time was 1:04.61 (PDF).

7.3 \makenoidxglossaries: cross-references (minimum 32/6000)

This example is as Test 7.1 but uses \makenoidxglossaries:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makenoidxglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printnoidxglossaries
\end{document}

The document build needed to fully resolve all references:

pdflatex test-doc76
pdflatex test-doc76
pdflatex test-doc76
pdflatex test-doc76
pdflatex test-doc76

The total build time was 0:53.86 (PDF).

7.4 bib2gls: cross-references (minimum 32/6000)

This example is as Test 7.1 but uses bib2gls with the file xrentries.bib.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printunsrtglossaries
\end{document}

This only requires two bib2gls calls:

pdflatex test-doc77
bib2gls -g test-doc77
pdflatex test-doc77
bib2gls -g test-doc77
pdflatex test-doc77
The first instance is sufficient to pick up the cross-reference trails. The second is required to pick up the locations from the references in the glossary.

The total build time was 0:06.98 (PDF).

7.5 bib2gls: cross-references, no glossary locations (minimum 32/6000)

This example is as Test 7.4 but suppresses the locations that occur in the glossary:

\backmatter
\GlsXtrSetDefaultNumberFormat{glsignore}
\printunsrtglossaries

This now only requires one bib2gls call:

pdflatex test-doc77a
bib2gls -g test-doc77a
pdflatex test-doc77a

The total build time was 0:03.93 (PDF).

7.6 makeglossaries (makeindex): cross-references (minimum 4000/6000)

This is similar to Test 7.1, but references 4000 entries within the main matter.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makeglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printglossaries
\end{document}

In this case, a total of three iterations in the bash script are needed to fully resolve all references. This is equivalent to:

pdflatex test-doc74big
makeglossaries test-doc74big
pdflatex test-doc74big
makeglossaries test-doc74big
pdflatex test-doc74big
makeglossaries test-doc74big
pdflatex test-doc74big

The total build time was 0:53.27, compared with 0:54.51 for Test 7.1 (PDF).

7.7 makeglossaries (xindy): cross-references (minimum 4000/6000)

This example is as Test 7.6 but uses xindy instead of makeindex. The document should almost be the same as in the other example, except for the xindy package option.

\usepackage[xindy]{glossaries}

Unfortunately the build script in this case originally exceeded the maximum number of iterations (20) with some entries that were actually referenced in the document not being added to the glossary. There were no warning or error messages. On investigate, it turned out that these entries, by random chance, had duplicate names, which meant they had duplicate sort values and so were merged. (This highlights the need to cap the maximum number of iterations.) Although the xrentries.tex file was randomly generated, these duplicates could indicate homographs in a real document. The solution was to redefine \glsprestandardsort to append the entry’s label to the sort value. This ensures unique sort values (although it could adversely affect the sort order).

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[xindy]{glossaries}

\renewcommand*{\glsprestandardsort}[3]{%
  \edef#1{#1.#3}%
  \glsdosanitizesort
}

\makeglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printglossaries
\end{document}

As in the previous example, a total of three iterations is required to fully resolve all references:

pdflatex test-doc75big
makeglossaries test-doc75big
pdflatex test-doc75big
makeglossaries test-doc75big
pdflatex test-doc75big
makeglossaries test-doc75big
pdflatex test-doc75big

The total build time was 1:12.82, compared with 1:04.61 for Test 7.2 (PDF).

7.8 \makenoidxglossaries: cross-references (minimum 4000/6000)

This example is as Test 7.6 but uses \makenoidxglossaries instead of makeindex. This document takes hours to compile. The main bulk of this time is spent sorting the entries. This only needs to be done on the final LaTeX run, so a workaround is used to omit sorting for the intermediate steps.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\providecommand{\sortmethod}{def}

\makenoidxglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printnoidxglossary[sort=\sortmethod]
\end{document}

The document build required to fully resolve all references is:

pdflatex test-doc76big
pdflatex test-doc76big
pdflatex test-doc76big
pdflatex "\def\sortmethod{standard}\input test-doc76big"

The total build time was aborted at 12h 24m, compared with 0:53.86 for Test 7.3 and 0:53.27 for Test 7.6 (PDF).

7.9 bib2gls: cross-references (minimum 4000/6000)

This example is as Test 7.6 but uses bib2gls instead of makeindex.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}
\begin{document}
\mainmatter

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printunsrtglossaries
\end{document}

As with Test 7.4, two bib2gls calls are require to ensure the location lists include the locations of the entries that are only referenced within the glossary:

pdflatex test-doc77big
bib2gls -g test-doc77big
pdflatex test-doc77big
bib2gls -g test-doc77big
pdflatex test-doc77big

The total build time was 0:53.17, compared with 0:06.98 for Test 7.4 and 0:53.27 for Test 7.6 (PDF).

7.10 bib2gls: cross-references (minimum 4000/6000)

This example is as Test 7.9 but switches to ignored locations in the backmatter:

\GlsXtrSetDefaultNumberFormat{glsignore}
\printunsrtglossaries
As with Test 7.5, this only requires a single bib2gls call:
pdflatex test-doc77abig
bib2gls -g test-doc77abig
pdflatex test-doc77abig

The total build time was 0:25.11, compared with 0:03.93 for Test 7.5 and 0:53.17 for Test 7.9 (PDF).

8. Alphabetical Order With Last Used (Subset)

These tests are as those in Section 3 (location list included) and in Section 7, but there is additional code at the end of the document that writes information to the aux file for each entry that has been marked as used. This simulates storing information in the aux file for use in the next run. The test command that performs this action is:

\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
which needs to be issued at the end of the document.

This command writes \@entry@used{label} to the aux file for each entry that has been marked as used. That command also needs to be defined. In this case, I’m assuming that a comma-separated list of entry labels is required as well as the total number of labels in that list:

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
Note that these definitions use internal commands so \makeatletter and \makeatother are required. Global definitions are necessary as the aux file is input within a group, which means that local definitions will be lost.

It may be that this sub-list isn’t required, in which case this command could simply set a field. For example, the following alternative definition will set the user1 field to 1:

\newcommand{\@entry@used}[1]{\glsfieldgdef{#1}{useri}{1}}
Here's a command that performs a simple test to determine if this field has been set for an individual entry (whose label is provided in the argument):
\newcommand{\ifentrywasusedlastrun}[1]{\ifglsfieldeq{#1}{useri}{1}}
This command actually has three arguments. The final two are the true and false code that will be picked up by \ifglsfieldeq (which takes five arguments). For example:
\ifentrywasusedlastrun{entry1}{was used}{wasn’t used}

For these tests, it’s simpler to create a list and calculate the total count as it makes it easier to check the result. The list is displayed at the start of the document with \glsseelist (this requires its argument to be expanded, otherwise use \glsxtrseelist with glossaries-extra).

With bib2gls, no entries are defined on the first LaTeX run, so there’s nothing to loop over. This means that in order to pick up the information from the aux file, an extra LaTeX run will be required after bib2gls has created the relevant glstex file. (This is likely to be needed anyway for all methods for substantial documents, to ensure page numbers are correct in the table of contents, location lists are up-to-date in the index etc.)

However, in this case, the list that is being iterated over only contains the entries that have been selected by bib2gls, which may be significantly smaller than the entire set of entries that the other methods are iterating over. Furthermore, when using bib2gls, the required information may already be available without the need to save it in the aux file. For example, if I’m testing the first use flag to determine whether or not an entry was indexed in the previous run (since I’m only using \gls, which both indexes and unsets the first use flag), then that information can already be determined.

The default settings with bib2gls means that only those entries that have been recorded (indexed) and their dependencies will be selected. Which means that all entries defined in the document (within the glstex file) were either recorded or were required by a recorded entry. In the event that there are dependencies that aren’t recorded, a simple test is to check if the location field has been set (which will be the case if either the entry is an unrecorded dependency or if it was only recorded with an ignored format, such as glsignore).

The \testloop is now performed in the preamble:

\newcommand{\testloop}{%
 \global\advance\usedlastruncount by 1\relax
 \forallglsentries{\thisentry}%
 {%
  \glsxtrifhasfield{location}{\thisentry}%
  {%
   \ifdefempty\entriesusedlastrun
   {\global\let\entriesusedlastrun\thisentry}%
   {\xappto\entriesusedlastrun{,\thisentry}}%
  }{}%
 }
}

If no list of entries from last run is required, but instead you just want to use the earlier \ifentrywasusedlastrun, then this can be defined as:

\newcommand{\ifentrywasusedlastrun}[1]{\glsxtrifhasfield{location}{#1}}

There are cases where the location field will be set for an entry without any records, and that’s where the entry has one of the cross-reference fields set (see, seealso or alias), in which case the cross-reference is added to the location list by default. If that’s likely to occur then another method is to instruct bib2gls to save the record count. By default, this is the total number of all records associated with the entry, including ignored records. If you want to exclude ignored records, you will need bib2gls v3.0+ and use the record-count-rule switch.

Note that if you have been using commands like \cgls, then you may want to consider switching to the analogous \rgls commands, which are more efficient, if you are storing the record count. (The \cgls commands require additional information to be written to the aux file, which is what using the record count is aiming to avoid.) If you want unit record counting, you’ll need to include the --record-count-unit switch when you invoke bib2gls.

The custom \testloop command could now be defined as:

\newcommand{\testloop}{%
 \global\advance\usedlastruncount by 1\relax
 \forallglsentries{\thisentry}%
 {%
  \GlsXtrIfFieldNonZero{recordcount}{\thisentry}%
  {%
   \ifdefempty\entriesusedlastrun
   {\global\let\entriesusedlastrun\thisentry}%
   {\xappto\entriesusedlastrun{,\thisentry}}%
  }{}%
 }
}
However, there’s no need for this command as bib2gls provides a command in the glstex file, which is used to set the recordcount field:
\providecommand*{\bibglssettotalrecordcount}[2]{%
   \GlsXtrSetField{#1}{recordcount}{#2}%
}
This command can instead be defined before \GlsXtrLoadResources to set the field and the additional information at the same time:
\newcommand*{\bibglssettotalrecordcount}[2]{%
  \GlsXtrSetField{#1}{recordcount}{#2}%
  \ifnum#2>0\relax
   \advance\usedlastruncount by 1\relax
   \ifdefempty\entriesusedlastrun
   {\def\entriesusedlastrun{#1}}%
   {\appto\entriesusedlastrun{,#1}}%
  \fi
}

In this case, \ifentrywasusedlastrun can be defined as:

\newcommand{\ifentrywasusedlastrun}[1]{\GlsXtrIfFieldNonZero{recordcount}{#1}}

For comparison, Test 8.10 and Test 8.17 use the same test command to write to the aux file as the non-bib2gls examples (which requires an extra LaTeX run), whereas the other bib2gls tests replace that command with a simple check to determine whether or not the location field has been set or hook into the record count assignment, as described above.

These alternative bib2gls methods are subtly different from using \ifglsused to determine whether or not to write information to the aux file. Since these test documents are now noting entries that were indexed (recorded) on the last LaTeX run rather that those that were marked as used by the end of the document for the last LaTeX run. The other difference is the order of entry labels in the list \entriesusedlastrun.

\forallglsentries is actually a nested loop that iterates over all glossaries and, for each glossary, iterates over all entries within that glossary. This means that the list will be in subsets corresponding to each glossary, with the items in each subset in the order in which they were added to the glossary (which occurs when the entry is defined). This means that the list is according to the order of definition per glossary. With bib2gls, the order of definition (from LaTeX’s point of view) is the order obtained from sorting. So with bib2gls, the list is in alphabetical order (within each subset).

Finally, Test 8.13 and Test 8.20 use record counting but switch to ignored locations for the glossary and the bib2gls v3.0+ switch --record-count-rule non-ignored is used. Since ignored locations aren’t included in the record count, entries that only occur in the glossary aren’t included in the list created by the test commands because, even though they were marked as used by the end of the document, their record count is zero. These examples have the simplest document build (LaTeX+bib2gls+LaTeX).

The best method depends on whether or not you are specifically interested in entries that have been marked as used (beware of resets) or if you are only interested in entries that have been indexed/recorded. The number of entries that are referenced within the document also makes a difference.

The results are summarized in Table 7. The comparison column shows the build time for the corresponding test from Section 3 or Section 7. Note that all but two tests list all entries that have been used in the document. Test 8.13 and Test 8.20 only list the subset of entries (32 and 4000, respectively) that were used in the main matter and not the additional entries that were added to resolve cross-references.

As with Section 3 and Section 7, the fastest methods are with bib2gls. The document build was approximately 3 seconds for Test 8.5 and 4 seconds for Test 8.13.

The slowest method for the small tests was xindy with a build time of approximately 8 seconds for Test 8.2 and 78 seconds for Test 8.8.

The large 4000/6000 tests that write information to the aux file cause a delay both in writing the information to the aux file at the end of the document and in reading the aux file at the start of the document. There are 4000 entries referenced in the main matter and 207 cross-referenced entries in the glossary. This means that the aux file has an additional 4207 lines on top of what it had for the analogous tests in Section 7.

The aux file will ordinarily be significantly larger with both bib2gls and \makenoidxglossaries, as that’s where the indexing information is saved. With makeindex and xindy, the information is saved in the associated glossary file. This means that all methods have the same number of write operations, but inputting the aux file will take longer for bib2gls and \makenoidxglossaries. Despite this, bib2gls still has the faster build times, even for Test 8.17 because bib2gls is able to resolve all the cross-reference trails in a single call. The second call is only required to ensure the location lists are correct.

For the large 4000/6000 tests, the information added to the aux file caused the build time for bib2gls to jump from 53 seconds to 3 minutes, for makeindex to jump from 53 seconds to 8.5 minutes, and for xindy to jump from 73 seconds to 9 minutes.

Table 7: Summary (Alphabetical Order With Last Used, Subset Referenced)
Test Build time (minutes:​seconds) Comparison PDF
Counterparts to Section 3 (40/2000)
8.1 makeglossaries (makeindex): 20/1000 (entries and acronyms) 0:06.21 0:05.84 (PDF)
8.2 makeglossaries (xindy): 20/1000 (entries and acronyms) 0:07.93 0:07.65 (PDF)
8.3 \makenoidxglossaries: 20/1000 (entries and acronyms) 0:05.83 0:05.64 (PDF)
8.4 bib2gls: 20/1000 (entries and abbreviations) 0:05.41 0:02.57 (PDF)
8.5 bib2gls: 20/1000 (entries and abbreviations) location check 0:02.71 0:02.57 (PDF)
8.6 bib2gls: 20/1000 (entries and abbreviations) record count 0:02.78 0:02.57 (PDF)
Counterparts to Section 7 (32/6000)
8.7 makeglossaries (makeindex): cross-references 1:06.25 0:54.51 (PDF)
8.8 makeglossaries (xindy): cross-references 1:17.87 1:04.61 (PDF)
8.9 \makenoidxglossaries: cross-references 1:05.77 0:53.86 (PDF)
8.10 bib2gls: cross-references 0:07.17 0:06.98 (PDF)
8.11 bib2gls: cross-references, location field 0:07.22 0:06.98 (PDF)
8.12 bib2gls: cross-references, record count 0:07.23 0:06.98 (PDF)
8.13 bib2gls: cross-references, record count and ignored locations 0:04.04 0:03.93 (PDF)
Counterparts to Section 7 (4000/6000)
8.14 makeglossaries (makeindex): cross-references 8:36.02 0:53.27 (PDF)
8.15 makeglossaries (xindy): cross-references 8:48.99 1:12.82 (PDF)
8.16 \makenoidxglossaries: cross-references aborted at 12h 24m (PDF)
8.17 bib2gls: cross-references 3:19.61 0:53.17 (PDF)
8.18 bib2gls: cross-references, location field 1:31.06 0:53.17 (PDF)
8.19 bib2gls: cross-references, record count 1:35.14 0:53.17 (PDF)
8.20 bib2gls: cross-references, record count and ignored locations 0:47.19 0:25.11 (PDF)

8.1 makeglossaries (makeindex): 20/1000 (entries and acronyms)

This example is as Test 3.1, but with the extra commands to save information in the aux file:

\documentclass{article}

\usepackage[acronym]{glossaries}

\makeglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\expandafter\glsseelist\expandafter{\entriesusedlastrun}.}

\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printglossaries
\end{document}

The document build is:

pdflatex test-doc78
makeglossaries test-doc78
pdflatex test-doc78

The total build time was 0:06.21, compared with 0:05.84 for Test 3.1 (PDF).

8.2 makeglossaries (xindy): 20/1000 (entries and acronyms)

This example is as Test 8.1, but includes the xindy package option.

The document build is:

pdflatex test-doc79
makeglossaries test-doc79
pdflatex test-doc79

The total build time was 0:07.93, compared with 0:07.65 for Test 3.2 and 0:06.21 for Test 8.1 (PDF).

8.3 \makenoidxglossaries: 20/1000 (entries and acronyms)

This example is as Test 3.3, but with the extra commands to save information in the aux file:

\documentclass{article}

\usepackage[acronym]{glossaries}

\makenoidxglossaries
\loadglsentries{entries-1000}
\loadglsentries{acronyms-1000}

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\expandafter\glsseelist\expandafter{\entriesusedlastrun}.}

\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printnoidxglossaries
\end{document}

The document build is:

pdflatex test-doc80
pdflatex test-doc80

The total build time was 0:05.83, compared with 0:05.64 for Test 3.3 and 0:06.21 for Test 8.1 (PDF).

8.4 bib2gls: 20/1000 (entries and abbreviations)

This example is as Test 3.4, but with the extra commands to save information in the aux file:

\documentclass{article}

\usepackage[abbreviations,record,postdot]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000}]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc81
bi2gls --group test-doc81
pdflatex test-doc81
pdflatex test-doc81

Note the extra LaTeX call that’s required in this case.

The resulting document is slightly different to Test 8.3, as the list stored in \entriesusedlastrun is now in alphabetical order (per glossary). Whereas in the previous tests, the list stored in \entriesusedlastrun is in the order of definition (per glossary). They are, in fact, both in order of definition, it’s just that bib2gls writes the LaTeX definition code in the glstex files in the order obtained from sorting (which is how it can be used with \printunsrtglossary).

The total build time was 0:05.41, compared with 0:02.57 for Test 3.4 and 0:06.21 for Test 8.1 (PDF).

8.5 bib2gls: 20/1000 (entries and abbreviations) location check

This example is as Test 8.4, but instead of saving information in the aux file, it simply tests if the location field has been set. Note that in this case \testloop is performed before the start of the document instead of at the end of the document.

\documentclass{article}

\usepackage[abbreviations,record,postdot]{glossaries-extra}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000}]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}
\newcommand{\testloop}{%
 \global\advance\usedlastruncount by 1\relax
 \forallglsentries{\thisentry}%
 {%
  \glsxtrifhasfield{location}{\thisentry}%
  {%
   \ifdefempty\entriesusedlastrun
   {\global\let\entriesusedlastrun\thisentry}%
   {\xappto\entriesusedlastrun{,\thisentry}}%
  }{}%
 }
}

\testloop

\begin{document}
\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc82
bi2gls --group test-doc82
pdflatex test-doc82

The total build time was 0:02.71, compared with 0:02.57 for Test 3.4 and 0:05.41 for Test 8.4 (PDF).

8.6 bib2gls: 20/1000 (entries and abbreviations) record count

This example is as Test 8.5, but uses record counting instead of checking the location field. The document build requires that bib2gls is invoked with the --record-count (or -c) switch. This will save the record count in the recordcount field. The \testloop command is defined in this case.

\documentclass{article}

\usepackage[abbreviations,record,postdot]{glossaries-extra}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\newcommand*{\bibglssettotalrecordcount}[2]{%
  \GlsXtrSetField{#1}{recordcount}{#2}%
  \ifnum#2>0\relax 
   \advance\usedlastruncount by 1\relax
   \ifdefempty\entriesusedlastrun
   {\def\entriesusedlastrun{#1}}%
   {\appto\entriesusedlastrun{,#1}}%
  \fi
}

\GlsXtrLoadResources[src={entries-1000,abbreviations-1000}]

\newcount\entryindex
\newcommand{\test}[2]{%
  \entryindex=0\relax
  \loop
   \gls{#1\number\entryindex}.
   \advance\entryindex by 1\relax
  \ifnum\entryindex<#2
  \repeat
}

\begin{document}
\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\test{entry}{20}
\test{abbrv}{20}

\test{entry}{20}
\test{abbrv}{20}

\newpage
\test{entry}{10}
\test{abbrv}{10}

\newpage
\test{entry}{5}
\test{abbrv}{5}

\newpage
\test{entry}{3}
\test{abbrv}{3}

\newpage
\test{entry}{2}
\test{abbrv}{2}

\newpage
\test{entry}{20}
\test{abbrv}{20}

\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc83
bi2gls --group --record-count test-doc83
pdflatex test-doc83

The total build time was 0:02.78, compared with 0:02.57 for Test 3.4 and 0:02.71 for Test 8.5 (PDF).

8.7 makeglossaries (makeindex): cross-references (minimum 32/6000)

This example is like Test 7.1, but with the extra commands to save information in the aux file:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makeglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\expandafter\glsseelist\expandafter{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printglossaries
\end{document}

As with Test 7.1, a total of four iterations are needed to fully resolve all references, but one final LaTeX call is required to ensure that the last used information is correct:

pdflatex test-doc84
makeglossaries test-doc84
pdflatex test-doc84
makeglossaries test-doc84
pdflatex test-doc84
makeglossaries test-doc84
pdflatex test-doc84
makeglossaries test-doc84
pdflatex test-doc84

The total build time was 1:06.25, compared with 0:54.51 for Test 7.1 (PDF).

8.8 makeglossaries (xindy): cross-references (minimum 32/6000)

This example is like Test 7.2, but with the extra commands to save information in the aux file. The document is the same as for Test 8.7 but uses the xindy package option.

As before, a total of four iterations are needed to fully resolve all references, and one final LaTeX call is required to ensure that the last used information is correct:

pdflatex test-doc85
makeglossaries test-doc85
pdflatex test-doc85
makeglossaries test-doc85
pdflatex test-doc85
makeglossaries test-doc85
pdflatex test-doc85
makeglossaries test-doc85
pdflatex test-doc85
pdflatex test-doc85

The total build time was 1:17.87, compared with 1:04.61 for Test 7.2 (PDF).

8.9 \makenoidxglossaries: cross-references (minimum 32/6000)

This example is like Test 7.3, but with the extra commands to save information in the aux file:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makenoidxglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\expandafter\glsseelist\expandafter{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printnoidxglossaries
\end{document}

As before, a total of four iterations are needed to fully resolve all references, but one final LaTeX call is needed to ensure the last used information is correct:

pdflatex test-doc86
pdflatex test-doc86
pdflatex test-doc86
pdflatex test-doc86
pdflatex test-doc86

The total build time was 1:05.77, compared with 0:53.86 for Test 7.3 (PDF).

8.10 bib2gls: cross-references (minimum 32/6000)

This example is like Test 7.4, but with the extra commands to save information in the aux file:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printunsrtglossaries
\end{document}

The document build requires two bib2gls calls to ensure that the location lists are correct. All the dependent entries are found on the first call, but their locations can’t be determined until they are recorded when the glossary is typeset. Since all entries are present following the first bib2gls call, they will all be added to the aux file on the second LaTeX call, so \entriesusedlastrun will be up-to-date by the third LaTeX call.

pdflatex test-doc87
bib2gls -g test-doc87
pdflatex test-doc87
bib2gls -g test-doc87
pdflatex test-doc87

As with Test 8.4, the list of last used entries is in alphabetical order.

The total build time was 0:07.17, compared with 0:06.98 for Test 7.4 (PDF).

8.11 bib2gls: cross-references (minimum 32/6000) location field

This example is like Test 8.10, but the location field is tested instead of saving information in the aux file.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}
\newcommand{\testloop}{%
 \global\advance\usedlastruncount by 1\relax
 \forallglsentries{\thisentry}%
 {%
  \glsxtrifhasfield{location}{\thisentry}%
  {%
   \ifdefempty\entriesusedlastrun
   {\global\let\entriesusedlastrun\thisentry}%
   {\xappto\entriesusedlastrun{,\thisentry}}%
  }{}%
 }
}

\testloop

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc88
bib2gls -g test-doc88
pdflatex test-doc88
bib2gls -g test-doc88
pdflatex test-doc88

The total build time was 0:07.22, compared with 0:06.98 for Test 7.4 and 0:07.17 for Test 8.10 (PDF).

8.12 bib2gls: cross-references (minimum 32/6000) record count

This example is like Test 8.11, but record counting is used.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\newcommand*{\bibglssettotalrecordcount}[2]{%
  \GlsXtrSetField{#1}{recordcount}{#2}%
  \ifnum#2>0\relax
   \advance\usedlastruncount by 1\relax
   \ifdefempty\entriesusedlastrun
   {\def\entriesusedlastrun{#1}}%
   {\appto\entriesusedlastrun{,#1}}%
  \fi
}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{50}{600}

\chapter{Second}
\test{600}{5}{700}

\backmatter
\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc89
bi2gls --group --record-count test-doc89
pdflatex test-doc89
bi2gls --group --record-count test-doc89
pdflatex test-doc89

The total build time was 0:07.23, compared with 0:06.98 for Test 7.4 and 0:07.17 for Test 8.10 (PDF).

8.13 bib2gls: cross-references (minimum 32/6000) record count excluding glossary

This example is like Test 8.12, but locations within the glossary are suppressed (Test 7.5)

\GlsXtrSetDefaultNumberFormat{glsignore}
\printunsrtglossaries

This now only requires one bib2gls call. As with the previous example, when --record-count is used, this example will list the 32 entries that are referenced in the main document plus the 7 cross-references that only occur in the document. This is because, by default, the record count includes ignored records.

With bib2gls v3.0+, it’s possible to exclude the ignored records from the count:

pdflatex test-doc90
bib2gls --group --record-count-rule non-ignored test-doc90
pdflatex test-doc90
If you prefer short switches:
pdflatex test-doc90
bib2gls -g -r n test-doc90
pdflatex test-doc90
This will now only list the 32 entries that are referenced in the main document.

The total build time was 0:04.04, compared with 0:06.98 for Test 7.4 and 0:07.17 for Test 8.10 (PDF).

8.14 makeglossaries (makeindex): cross-references (minimum 4000/6000)

This example is like Test 7.6, but with the extra commands to save information in the aux file:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\makeglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\expandafter\glsseelist\expandafter{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printglossaries
\end{document}
A similar bash script to that for Test 7.1 was used. In this case, there were three iterations in the loop, but an additional LaTeX call is required to ensure that \entriesusedlastrun is up-to-date. The document build is therefore:
pdflatex test-doc84big
makeglossaries test-doc84big
pdflatex test-doc84big
makeglossaries test-doc84big
pdflatex test-doc84big
makeglossaries test-doc84big
pdflatex test-doc84big
pdflatex test-doc84big

The total build time was 8:36.02, compared with 0:53.27 for Test 7.6 (PDF).

8.15 makeglossaries (xindy): cross-references (minimum 4000/6000)

This example is like Test 7.7, but with the extra commands to save information in the aux file. The document is the same as for Test 8.14 but uses the xindy package option and, as with Test 7.7, it needs to ensure unique sort values:

\usepackage[xindy]{glossaries}

\renewcommand*{\glsprestandardsort}[3]{%
  \edef#1{#1.#3}%
  \glsdosanitizesort
}

The document build is as for Test 8.14:

pdflatex test-doc85big
makeglossaries test-doc85big
pdflatex test-doc85big
makeglossaries test-doc85big
pdflatex test-doc85big
makeglossaries test-doc85big
pdflatex test-doc85big
pdflatex test-doc85big

The total build time was 8:48.99, compared with 1:12.82 for Test 7.7 (PDF).

8.16 \makenoidxglossaries: cross-references (minimum 4000/6000)

This example is like Test 7.8, but with the extra commands to save information in the aux file:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage{glossaries}

\providecommand{\sortmethod}{def}

\makenoidxglossaries
\loadglsentries{xrentries}

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\expandafter\glsseelist\expandafter{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printnoidxglossary[sort=\sortmethod]
\end{document}

The document build required to fully resolve all references and ensure that \entriesusedlastrun is up-to-date:

pdflatex test-doc86big
pdflatex test-doc86big
pdflatex test-doc86big
pdflatex test-doc86big
pdflatex "\def\sortmethod{standard}\input test-doc86big"

Since Test 7.8 was aborted at 12h 24m, there was no point running this test. The impact of saving and retrieving information in the aux file is negligible compared to the length of time taken to sort the entries.

8.17 bib2gls: cross-references (minimum 4000/6000)

This example is like Test 7.9, but with the extra commands to save information in the aux file:

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\makeatletter
\newcommand{\@entry@used}[1]{%
 \global\advance\usedlastruncount by 1\relax
 \ifdefempty\entriesusedlastrun
 {\gdef\entriesusedlastrun{#1}}%
 {\gappto\entriesusedlastrun{,#1}}%
}
\newcommand{\testloop}{\forallglsentries{\thisentry}%
 {\ifglsused{\thisentry}{\protected@write\@auxout{}{\string\@entry@used{\thisentry}}}{}}}
\makeatother

\AtEndDocument{\testloop}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printunsrtglossaries
\end{document}

The document build is as for Test 8.10:

pdflatex test-doc87big
bib2gls -g test-doc87big
pdflatex test-doc87big
bib2gls -g test-doc87big
pdflatex test-doc87big

As with Test 8.10, the list of last used entries is in alphabetical order.

The total build time was 3:19.61, compared with 0:53.17 for Test 7.9 (PDF).

8.18 bib2gls: cross-references (minimum 4000/6000) location field

This example is like Test 8.17, but the location field is tested instead of saving information in the aux file.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}
\newcommand{\testloop}{%
 \global\advance\usedlastruncount by 1\relax
 \forallglsentries{\thisentry}%
 {%
  \glsxtrifhasfield{location}{\thisentry}%
  {%
   \ifdefempty\entriesusedlastrun
   {\global\let\entriesusedlastrun\thisentry}%
   {\xappto\entriesusedlastrun{,\thisentry}}%
  }{}%
 }
}

\testloop

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc88big
bib2gls -g test-doc88big
pdflatex test-doc88big
bib2gls -g test-doc88big
pdflatex test-doc88big

The total build time was 1:31.06, compared with 0:53.17 for Test 7.9 and 3:19.61 for Test 8.17 (PDF).

8.19 bib2gls: cross-references (minimum 4000/6000) record count

This example is like Test 8.18, but record counting is used.

\documentclass{book}

\usepackage[colorlinks]{hyperref}
\usepackage[record]{glossaries-extra}

\newcount\usedlastruncount
\newcommand{\entriesusedlastrun}{}

\newcommand*{\bibglssettotalrecordcount}[2]{%
  \GlsXtrSetField{#1}{recordcount}{#2}%
  \ifnum#2>0\relax
   \advance\usedlastruncount by 1\relax
   \ifdefempty\entriesusedlastrun
   {\def\entriesusedlastrun{#1}}%
   {\appto\entriesusedlastrun{,#1}}%
  \fi
}

\GlsXtrLoadResources[src={xrentries}]

\newcount\entryindex
\newcommand{\test}[3]{%
  \entryindex=#1\relax
  \loop
   \gls{xrentry\number\entryindex}.
   \advance\entryindex by #2\relax
  \ifnum\entryindex<#3
  \repeat
}

\begin{document}
\frontmatter
\pagenumbering{roman}
\chapter{Recap}

\ifdefempty\entriesusedlastrun
{No entries used last run.}
{\number\usedlastruncount\space entries used last run: 
\glsxtrseelist{\entriesusedlastrun}.}

\mainmatter
\pagenumbering{arabic}

\chapter{First}
\test{0}{1}{2000}

\chapter{Second}
\test{4000}{1}{6000}

\backmatter
\printunsrtglossaries
\end{document}

The document build is:

pdflatex test-doc89big
bi2gls --group --record-count test-doc89big
pdflatex test-doc89big
bi2gls --group --record-count test-doc89big
pdflatex test-doc89big

The total build time was 1:35.14, compared with 0:53.17 for Test 7.9 and 3:19.61 for Test 8.17 (PDF).

8.20 bib2gls: cross-references (minimum 4000/6000) record count excluding glossary

This example is like Test 8.19, but locations within the glossary are suppressed (Test 7.10)

\GlsXtrSetDefaultNumberFormat{glsignore}
\printunsrtglossaries

The document build is as for Test 8.13:

pdflatex test-doc90big
bib2gls --group --record-count-rule non-ignored test-doc90big
pdflatex test-doc90big

The total build time was 0:47.19, compared with 0:53.17 for Test 7.9 and 3:19.61 for Test 8.17 (PDF).

Summary

  1. If you only have ASCII sort values, then makeindex is the fastest method if you want an alphabetical list of all defined entries for simple documents that don’t have complex cross-references. If you can’t work out how to integrate makeindex into your document build, use the automake package option.
  2. Cross-reference trails work best with bib2gls. With other methods, the document build complexity can increase significantly.
  3. The \makenoidxglossaries method should not be used for alphabetical sorting for a large number of entries. Test 7.3 took approximately 54 seconds to sort 39 entries, Test 1.8 took approximately 11 minutes to sort 100 entries, and Test 7.8, which had 4,207 entries, was aborted at 12h 24m.
  4. If you have non-ASCII sort values that consist of words or phrases and you want the terms ordered according to a particular locale’s alphabet, then use xindy or bib2gls.
  5. If the sort value consists solely of LaTeX commands, then the best method is bib2gls if bib2gls can convert the commands into the best matching Unicode characters or if another field (such as description) may be used as a more appropriate sort value (see Gallery: Sorting). Otherwise consider ordering by definition or use a helper command, like the example \newsymbol, to make it easier to assign the sort key to the label or description.
  6. If you’re sorting by order of use, the best methods are using bib2gls or using TeX (\makenoidxglossaries) but don’t have order of use with hierarchical entries as they are incompatible.
  7. If you don’t want to use an external tool, the simplest method is to define your terms in the required order (and only define the terms that are required in the document) and use \printunsrtglossary with glossaries-extra. Note that this won’t create any location lists.
  8. If you want to have a large file (or set of files) containing all the terms that you might need in any of your documents, then the best method is to use bib2gls with glossaries-extra. This is more efficient in terms of the document build time.
  9. If you have abbreviations then, with just the base glossaries package, use \setacronymstyle (to switch to the newer acronym mechanism) or, with the extension glossaries package, use \newabbreviation (rather than \newacronym).

History

Version 2 (2022-06-18)

This document was updated to add Section 7 and Section 8. All test documents were rebuilt with glossaries.sty v4.49, glossaries-extra.sty v1.48 and bib2gls v3.0.

Version 1 (2019-09-10)

The original document had tests compiled with TeX Live 2017, glossaries.sty v4.35, glossaries-extra.sty v1.27 and bib2gls v1.2. A summary of all build times from the previous version of this document are listed in Table H1.
Table H1: Summary of V1 Results
Test Build time (minutes:​seconds)
1.10:02.31
1.20:02.47
1.30:02.22
1.40:02.22
1.50:03.84
1.60:02.97
1.70:03.66
1.810:41.13
1.90:02.86
1.100:04.46
1.1110:29.05
1.120:03.07
1.130:04.16
1.140:03.51
1.150:05.57
1.160:04.77
1.1710:22.21
1.1810:15.07
1.190:06.76
1.200:05.76
1.210:07.13
1.2210:13.18
1.230:04.63
2.10:02.30
2.20:02.28
2.30:02.28
2.40:02.33
2.5failed
2.60:03.75
2.70:03.85
2.80:03.77
2.90:03.70
2.100:03.82
2.1110:31.03
2.1210:27.78
2.1310:29.45
2.1410:48.98
2.1510:48.40
2.160:03.20
2.170:03.15
2.180:03.30
2.190:03.35
2.200:03.26
3.10:05.30
3.20:07.16
3.30:05.06
3.40:02.30
3.50:05.28
3.60:07.12
3.70:05.11
3.80:02.32
3.90:02.45
4.10:02.27
4.20:03.69
4.30:03.08
4.40:01.53
4.50:02.90
5.10:05.01
5.20:05.65
5.30:04.93
5.40:02.19
6.10:00.73
6.20:00.59
6.30:00.67
6.40:00.58
6.50:00.58
6.60:00.64
6.70:00.64
6.8failed
6.90:00.88
6.100:00.89
6.110:00.94
6.120:00.94
6.130:01.07
6.140:00.91
6.150:01.73
6.160:00.84
6.170:00.87
6.180:00.89
6.190:01.33
6.200:00.48
6.210:00.57
6.220:01.35
6.230:01.33
6.240:01.34
6.250:01.49
6.260:01.33
6.270:01.35
6.280:01.38
6.290:01.21

© 2018 Dickimaw Books. "Dickimaw", "Dickimaw Books" and the Dickimaw parrot logo are trademarks. The Dickimaw parrot was painted by Magdalene Pritchett.

Terms of Use Privacy Policy Cookies Site Map FAQs