summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/tensor/tensor.dtx
blob: 0bdad9e620f90fbb77d399fb887caf26b50d7acf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
% \iffalse meta-comment
%
%% File: tensor.dtx
%%
% Copyright (C) 2023 Philip G. Ratcliffe <philip.ratcliffe@uninsubria.it>
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    http://www.latex-project.org/lppl.txt
%
% This file is part of the "tensor package" (the Work in LPPL)
% and all files in that package must be distributed together.
%
% The released version of this package is available from CTAN.
%
% This package has the LPPL maintenance status "maintained".
%
% The current maintainer of this package is Philip G. Ratcliffe.
%
% \fi
%
% \iffalse
%
%<package>\NeedsTeXFormat{LaTeX2e}[1995/12/01]
%<package>\ProvidesPackage{tensor}
%<package>   [2023/07/18 v2.2 tensor indices package (PGR)]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{tensor}
\NewDocElement[macrolike=false]{Argument}{argument}
\NewDocElement[macrolike=false]{Option}{option}
%
\CodelineIndex
\EnableCrossrefs
\RecordChanges
\DoNotIndex{\let,\def,\gdef,\newcommand,\renewcommand}
\DoNotIndex{\if,\else,\fi,\ifx,\fi,\iffalse,\fi,\iftrue,\fi}
\DoNotIndex{\@empty,\expandafter,\makebox,\relax,\string,\the,\z@}
\DoNotIndex{\MessageBreak,\on@line}
%
\begin{document}
  \DocInput{tensor.dtx}
\end{document}
%</driver>
% \fi
%
% \CheckSum{342}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{v1.0}{1996/06/03}{original version}
% \changes{v2.0}{2004/04/01}{extended \cs{tensor}, added \cs{indices} and
%   \cs{nuclide}, substituted \cs{newcommand} with \cs{DeclareRobustCommand} in
%   user commands, documented and packaged}
%
% \GetFileInfo{tensor.sty}
%
% \DoNotIndex{\CodelineIndex,\EnableCrossrefs,\RecordChanges}
%
% \title{%
%   The \textsf{tensor}\relax
%   \,\thanks{%
%     Based on and extending the original package of the same name by Mike Piff
%     (1996/06/03).}
%   \space
%   package for \LaTeX2e
% }
% \author{%
%   Philip G. Ratcliffe\relax
%   \,\thanks{E-mail: \textsf{philip.ratcliffe@uninsubria.it}}
% \\
%   Dipartimento di Scienza e Alta Tecnologia
% \\
%   Universit\`a degli Studi dell'Insubria---Como
% }
%
% \date{(\fileversion, last revision \filedate)}
%
% \maketitle
%
% \begin{abstract}
% This is a complete revision and extension of Mike Piff's original |tensor|
% package; it defines two commands for typesetting tensors with mixed upper and
% lower indices in which the correct horizontal spacing must be observed.
% Various forms of alignment are available and spaces may be replaced by dots
% or other symbols. Consistent preposing of indices is now made possible while
% backwards compatibility is maintained. A special-purpose command to typeset
% nuclides is also defined.
% \end{abstract}
%
% \section{Introduction}
%
% It is common in both physics and mathematics to use tensors with mixed upper
% and lower indices in which the relative horizontal positions and spacing are
% significant, for example
% \begin{displaymath}
%   \Gamma\indices{^\mu_{\nu\rho}},\quad R\indices{^\mu_\nu^\rho_\sigma}
%   \quad\mathrm{or}\quad
%   \epsilon\indices{^\mu^\nu^\rho_\sigma}.
% \end{displaymath}
% The macros defined in this package automatically maintain consistent
% horizontal positioning. Another common need addressed is the
% preposing of upper and lower indices, as in
% \begin{displaymath}
%   \tensor
%     [_{\rm H}]
%     {\langle q',t' \vert \mathcal{U}(t,t') \vert q,t\rangle}
%     {_{\rm H}}
%   \quad\mathrm{or}\quad
%   \nuclide[14][6]{C}.
% \end{displaymath}
% Note the correct spacing of the pre-index H in the above example. It should
% also be noted that constant vertical positioning is maintained for lone
% indices; consider the following (examine carefully the last lower index $o$
% on the right):
% \begin{displaymath}
%   {\rm M}\indices*{^o_o} \vert \tensor[_o]{{\rm M}}{}
%   \quad\mbox{\emph{cf.}}\quad
%   {\rm M}^o_o \vert _o{\rm M},
% \end{displaymath}
% where the former group was typeset using \cs{indices}, the latter using `|_|'
% and `|^|'.
%
% \section{Usage}
%
% Two robust math-mode commands, \cs{tensor} and \cs{indices}, are defined (the
% first of which remains backwards compatible with Mike Piff's original
% definition). A new, robust text- and math-mode command, \cs{nuclide}, is also
% defined specifically for typesetting nuclides, as in the above example.
%
% \subsection{User commands}
%
% \DescribeMacro{\indices}
% To produce a mathematical expression (typically a tensor) with mixed upper
% and lower indices, simply enter
% \meta{object}|\indices{|%
%   |^|\meta{sup$_{\,1}$}|_|\meta{sub$_{\,1}$}%
%   |^|\meta{sup$_{\,2}$}|_|\meta{sub$_{\,2}$}%
% \dots|}|.
% Thus, in math mode it is sufficient to type \emph{e.g.}
% \begin{center}
%   |M\indices{^a_b^{cd}_e}|\quad to obtain\quad
%   $M\indices{^a_b^{cd}_e}$.
% \end{center}
%
% \DescribeMacro{\tensor}
% This variant has been retained in a completely backwards compatible form
% while also being considerably extended; the syntax for the previous
% expression is |\tensor{M}{^a_b^{cd}_e}|, for which the resulting output is
% identical. The extended form of \cs{tensor} defined here has an optional
% argument for indices to be placed \emph{before} the tensor, thus:
% \begin{center}
%   |\tensor[^a_b^c_d]{M}{^e_f^g_h}|\quad produces\quad
%   $\tensor[^a_b^c_d]{M}{^e_f^g_h}$.
% \end{center}
% A fairly robust (if somewhat crude) attempt is made to ensure the correct
% spacing and skew of the preposed indices with respect to the tensor object
% itself.
%
% Note that also \cs{sb} and \cs{sp} may be used in place of `|_|' and `|^|'
% respectively for both the above macros.
%
% \DescribeMacro{\indices*}
% \DescribeMacro{\tensor*}
% These two macros have starred forms, which collapse the spacing (\emph{i.e.}
% return to standard form). While \cs{indices*} is clearly redundant (and is
% included merely for symmetry), \cs{tensor*} also \emph{right} justifies the
% \emph{pre}-index strings, so that \emph{e.g.} nuclides may be typeset as
% follows (though see below for a purpose-built command):
% \begin{center}
%   |\tensor*[^{14}_6]{\mathrm{C}}{}|\quad produces\quad
%   $\tensor*[^{14}_6]{\mathrm{C}}{}$.
% \end{center}
% For those familiar with the |amsmath| package, this is more-or-less a
% generalisation of (though \emph{not intended} as a substitute for) the
% \cs{sideset} command (which itself is \emph{only valid} for objects defined
% with \cs{mathop}). Note that to use \cs{tensor*} as a substitute for
% \cs{sideset}, it is necessary to insert a \cs{nolimits} command, thus:
% \begin{center}
%   |\tensor*[^*_*]{\prod\nolimits}{^*_*}|\quad produces\quad
%   $\displaystyle\tensor*[^*_*]{\prod\nolimits}{^*_*}$.
% \end{center}
% The output appears identical to that of |\sideset{_*^*}{_*^*}{\prod}|.
%
% \DescribeArgument{*}
% The \cs{indices*} and \cs{tensor*} forms \emph{alone}, allow a |*| to also be
% placed as the first entry in either index-list argument, causing alignment
% (\emph{left} justification) of the successive pairs of upper and lower
% indices. A warning is issued if a |*| appears in an argument string of either
% \emph{non}-starred commands. Thus,
% \begin{center}
%   |\tensor*{M}{*^{i_1}_{m_1}^{i_2}_{m_2}^{i_3}_{m_3}^{i_4}_{m_4}}|
% \\[2ex]
%   produces\hspace{\stretch{2}}
%   $\tensor*{M}{*^{i_1}_{m_1}^{i_2}_{m_2}^{i_3}_{m_3}^{i_4}_{m_4}}$\quad
%   (\emph{cf.} $M^{i_1i_2i_3i_4}_{m_1m_2m_3m_4}$).
%   \hspace*{\stretch{2}}
% \end{center}
% Note that \emph{no warning} is issued for improper pairing of successive
% indices.
%
% \DescribeMacro{\indexmarker}
% In analogy with the |tensind| package, the command \cs{indexmarker} (by
% default empty) may redefined (using \cs{renewcommand}) to introduce a visible
% place marker for the index spaces (though not all |tensind| functionality is
% reproduced here); a simple possibility is
% \begin{center}
% \vspace*{-2ex}
% |\renewcommand\indexmarker{\cdot}|,
% \\
%   after which,\hspace*{\stretch{2}}
% \\
%   |\tensor{M}{^a_b^c_d}|
% \\[1ex]
%   produces\hspace*{\stretch{2}}\null
% \\
%   $\renewcommand\indexmarker{\cdot}\tensor{M}{^a_b^c_d}$\quad instead of\quad
%   $\tensor{M}{^a_b^c_d}$\,.
% \end{center}
%
% \DescribeMacro{\nuclide}
% This command, available in both math and text modes, is defined with the same
% purpose and result as the \cs{isotope} command (from the package of the same
% name). The syntax is
% \begin{center}
%   |\nuclide[|\meta{mass no.}|][|\meta{atomic no.}|]{|\meta{symbol}|}|.
% \end{center}
% Thus, the earlier example of $\nuclide[14][6]{C}$ is obtained with
% |\nuclide[14][6]{C}| while |\nuclide[4][2]{\alpha}| gives
% $\nuclide[4][2]{\alpha}$. As indicated by the square brackets, the
% \meta{mass no.} and \meta{atomic no.} arguments are optional. Note that there
% is a little more space (|1mu|) between the numbers and the chemical symbol
% than appears in the example constructed manually with \cs{tensor*}.
%
% All the above-defined commands may be used recursively, \emph{i.e.} a
% \cs{tensor} may occur as an index to another \cs{tensor} and should behave
% according to the current superscript--subscript level. The user commands are
% defined here as `robust'; they may thus appear as so-called moving arguments,
% \emph{i.e.} to \cs{caption}, \cs{section} \emph{etc}.
%
% \DescribeMacro{\nuclideFont}
% \DescribeMacro{\massnumFont}
% By default, the fonts used in \cs{nuclide} for the chemical symbol, mass and
% atomic numbers are \cs{mathrm}; \emph{i}.\emph{e}., \cs{nuclideFont} (for the
% chemical symbol) is initially defined as \cs{mathrm} and \cs{massnumFont}
% (for the mass/atomic numbers) as \cs{nuclideFont} (for backwards
% compatibility). This then now allows for independent font variation of the
% chemical symbol and mass/atomic numbers. Both macros may be reset with
% \cs{renewcommand} to \cs{mathsf}, \cs{mathbf}, \cs{mathtt} \emph{etc}., or
% simply \cs{relax} (this last for \cs{nuclideFont} has the chemical symbol
% font default to \cs{mathit} for correct spacing, while for \cs{massnumFont}
% the mass and atomic numbers revert to standard math font).
%
% \subsection{Package options}
%
% As of v2.2, the package includes four options relating to the vertical
% alignment of indices. \LaTeX's behaviour in this regard is not always optimal
% or what the user may desire. Consider the following output (constructed using
% `|_|' and `|^|'.):
% \begin{displaymath}
%   \epsilon\indices{^\mu_\rho^\nu_{\tilde\lambda}} \;
%   g\indices{^\mu^\nu} \,.
% \end{displaymath}
% While the indices within each single mathematical object are mutually
% vertically aligned correctly, between separate objects they may not be. This
% is because \LaTeX\ sets the baseline according to the height and depth of the
% given indices on a per-object basis. To obviate such behaviour, this package
% takes the simplest route of using \cs{smash} to hide the height and depth of
% each superscript and subscript string so that they are always set with the
% same baselines. This naturally leads to a somewhat cramped form (superscripts
% are set a little too low and subscripts high) and so a specially defined
% \cs{strut} is included, which slightly raises superscripts and lowers
% subscripts; by default, this is only implemented in displayed math, as the
% impact on inline text may be too disruptive.
%
% \DescribeOption{align}
% \DescribeOption{text}
% \DescribeOption{nosmash}
% \DescribeOption{nostrut}
% The options thus introduced are |align|, |text|, |nosmash| and |nostrut|. The
% first implements both \cs{smash} and a \cs{strut} as outlined above, with
% |text| extending the implementation of the \cs{strut} to inline text, while
% |nosmash| and  |nostrut| cancel the single effects (using both entirely
% negates |align|). Option ordering is irrelevant and the last three are
% inoperative without the first.
%
% The desired effects are implemented via two internal commands, which may also
% be redefined by the user.
% \DescribeMacro{\tensorSmash}
% The first, \cs{tensorSmash}, is set equal to \cs{smash}, which then takes each
% index string as an argument.
% \DescribeMacro{\tensorStrut}
% The second, \cs{tensorStrut}, is set equal to the height of `|l|' and depth
% of `|j|' in the relevant font, (by default though only inside displayed math
% environments) and is appended to each \cs{smash}'ed index string.
%
% \subsection{Caveats}
%
% Grouping of multi-token indices should be performed as normal (\emph{i.e.}
% via enclosure within a brace pair |{|\,|}|). Moreover, owing to the method by
% which index strings are parsed, any index constructs such as |\mathrm{H}|
% must also be entirely enclosed in braces, thus: |\indices{_{\mathrm{H}}^x}|.
%
% Spacing is not guaranteed to always appear optimal, especially when between
% \emph{pre}-pended indices and the tensor object itself. Recall too that
% screen viewing often distorts small spaces owing to resolution effects.
%
% \subsection{External package requirements}
%
% No external packages are required or called.
%
% \subsection{Package conflicts}
%
% There are few conflicts with standard \LaTeX2e\ packages; a problem with the
% |color| package in the first version has now been corrected, as too a
% recently flagged problem with the |underscore| package.
%
% However, the macros defined here fail as arguments of \cs{bm} from the |bm|
% package (due to parsing conflicts) or, consequently, of macros defined by the
% \cs{maybebm} package. A work around for, say, a chapter or section header is
% \begin{center}
%   |{\let\nuclideFont\maybebm \nuclide[4][2]{\textup{He}}}|,
% \end{center}
% which should render \nuclide[\mathbf4][\mathbf2]{\textbf{He}} in the header,
% but \nuclide[4][2]{\textup{He}} in the contents listing.
%
% \StopEventually{\PrintChanges\PrintIndex}
%
% \section{Implementation}
%
% \subsection{User options}
%
% First, the package options with their related \cs{if}\dots\ conditionals are
% defined and processed.
%    \begin{macrocode}
\newif\iftnsr@Aln
\DeclareOption{align}{\tnsr@Alntrue}
\newif\iftnsr@Txt
\DeclareOption{text}{\tnsr@Txttrue}
\newif\iftnsr@Sma \tnsr@Smatrue
\DeclareOption{nosmash}{\tnsr@Smafalse}
\newif\iftnsr@Str \tnsr@Strtrue
\DeclareOption{nostrut}{\tnsr@Strfalse}
\ProcessOptions
%    \end{macrocode}
%
% \subsection{User commands}
%
% The |tensor| package defines three basic user commands:
% \begin{macro}{\tensor}
% The first takes three possible arguments (an optional index string to be
% \emph{preposed}, the tensor object, the index string) and also has a starred
% form, which suppresses spacing (it is backwards compatible with Mike Piff's
% original version).
%    \begin{macrocode}
\DeclareRobustCommand\tensor{%
  \tnsr@Prp
  \@ifstar{\tnsr@Spcfalse\tnsr@Aux}{\tnsr@Spctrue\tnsr@Aux}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\indices}
% The second is a `\emph{lightweight}' form, which is placed immediately
% \emph{following} the tensor object, takes just one argument (the index
% string) and also has a starred form (this form was \emph{not} however present
% in the original package).
% \changes{v2.1}{2004/12/20}{added starred form, for symmetry with
%   \cs{tensor*}}
%    \begin{macrocode}
\DeclareRobustCommand\indices{%
  \tnsr@Prp
  \@ifstar{\tnsr@Spcfalse\ndcs@Aux}{\tnsr@Spctrue\ndcs@Aux}%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\nuclide}
% This additional new command takes one direct argument (an optional mass
% number) and two indirect arguments (an optional atomic number, the chemical
% symbol---these last two are handled by an auxiliary macro). Since usage is
% common in text, math mode is ensured.
%    \begin{macrocode}
\DeclareRobustCommand\nuclide[1][]{%
  \ncld@Mno{#1}%
  \ncld@Aux
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\nuclideFont}
% \begin{macro}{\massnumFont}
% These set the fonts for \cs{nuclide}; the defaults are \cs{mathrm} for both
% \cs{nuclideFont} and \cs{massnumFont}. They may be redefined as \emph{e.g.}
% \changes{v2.2}{2023/07/18}{added independent mass/atomic-no.\ font control}
% \cs{mathsf}, \cs{mathbf}, \cs{mathtt}, \cs{mathit} \emph{etc}., or even
% simply \cs{relax} or \cs{renewcommand}\cs{nuclideFont}|{}|.
%    \begin{macrocode}
\newcommand\nuclideFont{\mathrm}
\newcommand\massnumFont{\nuclideFont}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Internal token registers}
%
% \begin{macro}{\tnsr@Sps}
% \begin{macro}{\tnsr@Sbs}
% \begin{macro}{\tnsr@Spe}
% \begin{macro}{\tnsr@Sbe}
% The token registers that hold the upper and lower index strings, and the most
% recent upper and lower index elements respectively:
%    \begin{macrocode}
\newtoks\tnsr@Sps
\newtoks\tnsr@Sbs
\newtoks\tnsr@Spe
\newtoks\tnsr@Sbe
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ncld@Mno}
% This token register temporarily holds the mass number for \cs{nuclide}.
%    \begin{macrocode}
\newtoks\ncld@Mno
%    \end{macrocode}
% \end{macro}
%
% \subsection{Internal switches}
%
% \begin{macro}{\iftnsr@Spc}
% The switch to select or suppress index element spacing.
%    \begin{macrocode}
\newif\iftnsr@Spc
%    \end{macrocode}
% \end{macro}
%
% \subsection{Internal macros}
%
% \begin{macro}{\tnsr@Prp}
% \begin{macro}{\tnsr@Wrn}
% Here we simply reset token registers and the warning macro before commencing.
%    \begin{macrocode}
\newcommand\tnsr@Wrn{}
\newcommand\tnsr@Prp{%
  \tnsr@Sps{}%
  \tnsr@Sbs{}%
  \def\tnsr@Wrn{}
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ndcs@Aux}
% This (lightweight) auxiliary macro for \cs{indices} takes one argument (an
% index string); it calls \cs{tnsr@Set}, prints the indices and then issues any
% warnings.
%    \begin{macrocode}
\newcommand\ndcs@Aux[1]{%
  \tnsr@Erx
  \def\tnsr@Obj{}%
  \tnsr@Set{#1}%
  \tnsr@Fin
  \tnsr@Wrn
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Aux}
% This auxiliary macro for \cs{tensor} takes three possible arguments (an
% optional pre-index string, the tensor object, the post-index string) and
% passes everything via \cs{mathpalette} to \cs{tnsr@Plt}.
%    \begin{macrocode}
\newcommand\tnsr@Aux[3][]{%
  \tnsr@Erx
  \mathpalette{\tnsr@Plt{#1}{#3}}{#2}%
  \tnsr@Wrn
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Plt}
% This takes four arguments (the pre-index string---may be empty, the
% post-index, the current math style, the tensor object) and calls
% \cs{tnsr@Set} separately for both pre- and post-index strings.
%    \begin{macrocode}
\newcommand\tnsr@Plt[4]{%
  \def\tnsr@Obj{#3#4}%
  \def\tnsr@Tmp{#1}%
  \ifx\tnsr@Tmp\@empty\else
    \tnsr@Set{#1}%
    \hphantom{{}\tnsr@Fin}%
    \tnsr@Sps\expandafter{%
      \expandafter\tnsr@Krn\expandafter{\the\tnsr@Sps}%
    }%
    \tnsr@Sbs\expandafter{%
      \expandafter\tnsr@Krn\expandafter{\the\tnsr@Sbs}%
    }%
  \fi
  \tnsr@Set{#2}%
  #4\tnsr@Fin
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Set}
% This takes one argument (a pre- or post-index string) and starts processing.
%    \begin{macrocode}
\newcommand\tnsr@Set[1]{%
  \let\tnsr@Swx\relax
  \tnsr@Pro#1\tnsr@Err
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Krn}
% This has one argument (a processed index string) and inserts the necessary
% offsets.
% \changes{v2.1}{2004/12/20}{slightly altered spacing}
%    \begin{macrocode}
\newcommand\tnsr@Krn[1]{%
  \settowidth\@tempdima{$\m@th\tnsr@Obj^{#1}\mkern-1mu$}%
  \kern-\@tempdima
  #1
  \settowidth\@tempdima{$\m@th\tnsr@Obj$}%
  \kern\@tempdima
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Pro}
% This is the index-string processing macro, it takes one argument (an index
% string):
% \changes{v2.2}{2023/07/18}{substituted \cs{ifx} with \cs{if} to avoid
%   \textsf{underscore} package conflict}
%    \begin{macrocode}
\newcommand\tnsr@Pro[1]{%
  \ifx#1\tnsr@Err
    \let\tnsr@Nxt\relax
  \else
    \if#1*
      \iftnsr@Spc
        \gdef\tnsr@Wrn{%
          \PackageWarning{tensor}{%
            '*' not allowed in argument here; I shall ignore it.%
            \MessageBreak Either remove it or use '\string\tensor*'%
          }%
        }%
      \else
        \let\tnsr@Swx\tnsr@Swa
      \fi
      \let\tnsr@Nxt\tnsr@Pro
    \else
      \if#1^
        \def\tnsr@Nxt{\tnsr@Add{\tnsr@Sps}{\tnsr@Sbs}{\tnsr@Spe}}%
      \else
        \if#1_
          \def\tnsr@Nxt{\tnsr@Add{\tnsr@Sbs}{\tnsr@Sps}{\tnsr@Sbe}}%
        \else
          \tnsr@Err
          \let\tnsr@Nxt\tnsr@Pro
        \fi
      \fi
    \fi
  \fi
  \tnsr@Nxt
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Swa}
% Here we flip the state of \cs{tnsr@Swx} to \cs{tnsr@Swb}.
%    \begin{macrocode}
\newcommand\tnsr@Swa{\let\tnsr@Swx\tnsr@Swb}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Swb}
% Here we flip the state of \cs{tnsr@Swx} to \cs{tnsr@Swa} then calculate and
% insert the necessary padding for horizontal index alignment.
%    \begin{macrocode}
\newcommand\tnsr@Swb{%
  \let\tnsr@Swx\tnsr@Swa
  \settowidth\@tempdima{$\m@th\tnsr@Obj{}^{\the\tnsr@Spe}$}%
  \settowidth\@tempdimb{$\m@th\tnsr@Obj{}_{\the\tnsr@Sbe}$}%
  \addtolength\@tempdima{-\@tempdimb}%
  \ifdim\@tempdima=\z@\else
    \ifdim\@tempdima>\z@
      \tnsr@Sbs\expandafter\expandafter\expandafter{%
        \expandafter\the\expandafter\tnsr@Sbs
        \expandafter\kern\the\@tempdima
      }%
    \else
      \@tempdima=-\@tempdima
      \tnsr@Sps\expandafter\expandafter\expandafter{%
        \expandafter\the\expandafter\tnsr@Sps
        \expandafter\kern\the\@tempdima
      }%
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Add}
% This macro takes four arguments (the token-register target for the next index
% token, the token-register target for the phantom element, the token-register
% target for the most-recent element, the next index token). It adds the next
% index token to the upper or lower string and (if spacing is \emph{on}) a
% place-holder (\cs{tnsr@Hph}) of the same size to the lower or upper string,
% respectively. It also calls \cs{tnsr@Swx} to flip state (if activated). The
% use of \cs{leavevmode} avoids conflict with the |color| package.
% \changes{v2.1}{2004/12/20}{added \cs{leavevmode}, to avoid \textsf{color}
%   package conflict}
%    \begin{macrocode}
\newcommand\tnsr@Add[4]{%
  #1\expandafter{\the#1\leavevmode{#4}}%
  \iftnsr@Spc
    #2\expandafter{\the#2\tnsr@Hph{#4}}%
  \fi
  #3{\leavevmode{#4}}%
  \tnsr@Swx
  \tnsr@Pro
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Hph}
% The place-holder macro, uses \cs{mathpalette} to call the contents
% \cs{tnsr@Mph}:
%    \begin{macrocode}
\newcommand\tnsr@Hph{\expandafter\mathpalette\expandafter\tnsr@Mph}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Mph}
% The place-holder macro contents:
% \changes{v2.1}{2004/12/20}{substituted \cs{hbox} with \cs{makebox}}
%    \begin{macrocode}
\newcommand\tnsr@Mph[2]{%
  \settowidth\@tempdima{$\m@th#1{#2}$}%
  \makebox[\@tempdima][c]{$\m@th#1\indexmarker$}%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\indexmarker}
% The default (blank) placeholder for index spacing:
% \changes{v2.1}{2004/12/20}{added capability to insert place holders}
%    \begin{macrocode}
\newcommand\indexmarker{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Fin}
% Finally, we put the index strings into place:
% \changes{v2.2}{2023/07/18}{added vertical alignment capability}
%    \begin{macrocode}
\newcommand\tnsr@Fin{%
  ^{\tensorSmash{\the\tnsr@Sps}\tnsr@Str}%
  _{\tensorSmash{\the\tnsr@Sbs}\tnsr@Str}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tensorSmash}
% Initialise \cs{tensorSmash} as \cs{relax} and then conditionally set it equal
% to \cs{smash} (it is user redefinable).
%    \begin{macrocode}
\let\tensorSmash\relax
\iftnsr@Aln
  \iftnsr@Sma
    \let\tensorSmash\smash
  \fi
\fi
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tensorStrut}
% \begin{macro}{\tnsr@Str}
% Initialise \cs{tensorStrut} as \cs{relax} and then conditionally set it to
% the height and depth of `|jl|'. By default, it is only applied to displayed
% math environments (passed on via \cs{tnsr@Str}, which is \cs{def}'ed  as
% \cs{tensorStrut} to be user redefinable), but always (\emph{i.e.} extended to
% inline text) if the package option |text| is present.
%    \begin{macrocode}
\newcommand\tensorStrut{}
\let\tnsr@Str\relax
\iftnsr@Aln
  \iftnsr@Str
    \renewcommand\tensorStrut{\vphantom{jl}}
    \iftnsr@Txt
      \def\tnsr@Str{\tensorStrut}
    \else
      \everydisplay\expandafter{\the\everydisplay\let\tnsr@Str\tensorStrut}
    \fi
  \fi
\fi
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ncld@Aux}
% This auxiliary macro takes two arguments (an optional atomic number and the
% chemical symbol). The mass number is passed on via \cs{ncld@Mno}. Math mode
% is ensured since usage is common in text. The spacing is increased by |1mu|
% for better appearance.
%    \begin{macrocode}
\newcommand\ncld@Aux[2][]{%
  \ensuremath{%
    \tensor*[^{\massnumFont{\the\ncld@Mno}}_{\massnumFont{#1}}]%
      {\mkern1mu{\mathit{\nuclideFont{#2}}{}}}{}%
  }%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Err}
% This is invoked in the only error situations considered.
%    \begin{macrocode}
\newcommand\tnsr@Err{}
\newcommand\tnsr@Erx{%
  \def\tnsr@Err{%
    \global\let\tnsr@Err\relax
    \PackageError{tensor}{%
      Misordered sub/superscript items\on@line;
      \MessageBreak index tokens may have been lost.
      \MessageBreak Press <return> and I shall try to continue%
    }{Index string probably has extra/missing '^' or '_'.}%
  }%
}
%    \end{macrocode}
% \end{macro}
%
% \Finale
%
\endinput
%%
%% End of file 'tensor.dtx'.