math-ali.mkiv /size: 52 Kb    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=math-ali,
3%D        version=2008.10.20,
4%D          title=\CONTEXT\ Math Macros,
5%D       subtitle=Math Alignments,
6%D         author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Math Macros / Math Alignments}
15
16\unprotect
17
18%D The code here has been moved from other files. Beware: the \MKII\ and \MKIV\ code
19%D is not gathered in files with the same name. In the meantime this code has been
20%D adapted to \MKIV\ but more is possible. The code is somewhat complicated by the
21%D fact that alignments are tricky with rspect to tagging.
22
23% export:
24%
25% alignment : ok
26% cases     :
27% matrix    : ok
28% substack  :
29
30%D \macros
31%D   {definemathalignment, setupmathalignment, startmathalignment}
32%D
33%D Modules may provide additional alignment features. The following mechanisms are
34%D provided by the core.
35
36\newtoks\t_math_align_a
37\newtoks\t_math_align_b
38\newtoks\t_math_align_c
39
40\newskip\d_math_eqalign_distance
41
42\unexpanded\def\math_eqalign_distance
43  {\relax
44   \ifdim\d_math_eqalign_distance>\zeropoint
45   % \hskip\d_math_eqalign_distance
46     \tabskip\d_math_eqalign_distance
47   \fi
48   \mathalignmentparameter\c!separator
49   \relax}
50
51\def\displayopenupvalue{.25\bodyfontsize}
52
53\def\math_build_eqalign
54  {\scratchtoks\emptytoks
55   \d_math_eqalign_distance\mathalignmentparameter\c!distance\relax
56   \scratchcounterone\mathalignmentparameter\c!m
57   \scratchcountertwo\mathalignmentparameter\c!n
58   \etoksapp\scratchtoks{\the\t_math_align_a}%
59   \scratchcounter\plusone
60   \dorecurse{\numexpr\scratchcounterone*\scratchcountertwo-\plusone\relax}
61     {\ifnum\scratchcounter=\scratchcountertwo
62        \scratchcounter\plusone
63        \etoksapp\scratchtoks{\math_eqalign_distance}%
64        \etoksapp\scratchtoks{\global\c_math_eqalign_column\zerocount}%
65      \else
66        \advance\scratchcounter\plusone
67      \fi
68      \etoksapp\scratchtoks{\the\t_math_align_b}}%
69   \etoksapp\scratchtoks{\the\t_math_align_c}}
70
71\def\math_math_in_eqalign#1%
72  {\startforceddisplaymath
73   \tabskip\zeropoint
74   \everycr\emptytoks
75   {{}#1{}}%
76   \stopforceddisplaymath}
77
78\def\math_text_in_eqalign#1%
79  {\startimath
80   \tabskip\zeropoint
81   \everycr\emptytoks
82   #1%
83   \stopimath}
84
85\def\eqalign#1% why no halign here, probably because of displaywidth
86  {\emptyhbox
87   \mskip\thinmuskip
88   \vcenter
89     {\math_openup\displayopenupvalue % was: \openup\jot
90      \mathsurround\zeropoint
91      \ialign{%
92        \strut
93        \hfil
94        \startforceddisplaymath{\alignmark\alignmark}\stopforceddisplaymath
95        \aligntab
96        \startforceddisplaymath{{}\alignmark\alignmark{}}\stopforceddisplaymath
97        \hfil\crcr
98        #1\crcr}%
99     }%
100   \mskip\thinmuskip}
101
102% preamble is scanned for tabskips so we need the span to prevent an error message
103
104\setnewconstant\eqalignmode\plusone
105
106% use zeroskipplusfill
107
108\def\math_prepare_r_eqalign_no
109  {\t_math_align_a
110     {\strut
111      \tabskip\zeropoint
112      \alignmark\alignmark % for picking up the number
113      \aligntab
114      \math_first_in_eqalign
115      \hfil
116      \math_left_of_eqalign
117      \span
118      \math_math_in_eqalign{\alignmark\alignmark}%
119      \math_right_of_eqalign
120      \tabskip\zeropoint}%
121   \t_math_align_b
122     {\aligntab
123      \math_next_in_eqalign
124      \math_left_of_eqalign
125      \span
126      \math_math_in_eqalign{\alignmark\alignmark}%
127      \math_right_of_eqalign
128      \tabskip\zeropoint}%
129   \ifnum\mathraggedstatus=\plusone
130     \t_math_align_c
131       {\hfil
132        \aligntab
133        \span
134        \math_text_in_eqalign{\alignmark\alignmark}%
135        \tabskip\zeropoint}%
136   \else\ifnum\mathraggedstatus=\plusthree
137     \t_math_align_c
138       {\hfil
139        \tabskip\zeropoint\s!plus 1\s!fill
140        \aligntab
141        \span
142        \math_text_in_eqalign{\alignmark\alignmark}%
143        \tabskip\zeropoint}%
144   \else
145     \t_math_align_c
146       {\hfil
147        \tabskip\centering
148        \aligntab
149        \span
150        \llap{\math_text_in_eqalign{\alignmark\alignmark}}%
151        \tabskip\zeropoint}%
152   \fi\fi
153   \math_build_eqalign
154   \the\mathdisplayaligntweaks
155   \tabskip\centering}
156
157\def\math_prepare_l_eqalign_no  % \checkeddisplaymath
158  {\t_math_align_a
159     {\strut
160      \tabskip\zeropoint
161      \alignmark\alignmark % for picking up the number
162      \aligntab
163      \math_first_in_eqalign
164      \hfil
165      \math_left_of_eqalign
166      \span
167      \math_math_in_eqalign{\alignmark\alignmark}%
168      \math_right_of_eqalign
169      \tabskip\zeropoint}%
170   \t_math_align_b
171     {\aligntab
172      \math_next_in_eqalign
173      \math_left_of_eqalign
174      \span
175      \math_math_in_eqalign{\alignmark\alignmark}%
176      \math_right_of_eqalign
177      \tabskip\zeropoint}%
178   \ifnum\mathraggedstatus=\plusone
179     \t_math_align_c
180       {\hfil
181        \aligntab
182        \kern-\displaywidth
183        \span
184        \rlap{\math_text_in_eqalign{\alignmark\alignmark}}%
185        \tabskip\displaywidth}%
186   \else\ifnum\mathraggedstatus=\plusthree
187     \t_math_align_c
188       {\hfil
189        \tabskip\zeropoint\s!plus 1\s!fill
190        \aligntab
191        \kern-\displaywidth
192        \span
193        \math_rlap{\math_text_in_eqalign{\alignmark\alignmark}}%
194        \tabskip\displaywidth}%
195   \else
196     \t_math_align_c
197       {\hfil
198        \tabskip\centering
199        \aligntab
200        \kern-\displaywidth
201        \span
202        \rlap{\math_text_in_eqalign{\alignmark\alignmark}}%
203        \tabskip\displaywidth}%
204   \fi\fi
205   \math_build_eqalign
206   \the\mathdisplayaligntweaks
207   \tabskip\centering}
208
209\def\math_halign_checked
210   {\halign \ifcase\eqalignmode \or to \checkeddisplaywidth \fi}
211
212\def\math_both_eqalign_no_normal#1#2%
213  {\ifmmode
214     \the\mathdisplayaligntweaks
215     \vcenter\bgroup
216     \let\math_finish_eqalign_no\egroup
217   \else
218     \let\math_finish_eqalign_no\relax
219   \fi
220   #1%
221   \math_halign_checked\expandafter\bgroup\the\scratchtoks\crcr#2\crcr\egroup
222   \math_finish_eqalign_no}
223
224\installcorenamespace {mathalignlocation}
225
226\setvalue{\??mathalignlocation\v!top   }{\let\math_alignment_halign_method\halign\tpack}
227\setvalue{\??mathalignlocation\v!bottom}{\let\math_alignment_halign_method\halign\vpack}
228\setvalue{\??mathalignlocation\v!center}{\let\math_alignment_halign_method\halign\vcenter}
229
230\def\math_both_eqalign_no_aligned#1%
231  {\let\math_alignment_halign_method\math_halign_checked
232   \ifmmode
233     \the\mathdisplayaligntweaks
234     \global\mathnumberstatus\plusone
235     \ifcase\mathraggedstatus
236       \def\math_finish_eqalign_no{\crcr\egroup}%
237     \else % we're in a mathbox
238       \ifcsname\??mathalignlocation\mathalignmentparameter\c!location\endcsname
239         \lastnamedcs % top|bottom|center as suggested by HM
240       \else
241         \vcenter
242       \fi
243       \bgroup
244       \def\math_finish_eqalign_no{\crcr\egroup\egroup}%
245     \fi
246   \fi
247   #1%
248   \math_alignment_halign_method\expandafter\bgroup\the\scratchtoks\crcr}
249
250\def\math_rlap#1%
251  {\setbox\scratchbox\hbox{#1}%
252   \ifdim\wd\scratchbox>\d_math_number_correction
253     \global\d_math_number_correction\wd\scratchbox
254   \fi
255   \box\scratchbox
256   \global\mathnumberstatus\plustwo}
257
258\def\math_handle_eqalign_no_r_normal {\math_both_eqalign_no_normal \math_prepare_r_eqalign_no}
259\def\math_handle_eqalign_no_l_normal {\math_both_eqalign_no_normal \math_prepare_l_eqalign_no}
260\def\math_handle_eqalign_no_r_aligned{\math_both_eqalign_no_aligned\math_prepare_r_eqalign_no}
261\def\math_handle_eqalign_no_l_aligned{\math_both_eqalign_no_aligned\math_prepare_l_eqalign_no}
262\def\math_finish_eqalign_no          {\crcr\egroup}
263
264\let\reqalignno\relax
265\let\leqalignno\relax
266\let\eqalignno \relax
267
268%D Here we implement the user interface part. We start with basic math alignments:
269
270\newcount      \c_math_eqalign_column
271\newconditional\c_math_eqalign_first
272
273\newtoks \everymathalignment
274\newtoks \everymathalignmentdone
275
276\def\math_alignment_NN
277  {\dodirectdoubleempty\math_alignment_NN_indeed}
278
279\def\math_alignment_NN_indeed[#1][#2]%
280  {\aligntab
281   \strc_formulas_place_number_nested{#1}{#2}}
282
283\def\math_alignment_NR
284  {\dodirectdoubleempty\math_alignment_NR_indeed}
285
286\def\math_alignment_NR_indeed[#1][#2]%
287  {\aligntab
288   \dostoptagged % finish cell
289   \strc_formulas_place_number_nested{#1}{#2}%
290   \math_number_right_of_eqalign
291   \global\settrue\c_math_eqalign_first
292   \crcr
293   \dostoptagged} % finish row
294
295\def\math_alignment_NC
296  {\relax
297   \ifconditional\c_math_eqalign_first
298     \ifx\p_math_alignment_number\v!auto
299       \strc_formulas_place_number_nested{+}{}%
300     \fi
301     \global\setfalse\c_math_eqalign_first
302   \fi
303   \math_number_left_of_eqalign
304   \aligntab}
305
306\def\math_alignment_EQ
307  {\NC=}
308
309\installmacrostack\NC % maybe more to shared table definitions
310\installmacrostack\NN % maybe more to shared table definitions
311\installmacrostack\EQ % maybe more to shared table definitions
312\installmacrostack\NR % maybe more to shared table definitions
313\installmacrostack\BC % maybe more to shared table definitions
314\installmacrostack\EC % maybe more to shared table definitions
315
316\appendtoks
317    \push_macro_NC
318    \push_macro_NN
319    \push_macro_EQ
320    \push_macro_NR
321    \let\NC\math_alignment_NC
322    \let\NN\math_alignment_NN
323    \let\EQ\math_alignment_EQ
324    \let\NR\math_alignment_NR
325    \global\settrue\c_math_eqalign_first
326\to \everymathalignment
327
328\appendtoks
329    \pop_macro_NR
330    \pop_macro_EQ
331    \pop_macro_NN
332    \pop_macro_NC
333\to \everymathalignmentdone
334
335\let\math_alignment_snap_start\relax
336\let\math_alignment_snap_stop \relax
337
338% % experimental:
339%
340% \def\math_alignment_snap_start
341%   {\ifgridsnapping
342%      \edef\p_math_alignment_grid{\mathalignmentparameter\c!grid}%
343%      \ifx\p_math_alignment_grid\v!no\else
344%        \snaptogrid[\p_math_alignment_grid]\vbox\bgroup
345%      \fi
346%    \fi}
347%
348% \def\math_alignment_snap_stop
349%   {\ifgridsnapping
350%      \ifx\p_math_alignment_grid\v!no\else
351%        \egroup
352%      \fi
353%    \fi}
354%
355% % doesn't work well, so:
356
357\let\math_alignment_snap_start\relax
358\let\math_alignment_snap_stop \relax
359
360% end of experimental
361
362\newconditional\c_math_alignment_auto_number
363
364\unexpanded\def\math_alignment_start#1%
365  {\edef\currentmathalignment{#1}%
366   \dosingleempty\math_alignment_start_indeed}
367
368\def\math_alignment_start_indeed[#1]%
369  {% \begingroup not permitted ($$...assignments...\halign... )
370   \iffirstargument
371     \setupmathalignment[\currentmathalignment][#1]% bad! ungrouped
372   \fi
373   \math_alignment_snap_start
374   \the\everymathalignment
375   \c_math_eqalign_column\zerocount
376   \edef\p_math_alignment_number{\mathalignmentparameter\c!number}%
377   \processcommacommand
378     [\mathalignmentparameter\c!align]%
379     {\advance\c_math_eqalign_column\plusone\math_eqalign_set_column}% takes argument
380   \global\c_math_eqalign_column\plusone
381   \dostarttagged\t!math\empty
382   \dostarttagged\t!mtable\currentmathalignment
383   \numberedeqalign}
384
385\def\math_alignment_stop
386  {\math_finish_eqalign_no
387   \dostoptagged
388   \dostoptagged
389   \the\everymathalignmentdone
390   \math_alignment_snap_stop}
391
392\installcorenamespace{mathalignment}
393\installcorenamespace{mathalignmentvariant}
394
395\installcommandhandler \??mathalignment {mathalignment} \??mathalignment
396
397\appendtoks
398    \setuevalue{\e!start\currentmathalignment}{\math_alignment_start{\currentmathalignment}}%
399    \setvalue  {\e!stop \currentmathalignment}{\math_alignment_stop}%
400\to \everydefinemathalignment
401
402\setupmathalignment
403  [\c!n=2,
404   \c!m=1,
405   \c!distance=\emwidth,
406   \c!grid=\v!math]
407
408\definemathalignment[align]            % default case (this is what amstex users expect)
409\definemathalignment[\v!mathalignment] % prefered case (this is cleaner, less clashing)
410
411% special case.. in case one mistypes ..
412
413\ifdefined \startalignment
414
415    \let\align_math_normal_start\startalign
416    \let\align_math_normal_stop \stopalign
417
418    \let\align_text_normal_start\startalignment
419    \let\align_text_normal_stop \stopalignment
420
421    \unexpanded\def\startalign
422      {\ifmmode
423         \let\stopalign\align_math_normal_stop % cannot be an unexpanded def ... lookahead in align
424         \expandafter\align_math_normal_start
425       \else\ifinformula
426         \let\stopalign\align_math_normal_stop
427         \doubleexpandafter\align_math_normal_start
428       \else
429         \let\stopalign\align_text_normal_stop
430         \doubleexpandafter\align_text_normal_start
431       \fi\fi}
432
433    \let\stopalign\relax
434
435    \unexpanded\def\startalignment
436      {\ifmmode
437         \let\stopalignment\align_math_normal_stop % cannot be an unexpanded def ... lookahead in align
438         \expandafter\align_math_normal_start
439       \else\ifinformula
440         \let\stopalignment\align_math_normal_stop % cannot be an unexpanded def ... lookahead in align
441         \doubleexpandafter\align_math_normal_start
442       \else
443         \let\stopalignment\align_text_normal_stop
444         \doubleexpandafter\align_text_normal_start
445       \fi\fi}
446
447    \let\stopalignment\relax
448
449\fi
450
451%
452
453\unexpanded\def\numberedeqalign
454  {\doifelse{\formulaparameter\c!location}\v!left
455     \math_handle_eqalign_no_l_aligned
456     \math_handle_eqalign_no_r_aligned}
457
458\def\math_first_in_eqalign
459  {\global\c_math_eqalign_column\plusone
460   \dostarttagged\t!mtablerow \empty
461   \dostarttagged\t!mtablecell\empty}
462
463\def\math_next_in_eqalign
464  {\global\advance\c_math_eqalign_column\plusone
465   \dostoptagged % finish cell
466   \dostarttagged\t!mtablecell\empty}
467
468\def\math_left_of_eqalign
469  {\ifcsname\??mathalignmentvariant\number\c_math_eqalign_column\endcsname
470     \ifcase\lastnamedcs \or \relax \or \hfill \or \hfill \fi
471   \fi}
472
473\def\math_right_of_eqalign
474  {\ifcsname\??mathalignmentvariant\number\c_math_eqalign_column\endcsname
475     \ifcase\lastnamedcs \or \hfill \or \relax \or \hfill \fi
476   \fi}
477
478\newconditional\c_math_alignment_local_number % not used but when true puts in front (todo)
479
480\def\math_number_right_of_eqalign
481  {\ifcase\wd\b_strc_formulas_number\else
482     \ifconditional\c_math_alignment_local_number
483       \ifcase\c_strc_math_number_location\or\or
484         \box\b_strc_formulas_number
485       \fi
486     \else
487       \box\b_strc_formulas_number
488     \fi
489   \fi}
490
491\def\math_number_left_of_eqalign
492  {\ifcase\wd\b_strc_formulas_number\else
493     \ifconditional\c_math_alignment_local_number
494       \ifcase\c_strc_math_number_location\or
495         \box\b_strc_formulas_number
496       \fi
497     \fi
498   \fi}
499
500% \def\math_eqalign_set_column#1% we could just add to the preamble (as with other alignments)
501%   {\expandafter\let\csname\??mathalignmentvariant\number\c_math_eqalign_column\expandafter\endcsname
502%      \csname\??mathalignmentvariant\ifcsname\??mathalignmentvariant#1\endcsname#1\else\v!normal\fi\endcsname}
503
504\def\math_eqalign_set_column#1% we could just add to the preamble (as with other alignments)
505  {\expandafter\chardef\csname\??mathalignmentvariant\number\c_math_eqalign_column\expandafter\expandafter\expandafter\endcsname
506     \ifcsname\??mathalignmentvariant#1\endcsname\lastnamedcs\else\zerocount\fi\relax}
507
508\letvalue{\??mathalignmentvariant\v!normal}\zerocount
509\letvalue{\??mathalignmentvariant\v!left  }\plusone
510\letvalue{\??mathalignmentvariant\v!right }\plustwo
511\letvalue{\??mathalignmentvariant\v!middle}\plusthree
512
513\def\math_align_NR_generic[#1][#2]%
514  {\strc_formulas_place_number_nested{#1}{#2}\crcr}
515
516%D \starttyping
517%D \placeformula[eqn0]\startformula \startalign[n=1] a\NR       \stopalign \stopformula See \in[eqn0]
518%D \placeformula[eqn1]\startformula \startalign[n=1] a\NR       \stopalign \stopformula See \in[eqn1]
519%D \placeformula      \startformula \startalign[n=1] a\NR[eqn2] \stopalign \stopformula See \in[eqn2]
520%D \placeformula[eqn3]\startformula \startalign[n=1] a\NR[+]    \stopalign \stopformula See \in[eqn3]
521%D \stoptyping
522
523%D \startbuffer
524%D \placeformula \startformula \eqalignno {
525%D  a &= b & \formulanumber \cr
526%D  c &= d \cr
527%D    &= e \cr
528%D    &= f & \formulanumber
529%D } \stopformula
530%D \stopbuffer
531%D
532%D \typebuffer \getbuffer
533%D
534%D \startbuffer
535%D \placeformula \startformula \startalign
536%D \NC  a \EQ b \NR[+]
537%D \NC  c \EQ d \NR
538%D \NC    \EQ f \NR[for:demo-a-1]
539%D \NC    \EQ g \NR[for:demo-a-2][a]
540%D \NC    \EQ h \NR[for:demo-a-3][b]
541%D \NC    \EQ i \NR
542%D \stopalign \stopformula
543%D \stopbuffer
544%D
545%D \typebuffer \getbuffer
546%D
547%D \startbuffer
548%D \placeformula \startformula \startalign
549%D \NC a \EQ b \NR[+]
550%D \NC c \EQ d \NR
551%D \NC   \EQ f \NR
552%D \NC   \EQ g \NR
553%D \NC   \EQ h \NR
554%D \NC   \EQ i \NR[+]
555%D \stopalign \stopformula
556%D \stopbuffer
557%D
558%D \typebuffer \getbuffer
559%D
560%D \startbuffer
561%D \placeformula \startformula \startalign
562%D \NC  a \NC \eq  b \NR[+]
563%D \NC  c \NC \neq d \NR
564%D \NC    \NC \neq f \NR[for:demo-b-1]
565%D \NC    \NC \geq g \NR[for:demo-b-2][a]
566%D \NC    \NC \leq h \NR[for:demo-b-3][b]
567%D \NC    \NC \neq i \NR
568%D \stopalign \stopformula
569%D \stopbuffer
570%D
571%D \typebuffer \getbuffer
572%D
573%D \startbuffer
574%D \placeformula \startformula \startalign[n=3,align={left,middle,right}]
575%D \NC       l \NC = \NC r     \NR
576%D \NC    left \NC = \NC right \NR
577%D \stopalign \stopformula
578%D \stopbuffer
579%D
580%D \typebuffer \getbuffer
581%D
582%D \startbuffer
583%D \placeformula \startformula \startalign[n=3,align={right,middle,left}]
584%D \NC       l \NC = \NC r     \NR
585%D \NC    left \NC = \NC right \NR
586%D \stopalign \stopformula
587%D \stopbuffer
588%D
589%D \typebuffer \getbuffer
590%D
591%D \startbuffer
592%D \placeformula \startformula \startalign[n=3,align={middle,middle,middle}]
593%D \NC       l \NC = \NC r     \NR
594%D \NC    left \NC = \NC right \NR
595%D \stopalign \stopformula
596%D \stopbuffer
597%D
598%D \typebuffer \getbuffer
599%D
600%D \startbuffer
601%D \placeformula
602%D \startformula
603%D     \startalign[n=3,align={middle,middle,middle}]
604%D         \NC a  \NC = \NC b  \NR[+]
605%D         \NC 2a \NC = \NC 2b \NR
606%D     \stopalign
607%D \stopformula
608%D \stopbuffer
609%D
610%D \typebuffer \getbuffer
611%D
612%D \startbuffer
613%D \placeformula
614%D \startformulas
615%D     \setupmathalignment[n=3,align={middle,middle,middle}]%
616%D     \startformula
617%D         \startalign
618%D             \NC a  \NC = \NC b  \NR[+]
619%D             \NC 2a \NC = \NC 2b \NR
620%D         \stopalign
621%D     \stopformula
622%D     \startformula
623%D         \startalign
624%D             \NC a  \NC = \NC b  \NR[+]
625%D             \NC 2a \NC = \NC 2b \NR
626%D         \stopalign
627%D     \stopformula
628%D \stopformulas
629%D \stopbuffer
630%D
631%D \typebuffer \getbuffer
632%D
633%D \startbuffer
634%D \placeformula
635%D \startformulas
636%D     \dorecurse{5}{\startformula
637%D         \startalign[n=3,align={middle,middle,middle}]
638%D             \NC a  \NC = \NC b  \NR[+]
639%D             \NC 2a \NC = \NC 2b \NR
640%D         \stopalign
641%D     \stopformula}
642%D \stopformulas
643%D \stopbuffer
644%D
645%D \typebuffer \getbuffer
646
647%D \macros
648%D   {definemathcases, setupmathcases, startmathcases}
649%D
650%D Another wish \unknown
651
652\installcorenamespace{mathcases}
653
654\installcommandhandler \??mathcases {mathcases} \??mathcases
655
656\setupmathcases
657  [\c!distance=\emwidth,
658   \c!strut=\v!yes, % new
659   \c!numberdistance=2.5\emwidth,
660   \c!left={\left\{\mskip\thinmuskip},
661   \c!right={\right.}]
662
663\appendtoks
664    \setuevalue{\e!start\currentmathcases}{\math_cases_start{\currentmathcases}}%
665    \setvalue  {\e!stop \currentmathcases}{\math_cases_stop}%
666\to \everydefinemathcases
667
668\unexpanded\def\math_cases_start#1%
669  {\begingroup
670   \edef\currentmathcases{#1}%
671   \dosingleempty\math_cases_start_indeed}
672
673\def\math_cases_NC_zero
674  {\math_cases_NC}
675
676\def\math_cases_MC_zero
677  {\math_cases_NC
678   \ifmmode\else
679     \startimath
680     \let\math_cases_end_math\stopimath
681   \fi}
682
683\let\math_cases_end_math\relax
684
685\def\math_cases_NR_zero
686  {\unskip
687   \math_cases_end_math
688   \aligntab
689   \glet\math_cases_NC\math_cases_NC_first
690   \dodirectdoubleempty\math_cases_NR}
691
692\def\math_cases_NC_first
693  {\glet\math_cases_NC\math_cases_NC_second}
694
695\def\math_cases_NC_second
696  {\math_cases_end_math\aligntab}
697
698\let\math_cases_NR\math_align_NR_generic
699
700\installmacrostack\math_cases_NC
701
702\unexpanded\def\math_cases_start_indeed[#1]%
703  {\iffirstargument
704     \setupcurrentmathcases[#1]%
705   \fi
706   \edef\p_strut{\mathcasesparameter\c!strut}%
707   \ifx\p_strut\v!yes
708     \let\math_cases_strut\strut
709   \else
710     \let\math_cases_strut\relax
711   \fi
712   \mathcasesparameter\c!left
713   \vcenter\bgroup
714   \push_macro_math_cases_NC
715   \let\endmath\relax
716   \let\NC\math_cases_NC_zero
717   \let\MC\math_cases_MC_zero
718   \let\NR\math_cases_NR_zero
719   \glet\math_cases_NC\math_cases_NC_first
720   \normalbaselines
721   \mathsurround\zeropoint
722   \everycr\emptytoks
723   \tabskip\zeropoint
724   \global\c_math_eqalign_column\plusone
725   \halign\bgroup
726     \startimath
727     \mathcasesparameter\c!style
728     \alignmark\alignmark
729     \stopimath
730     \hfil
731     \aligntab
732     \hskip\mathcasesparameter\c!distance\relax
733     \pop_macro_math_cases_NC
734     \math_cases_strut % looks better
735     \alignmark\alignmark
736     \hfil
737     \aligntab
738     \hskip\mathcasesparameter\c!numberdistance\relax
739     \let\formuladistance\!!zeropoint
740     \span\math_text_in_eqalign{\alignmark\alignmark}%
741     \crcr} % todo: number
742
743\def\math_cases_stop
744  {\crcr
745   \egroup
746   \popmacro\math_cases_NC
747   \egroup
748   \mathcasesparameter\c!right
749   \endgroup}
750
751\definemathcases[cases]
752\definemathcases[\v!mathcases]
753
754%D \startbuffer
755%D \placeformula \startformula \startcases
756%D \NC 2 \NC $ y > 0 $ \NR
757%D \NC 7 \NC $ x = 7 $ \NR[+]
758%D \NC 4 \NC otherwise \NR
759%D \stopcases \stopformula
760%D \stopbuffer
761%D
762%D \typebuffer \getbuffer
763%D
764%D \startbuffer
765%D \placeformula \startformula x \startcases
766%D \NC 2 \NC $ y > 0 $ \NR[+]
767%D \NC 7 \NC $ x = 7 $ \NR
768%D \NC 4 \NC otherwise \NR
769%D \stopcases \stopformula
770%D \stopbuffer
771%D
772%D \typebuffer \getbuffer
773%D
774%D \startbuffer
775%D \placeformula \startformula \startcases
776%D \NC 2 \NC $ y > 0 $ \NR
777%D \NC 7 \NC $ x = 7 $ \NR
778%D \NC 4 \NC otherwise \NR
779%D \stopcases \stopformula
780%D \stopbuffer
781%D
782%D \typebuffer \getbuffer
783%D
784%D \startbuffer
785%D \placeformula \startformula x \startcases
786%D \NC 2 \NC $ y > 0 $ \NR
787%D \NC 7 \NC $ x = 7 $ \NR
788%D \NC 4 \NC otherwise \NR
789%D \stopcases \stopformula
790%D \stopbuffer
791%D
792%D \typebuffer \getbuffer
793
794%D \macros
795%D   {definemathmatrix, setupmathmatrix, startmathmatrix}
796%D
797%D Yet another one \unknown. This time we implement the lot a bit
798%D different which is a side effect of getting the tagging right. In
799%D retrospect the main alignment could be done this way but \unknown
800
801\installcorenamespace{mathmatrix}
802
803\installcommandhandler \??mathmatrix {mathmatrix} \??mathmatrix
804
805\setupmathmatrix
806  [\c!distance=\emwidth,
807   \c!left=,
808   \c!right=,
809   \c!align=\v!middle]
810
811\appendtoks
812    \setuevalue{\e!start\currentmathmatrix}{\math_matrix_start{\currentmathmatrix}}%
813    \setvalue  {\e!stop \currentmathmatrix}{\math_matrix_stop}% no u else lookahead problem
814\to \everydefinemathmatrix
815
816\def\math_matrix_start_table
817  {\global\c_math_eqalign_column\zerocount
818   \dostarttagged\t!math\empty
819   \dostarttagged\t!mtable\empty}
820
821\def\math_matrix_stop_table
822  {\dostoptagged
823   \dostoptagged}
824
825\def\math_matrix_start_row
826  {\noalign{\global\c_math_eqalign_column\zerocount}%
827   \dostarttagged\t!mtablerow\empty}
828
829\def\math_matrix_stop_row
830  {\dostoptagged}
831
832\unexpanded\def\math_matrix_start_cell
833  {\dostarttagged\t!mtablecell\empty
834   \hss
835   \math_left_of_eqalign
836   \startimath
837   \math_matrix_set_style
838   \tabskip\zeropoint
839   \everycr\emptytoks}
840
841\unexpanded\def\math_matrix_stop_cell
842  {\stopimath
843   \math_right_of_eqalign
844   \hss
845   \dostoptagged}
846
847% We could construct a preamble with alignment and such embedded but the number
848% of matrices with many rows is normally so low that it doesn't pay of at all.
849
850\unexpanded\def\math_matrix_distance
851  {\relax
852   \ifdim\d_math_eqalign_distance>\zeropoint
853     \hskip\d_math_eqalign_distance
854   \fi
855   \relax}
856
857\def\math_matrix_preamble
858  {\math_matrix_strut
859   \global\advance\c_math_eqalign_column\plusone
860   \math_matrix_start_cell
861     \alignmark\alignmark
862   \math_matrix_stop_cell
863   \aligntab
864   \aligntab
865   \math_matrix_distance
866   \global\advance\c_math_eqalign_column\plusone
867   \math_matrix_start_cell
868     \alignmark\alignmark
869   \math_matrix_stop_cell}
870
871\newconditional\c_math_matrix_first
872
873\def\math_matrix_NR
874  {\aligntab\omit
875   \math_matrix_stop_row
876   \math_matrix_pickup
877   \crcr
878   \math_matrix_start_row}
879
880\def\math_matrix_NC
881  {\ifconditional\c_math_matrix_first
882     \expandafter\math_matrix_NC_yes
883   \else
884     \expandafter\math_matrix_NC_nop
885   \fi}
886
887\def\math_matrix_pickup{\global\settrue \c_math_matrix_first}
888\def\math_matrix_NC_yes{\global\setfalse\c_math_matrix_first}
889\def\math_matrix_NC_nop{\aligntab} % avoids lookahead
890
891% \def\math_matrix_stop_wrapup
892%   {\crcr
893%    \strut
894%    \crcr
895%    \noalign{\vskip-\struthtdp}}
896
897\def\math_matrix_start_processing
898  {\dontleavehmode
899   \bgroup
900   \tabskip\zeropoint
901   \math_matrix_pickup
902   \let\NR\math_matrix_NR
903   \let\NC\math_matrix_NC
904   \let\MC\math_matrix_NC
905   %
906   \let\endmath\relax
907   %
908   \setbox\nextbox\vbox\bgroup
909   \math_matrix_start_table
910   \halign \bgroup
911     % preamble
912     \span\math_matrix_preamble
913     % done
914     \crcr
915     \math_matrix_start_row}
916
917\def\math_matrix_stop_processing
918  {%\math_matrix_stop_wrapup % optional
919   \math_matrix_stop_row
920   \egroup
921   \math_matrix_stop_table
922   \egroup
923   \mathmatrixleft
924   \math_matrix_finish_nextbox
925   \mathmatrixright
926   \egroup}
927
928\let\math_matrix_strut    \strut
929\let\math_matrix_set_style\relax
930
931\def\math_matrix_check_settings
932  {\edef\p_strut{\mathmatrixparameter\c!strut}%
933   \ifx\p_strut\v!no
934     \let\math_matrix_strut\relax
935   \else
936     \let\math_matrix_strut\strut
937     \ifx\p_strut\v!yes\else
938       \spacing\p_strut
939     \fi
940   \fi
941   \d_math_eqalign_distance\mathmatrixparameter\c!distance\relax
942   \edef\math_matrix_set_style{\mathmatrixparameter\c!style}}
943
944\def\math_matrix_set_defaults
945  {\normalbaselines % hm, spacing ?
946   \mathsurround\zeropoint
947   \tabskip\zeropoint}
948
949\def\math_matrix_set_columns_step
950  {\advance\c_math_eqalign_column\plusone
951  %\c_math_matrix_columns\c_math_eqalign_column
952   \math_eqalign_set_column}
953
954\def\math_matrix_set_columns
955  {\c_math_eqalign_column\zerocount
956   \rawprocesscommacommand[\mathmatrixparameter\c!align]\math_matrix_set_columns_step}
957
958\newcount\c_math_eqalign_column_saved
959\newcount\c_math_eqalign_first_saved
960
961% \installglobalmacrostack\c_math_matrix_first
962
963\unexpanded\def\math_matrix_start#1%
964  {\begingroup
965   \globalpushmacro\c_math_matrix_first % hm, does that work?
966   \c_math_eqalign_column_saved\c_math_eqalign_column
967   \c_math_eqalign_first_saved \c_math_eqalign_first
968   \edef\currentmathmatrix{#1}%
969   \dosingleempty\math_matrix_start_indeed}
970
971\unexpanded\def\math_matrix_start_indeed[#1]%
972  {\iffirstargument
973     \setupcurrentmathmatrix[#1]%
974   \fi
975   \math_matrix_check_settings
976   \math_matrix_set_defaults
977   \math_matrix_set_columns
978   \math_matrix_start_processing}
979
980\def\math_matrix_stop
981  {\math_matrix_stop_processing
982   \global\c_math_eqalign_first\c_math_eqalign_first_saved
983   \global\c_math_eqalign_column\c_math_eqalign_column_saved
984   \globalpopmacro\c_math_matrix_first
985   \endgroup}
986
987% vcenter:
988%
989% delta     = (height(v) + depth(v))/2
990% axis      = math_axis_size(cur_size)
991% height(v) = delta + axis
992% depth(v)  = delta - axis
993
994\installcorenamespace{mathmatrixalignlocation}
995
996\let\mathmatrixleft \empty % experimental hook
997\let\mathmatrixright\empty % experimental hook
998
999\setvalue{\??mathmatrixalignlocation\v!top   }{\raise\dimexpr(\nextboxdp-\nextboxht)/2 +\mathaxisheight\mathstyle\relax}
1000\setvalue{\??mathmatrixalignlocation\v!high  }{\raise\dimexpr(\nextboxdp-\nextboxht)/2\relax}
1001\setvalue{\??mathmatrixalignlocation\v!center}{\relax}
1002\setvalue{\??mathmatrixalignlocation\v!lohi}  {\relax}
1003\setvalue{\??mathmatrixalignlocation\v!normal}{\relax}
1004\setvalue{\??mathmatrixalignlocation\v!bottom}{\lower\dimexpr(\nextboxdp-\nextboxht)/2 +\mathaxisheight\mathstyle\relax}
1005\setvalue{\??mathmatrixalignlocation\v!low   }{\lower\dimexpr(\nextboxdp-\nextboxht)/2\relax}
1006
1007\def\math_matrix_finish_nextbox
1008  {\begincsname\??mathmatrixalignlocation\mathmatrixparameter\c!location\endcsname\hbox\bgroup
1009     \normalstartimath
1010     \mathmatrixparameter\c!left
1011     \vcenter{\box\nextbox}%
1012     \mathmatrixparameter\c!right
1013     \normalstopimath
1014   \egroup}
1015
1016\definemathmatrix[matrix]
1017\definemathmatrix[\v!mathmatrix]
1018
1019%D \startbuffer
1020%D \placeformula \startformula[-] \startmatrix
1021%D \NC 1 \NC x \NC a \NR
1022%D \NC 2 \NC y \NC b \NR
1023%D \NC 3 \NC z \NC c \NR
1024%D \stopmatrix \stopformula
1025%D \stopbuffer
1026%D
1027%D \typebuffer \getbuffer
1028%D
1029%D \definemathmatrix[bmatrix][left={\left[\mskip\thinmuskip},right={\mskip\thinmuskip\right]},strut=1.25]
1030%D
1031%D \startbuffer
1032%D \placeformula \startformula[-] \startbmatrix
1033%D \NC 1 \NC x \NC a \NR
1034%D \NC 2 \NC y \NC b \NR
1035%D \NC 3 \NC z \NC c \NR
1036%D \stopbmatrix \stopformula
1037%D \stopbuffer
1038%D
1039%D \typebuffer \getbuffer
1040%D
1041%D Taco added some code (dedicated to Aditya Mahajan) that gives more
1042%D control over aligments:
1043
1044%D \startbuffer
1045%D \startformula
1046%D   \startmatrix
1047%D    \NC a + x \NC = \NC a + d \NR
1048%D    \NC y     \NC = \NC d     \NR
1049%D   \stopmatrix
1050%D \stopformula
1051%D \stopbuffer
1052%D
1053%D \typebuffer \getbuffer
1054
1055%D \startbuffer
1056%D \startformula
1057%D   \startmatrix [distance=3pt,align={right,left}]
1058%D    \NC a + x \NC = a + d \NR
1059%D    \NC y     \NC = d     \NR
1060%D   \stopmatrix
1061%D \stopformula
1062%D \stopbuffer
1063%D
1064%D \typebuffer \getbuffer
1065
1066%D \startbuffer
1067%D \startformula
1068%D   \startmatrix [left=\left(,right=\right)]
1069%D    \NC a + x \NR
1070%D    \NC y    \NR
1071%D   \stopmatrix
1072%D \stopformula
1073%D \stopbuffer
1074%D
1075%D \typebuffer \getbuffer
1076%D
1077%D A bit more complex code:
1078%D
1079%D \startbuffer
1080%D \startformula
1081%D    \text{Let }{\cal R} = \bigcup_{P_{X_1},P_{X_2}}
1082%D    \left\{ (R_1, R_2) :
1083%D    \startmatrix[distance=1em,align={left,left,right}]
1084%D      \NC R_1        \NC < I(X_1 ; Y \mid X_2)      \NC R_1       \NR
1085%D      \NC \hfill Q_2 \NC < I(X_2 ; Y \mid X_1)      \NC R_2       \NR
1086%D      \NC R_1 + R_2  \NC < I(X_1 ; Y)               \NC R_1 + R_2 \NR
1087%D    \stopmatrix
1088%D    \right\}
1089%D \stopformula
1090%D \stopbuffer
1091%D
1092%D \typebuffer \getbuffer
1093
1094%D \macros
1095%D   {startmatrices}
1096%D
1097%D Just a handy keystroke safer:
1098
1099\unexpanded\def\startmatrices
1100  {\begingroup
1101   \setupmathmatrix}
1102
1103\unexpanded\def\stopmatrices
1104  {\endgroup}
1105
1106%D \startbuffer
1107%D \startformula
1108%D   \startmatrix[left={\left(},right={\right)}]
1109%D     \NC A \NC B \NR \NC C \NC D \NR
1110%D   \stopmatrix
1111%D   =
1112%D   \startmatrix[left={\left(},right={\right)},location=low]
1113%D     \NC A \NC B \NR \NC C \NC D \NR
1114%D   \stopmatrix
1115%D   =
1116%D   \startmatrix[left={\left(},right={\right)},location=high]
1117%D     \NC A \NC B \NR \NC C \NC D \NR
1118%D   \stopmatrix
1119%D \stopformula
1120%D \stopbuffer
1121%D
1122%D \typebuffer \getbuffer
1123%D
1124%D \startbuffer
1125%D \startformula
1126%D   \startmatrices[left={\left(},right={\right)}]
1127%D     \startmatrix
1128%D       \NC A \NC B \NR \NC C \NC D \NR
1129%D     \stopmatrix
1130%D     =
1131%D     \startmatrix[location=bottom]
1132%D       \NC A \NC B \NR \NC C \NC D \NR
1133%D     \stopmatrix
1134%D     =
1135%D     \startmatrix[location=top]
1136%D       \NC A \NC B \NR \NC C \NC D \NR
1137%D     \stopmatrix
1138%D   \stopmatrices
1139%D \stopformula
1140%D \stopbuffer
1141%D
1142%D \typebuffer  % does not run well: \getbuffer
1143
1144%D Handy for the \type {m-matrix} module:
1145
1146\unexpanded\def\startnamedmatrix
1147  {\dodoubleempty\math_matrix_start_named}
1148
1149\def\math_matrix_start_named[#1][#2]%
1150  {\begingroup
1151   \edef\currentmathmatrix{#1}%
1152   \ifsecondargument
1153     \setupcurrentmathmatrix[#2]%
1154   \fi
1155   \math_matrix_start\currentmathmatrix}
1156
1157\def\stopnamedmatrix
1158  {\math_matrix_stop
1159   \endgroup}
1160
1161%D The following code is derived from Aditya's simplematrix prototype but
1162%D adapted to regular mathmatrices (which saves some code so it can go into
1163%D the core):
1164
1165\def\math_matrix_simple_row#1%
1166  {\rawprocesscommalist[#1]\math_matrix_simple_col
1167   \toksapp\scratchtoks{\NR}}
1168
1169\def\math_matrix_simple_col#1%
1170  {\toksapp\scratchtoks{\NC#1}}
1171
1172\unexpanded\def\math_matrix_simple[#1][#2]#3%
1173  {\begingroup
1174   \edef\currentmathmatrix{#1}%
1175   \ifsecondargument
1176     \setupcurrentmathmatrix[#2]%
1177   \fi
1178   \scratchtoks\emptytoks
1179   \processlist[];\math_matrix_simple_row[#3]%
1180   \math_matrix_start\currentmathmatrix
1181   \the\scratchtoks
1182   \math_matrix_stop
1183   \endgroup}
1184
1185%D We hook it into the normal mathmatrix code:
1186
1187\appendtoks
1188    \edef\p_simplecommand{\mathmatrixparameter\c!simplecommand}%
1189    \ifx\p_simplecommand\empty\else
1190        \setuevalue{\p_simplecommand}{\dodoubleempty\math_matrix_simple[\currentmathmatrix]}%
1191    \fi
1192\to \everydefinemathmatrix
1193
1194%D And predefine some matrices:
1195
1196\definemathmatrix[matrix:parentheses][\c!left={\left(\mskip\thinmuskip},\c!right={\mskip\thinmuskip\right)},\c!align=\v!middle]
1197\definemathmatrix[matrix:brackets]   [\c!left={\left[\mskip\thinmuskip},\c!right={\mskip\thinmuskip\right]},\c!align=\v!middle]
1198\definemathmatrix[matrix:bars]       [\c!left={\left|\mskip\thinmuskip},\c!right={\mskip\thinmuskip\right|},\c!align=\v!middle]
1199
1200\definemathmatrix[thematrix][matrix:parentheses][\c!simplecommand=thematrix]
1201
1202%D \startbuffer
1203%D \startformula
1204%D \thematrix{1,2,3,4;5,6,7,8;9,10,11,12}
1205%D \stopformula
1206%D \stopbuffer
1207%D
1208%D \typebuffer \getbuffer
1209%D
1210%D \startbuffer
1211%D \startformula
1212%D \startthematrix
1213%D     \NC 1\NC 2\NC 3\NC 4\NR
1214%D     \NC 5\NC 6\NC 7\NC 8\NR
1215%D     \NC 9\NC10\NC11\NC12\NR
1216%D \stopthematrix
1217%D \stopformula
1218%D \stopbuffer
1219%D
1220%D \typebuffer \getbuffer
1221
1222%D \macros
1223%D   {startintertext}
1224%D
1225%D Preliminary feature:
1226%D
1227%D {\em example code}
1228%D
1229%D The intertext commands have to be expandable (in aligment lookahead) so
1230%D we cannot use \type {\unexpanded}.
1231
1232\def\startintertext#1\stopintertext
1233  {\noalign{\math_intertext{#1}}}
1234
1235\let\stopintertext\relax
1236
1237\def\intertext#1%
1238  {\noalign{\math_intertext{#1}}}
1239
1240\unexpanded\def\math_intertext#1%
1241  {\penalty\postdisplaypenalty
1242   \afterdisplayspace
1243   \vbox{\forgetall\noindent#1\par}%
1244   \penalty\predisplaypenalty
1245   \beforedisplayspace}
1246
1247%D \macros
1248%D   {substack}
1249%D
1250%D Preliminary code:
1251%D
1252%D \startbuffer
1253%D \startformula
1254%D    \sum_{%
1255%D      \startsubstack
1256%D       i = 1 \NR
1257%D       i \neq n \NR
1258%D       i \neq m
1259%D       \stopsubstack
1260%D     }a_i
1261%D \stopformula
1262%D \stopbuffer
1263%D
1264%D \getbuffer which was typed as \typebuffer
1265%D
1266%D Notice that these macros give the correct spacing for
1267%D subscripts. Compare for example
1268%D
1269%D \startbuffer
1270%D \startformula
1271%D \sum_{\startsubstack a \NR b \NR \stopsubstack}
1272%D \text{ and }
1273%D \sum_{\scriptstyle a \atop \scriptstyle}
1274%D \stopformula
1275%D \stopbuffer
1276%D
1277%D \typebuffer which gives \getbuffer
1278
1279% no tagging yet : how is it supposed to be coded?
1280
1281\unexpanded\def\startsubstack
1282  {\begingroup
1283   \vcenter\bgroup
1284   \baselineskip\mathstacktotal
1285   \lineskip\mathstackvgap
1286   \lineskiplimit\lineskip
1287   \mathsurround\zeropoint
1288   \everycr\emptytoks
1289   \let\NC\relax
1290   \let\MC\relax
1291   \let\NR\crcr
1292   \halign\bgroup\hfil\normalstartimath\scriptstyle\alignmark\alignmark\normalstopimath\hfil\crcr}
1293
1294\def\stopsubstack % todo: \unexpanded and delayed
1295  {\crcr
1296   \egroup
1297   \egroup
1298   \endgroup}
1299
1300% %D \macros
1301% %D   {bordermatrix}
1302% %D
1303% %D In \PLAIN\ \TEX\ the width of a parenthesis is stored in
1304% %D the \DIMENSION\ \type{\mathparentwd}. This value is derived from
1305% %D the width of \type{\tenrm B}, so let's take care of it now:
1306%
1307% \ifx\mathparentwd\undefined \newdimen\mathparentwd \fi
1308%
1309% \let\normalbordermatrix\bordermatrix % move that code to here instead
1310%
1311% \unexpanded\def\bordermatrix
1312%   {\begingroup
1313%    \setbox\scratchbox\hbox{\mr\char"239C}%
1314%    \global\mathparentwd\wd\scratchbox
1315%    \endgroup
1316%    \normalbordermatrix}
1317%
1318% \def\bordermatrix
1319%   {\begingroup
1320%    \mr
1321%    \global\mathparentwd\fontcharwd\font"239C\relax
1322%    \endgroup
1323%    \normalbordermatrix}
1324
1325%D \macros{overset, underset}
1326%D
1327%D The macros \type{\overset} and \type{\underset} are provided by
1328%D \AMS\ packages in \LATEX. These macro allows you to place a symbol
1329%D above or below another symbol, irrespective of whether the other
1330%D symbol is a relation or something else, and without influencing the
1331%D spacing.  For most cases there is a better way to do such things
1332%D (declaring a math command with limop option, or using accents), but
1333%D occasionally these macros can be useful, for example:
1334%D
1335%D \startbuffer
1336%D \startformula
1337%D \overset{*}{X} \underset{*}{X}
1338%D \stopformula
1339%D \stopbuffer
1340%D \typebuffer \getbuffer
1341%D
1342%D Use these macros sparingly. Remember, \TEX\ was designed for
1343%D mathematics, so there is usually a proper method for typesetting
1344%D common math notation.
1345%D
1346%D These macros are a cleaner version of \type {\binrel@} and
1347%D \type {\binrel@@} macros in \AMSTEX\ packages.
1348
1349\def\math_binrel_apply#1%
1350  {\begingroup
1351   \setbox\scratchbox\hbox
1352     {\thinmuskip   0mu
1353      \medmuskip   -1mu
1354      \thickmuskip -1mu
1355      \setbox\scratchbox\hbox{\normalstartimath#1\mathsurround\zeropoint\normalstopimath}%
1356      \kern-\wd\scratchbox
1357      \normalstartimath{}#1{}\mathsurround\zeropoint\normalstopimath}%
1358   \ifdim\wd\scratchbox<\zeropoint
1359     \endgroup
1360     \expandafter\mathbin
1361   \else\ifdim\wd\scratchbox>\zeropoint
1362     \endgroup
1363     \doubleexpandafter\mathrel
1364   \else
1365     \endgroup
1366     \doubleexpandafter\firstofoneargument
1367   \fi\fi}
1368
1369\unexpanded\def\overset#1#2%
1370  {\math_binrel_apply{#2}{\mathop{\kern\zeropoint#2}\limits\normalsuperscript{#1}}}
1371
1372\unexpanded\def\underset#1#2%
1373  {\math_binrel_apply{#2}{\mathop{\kern\zeropoint#2}\limits\normalsubscript  {#1}}}
1374
1375%D The following code comes from \type {math-str.mkiv}.
1376%D
1377%D Here we implement a basic math alignment mechanism. Numbers are also handled. The macros
1378%D \type {\startinnermath} and \type {\stopinnermath} can be overloaded in specialized
1379%D modules.
1380
1381\installcorenamespace{mathinnerstart}
1382\installcorenamespace{mathinnerstop}
1383
1384% \unexpanded\def\startinnermath{\csname\??mathinnerstart\formulaparameter\c!align\endcsname}
1385% \unexpanded\def\stopinnermath {\csname\??mathinnerstop \formulaparameter\c!align\endcsname}
1386
1387\unexpanded\def\startinnermath{\expandnamespaceparameter\??mathinnerstart\formulaparameter\c!align\v!normal}
1388\unexpanded\def\stopinnermath {\expandnamespaceparameter\??mathinnerstop \formulaparameter\c!align\v!normal}
1389
1390\unexpanded\def\mathinnerstrut
1391  {\doif{\formulaparameter\c!strut}\v!yes\strut}
1392
1393\unexpanded\def\defineinnermathhandler#1#2#3%
1394  {\setvalue{\??mathinnerstart#1}{#2}%
1395   \setvalue{\??mathinnerstop #1}{#3}}
1396
1397\installtextracker
1398  {formulas.boxes}
1399  {\let\math_hbox\ruledhbox}
1400  {\let\math_hbox\hbox}
1401
1402\let\math_hbox\hbox
1403
1404\newconstant\mathraggedstatus % normal left center  right
1405\newconstant\mathnumberstatus % nothing normal shift_right
1406
1407\newdimen\d_math_number_correction
1408
1409\def\math_box_llapped_math_no
1410  {\ifcase\mathraggedstatus\or
1411     \box\b_strc_formulas_number
1412   \or
1413     \llap{\box\b_strc_formulas_number}%
1414   \or
1415     \llap{\box\b_strc_formulas_number}%
1416   \fi}
1417
1418\def\math_box_rlapped_math_no
1419  {\ifcase\mathraggedstatus\or
1420     \rlap{\box\b_strc_formulas_number}%
1421   \or
1422     \rlap{\box\b_strc_formulas_number}%
1423   \or
1424     \box\b_strc_formulas_number
1425   \fi}
1426
1427\newconditional\c_strc_math_has_number
1428\newconditional\c_strc_math_display_overflow
1429\newconstant   \c_strc_math_number_location
1430\newdimen      \d_strc_math_number_width
1431\newdimen      \d_strc_math_display_width
1432\newbox        \b_strc_math_display
1433\newconstant   \c_strc_formulas_frame_mode
1434\newdimen      \d_strc_math_indent
1435\newconditional\c_strc_math_indent
1436
1437\let\d_strc_math_framed_width\displaywidth
1438
1439\setvalue{\??formulaoption\v!frame}%
1440  {\edef\p_frame{\formulaparameter\c!frame}%
1441   \ifx\p_frame\v!number
1442     \c_strc_formulas_frame_mode\plustwo % inside frame
1443   \else
1444     \c_strc_formulas_frame_mode\plusone % outside frame
1445   \fi}
1446
1447% mode: 0=no frame | 1=number inside frame | 2=number outside frame
1448
1449\def\strc_math_flush_aligned
1450  {\ifcase\c_strc_math_vertical
1451     \ifcase\mathraggedstatus\or\hfill\or\hfill\fi
1452     \box\b_strc_math_display
1453     \ifcase\mathraggedstatus\or\or\hfill\or\hfill\fi
1454   \else
1455     \ifconditional\c_strc_math_indent
1456       \ifzeropt\d_strc_math_indent\else
1457         \hangafter\plusone
1458         \hangindent\d_strc_math_indent
1459       \fi
1460     \fi
1461     \edef\p_interlinespace{\formulaparameter\c!interlinespace}%
1462     \ifx\p_interlinespace\empty\else\baselineskip\p_interlinespace\fi
1463     \global\d_strc_math_indent\zeropoint
1464     \ifcase\mathraggedstatus\or\raggedleft\or\raggedcenter\or\raggedright\fi
1465     \unhbox\b_strc_math_display
1466   \fi}
1467
1468\def\strc_math_flush_box_normal
1469  {\ifcase\c_strc_math_vertical
1470     \hbox to \displaywidth\bgroup
1471        \strc_math_flush_aligned
1472     \egroup
1473   \else
1474     \strc_math_flush_aligned
1475   \fi}
1476
1477\def\strc_math_flush_box_framed_common
1478  {\setformulaframedparameter\c!align{\formulaparameter\c!align}%
1479   \letformulaframedparameter\c!strut\v!no
1480   \d_framed_formula\ht\b_strc_math_display
1481   \ifcase\mathraggedstatus\or\hfill\or\hfill         \fi
1482   \inheritedformulaframedframed{\box\b_strc_math_display}%
1483   \ifcase\mathraggedstatus\or      \or\hfill\or\hfill\fi}
1484
1485% \def\strc_math_flush_box_framed_inline
1486%   {\letformulaframedparameter\c!location\empty
1487%    \letformulaframedparameter\c!width\displaywidth
1488%    \strc_math_flush_box_framed_common}
1489
1490\def\strc_math_flush_box_framed_display
1491  {\let\currentformulaframed\currentformula
1492   \letformulaframedparameter\c!location\v!formula
1493   \setformulaframedparameter\c!width{\d_strc_math_framed_width}%
1494   \strc_math_flush_box_framed_common}
1495
1496\def\strc_math_flush_box_framed_fit_inline
1497  {\let\currentformulaframed\currentformula
1498   \letformulaframedparameter\c!location\empty
1499   \letformulaframedparameter\c!width\v!fit
1500   \strc_math_flush_box_framed_common}
1501
1502\def\strc_math_flush_box_framed_fit_display
1503  {\let\currentformulaframed\currentformula
1504   \letformulaframedparameter\c!location\v!formula
1505   \letformulaframedparameter\c!width\v!fit
1506   \strc_math_flush_box_framed_common}
1507
1508% combiners
1509
1510\def\strc_math_flush_box
1511  {\ifcase\c_strc_formulas_frame_mode
1512     \strc_math_flush_box_normal
1513   \else
1514     \strc_math_flush_box_framed_display
1515   \fi}
1516
1517\def\strc_math_number_right_normal
1518  {\strc_math_flush_aligned
1519   \hss % hss makes room for number
1520   \math_box_llapped_math_no}
1521
1522\def\strc_math_number_left_normal
1523  {\math_box_rlapped_math_no
1524   \strc_math_flush_aligned
1525   \hss} % hss makes room for number
1526
1527\def\strc_math_number_right_normal_outside
1528  {\ifconditional\c_strc_formulas_tight
1529     \strc_math_flush_box_framed_fit_display
1530   \else
1531     \strc_math_flush_box_framed_display
1532   \fi
1533   \hss % hss makes room for number
1534   \math_box_llapped_math_no}
1535
1536\def\strc_math_number_left_normal_outside
1537  {\math_box_rlapped_math_no
1538   \hss % hss makes room for number
1539   \ifconditional\c_strc_formulas_tight
1540     \strc_math_flush_box_framed_fit_display
1541   \else
1542     \strc_math_flush_box_framed_display
1543   \fi}
1544
1545\def\strc_math_number_right_normal_inside
1546  {\setbox\b_strc_math_display\hpack to \dimexpr\displaywidth-\d_framed_locator_lo-\d_framed_locator_ro\relax\bgroup
1547     \strc_math_flush_aligned
1548     \hss
1549     \math_box_llapped_math_no
1550   \egroup
1551   \strc_math_flush_box_framed_fit_inline}
1552
1553\def\strc_math_number_left_normal_inside
1554  {\setbox\b_strc_math_display\hpack to \dimexpr\displaywidth-\d_framed_locator_lo-\d_framed_locator_ro\relax\bgroup
1555     \math_box_rlapped_math_no
1556     \hss
1557     \strc_math_flush_aligned
1558   \egroup
1559   \strc_math_flush_box_framed_fit_inline}
1560
1561\def\strc_math_number_right_overflow
1562  {\vpack\bgroup
1563     \strc_math_flush_box
1564     \par
1565     \hpack to \displaywidth\bgroup
1566       \hss
1567       \math_box_llapped_math_no
1568     \egroup
1569   \egroup}
1570
1571\def\strc_math_number_left_overflow
1572  {\vpack\bgroup
1573     \hpack to \displaywidth\bgroup
1574       \math_box_rlapped_math_no
1575       \hss
1576     \egroup
1577     \strc_math_flush_box
1578   \egroup}
1579
1580\def\strc_math_number_right_overflow_outside
1581  {\vpack\bgroup
1582     \strc_math_flush_box_framed_fit_inline
1583%      \hskip\zeropoint % nicely breaks the line without introducing funny vertical spacing ... why o why
1584     \hpack to \displaywidth\bgroup
1585       \hss
1586       \math_box_llapped_math_no
1587     \egroup
1588   \egroup}
1589
1590\def\strc_math_number_left_overflow_outside
1591  {\vpack\bgroup
1592     \hpack to \dimexpr\displaywidth-\d_framed_locator_lo\relax\bgroup
1593       \math_box_rlapped_math_no
1594       \hss
1595     \egroup
1596     \hskip\zeropoint % nicely breaks the line without introducing funny vertical spacing ... why o why
1597     \strc_math_flush_box_framed_fit_inline
1598   \egroup}
1599
1600\def\strc_math_number_right_overflow_inside
1601  {\setbox\b_strc_math_display\vpack\bgroup
1602     \box\b_strc_math_display
1603     \hpack to \displaywidth\bgroup
1604       \hss
1605       \math_box_llapped_math_no
1606       \hskip\d_framed_locator_ro
1607     \egroup
1608   \egroup
1609   \strc_math_flush_box_framed_fit_inline}
1610
1611\def\strc_math_number_left_overflow_inside
1612  {\setbox\b_strc_math_display\vpack\bgroup
1613     \hpack to \displaywidth\bgroup
1614     % \hskip\d_framed_locator_lo
1615       \math_box_rlapped_math_no
1616       \hss
1617     \egroup
1618     \box\b_strc_math_display
1619   \egroup
1620   \strc_math_flush_box_framed_fit_inline}
1621
1622% checkers
1623
1624\def\strc_math_number_check
1625  {\d_strc_math_display_width\wd\b_strc_math_display
1626   \ifconditional\c_strc_formulas_tight
1627     \ifdim\d_strc_math_display_width>\displaywidth
1628       \settrue\c_strc_math_display_overflow
1629     \else
1630       \displaywidth\d_strc_math_display_width
1631       \setfalse\c_strc_math_display_overflow
1632     \fi
1633   \else
1634     \ifdim\d_strc_math_display_width>\displaywidth
1635       \settrue\c_strc_math_display_overflow
1636     \else
1637       \setfalse\c_strc_math_display_overflow
1638     \fi
1639   \fi}
1640
1641\def\strc_math_number_check_outside
1642  {\d_strc_math_display_width\naturalwd\b_strc_math_display
1643   \ifdim\dimexpr\d_strc_math_display_width+\d_framed_locator_lo+\d_framed_locator_ro\relax>\displaywidth
1644     \settrue\c_strc_math_display_overflow
1645   \else
1646     \setfalse\c_strc_math_display_overflow
1647   \fi
1648   % still ok?
1649   \ifnum\mathraggedstatus=\plustwo
1650     \edef\d_strc_math_framed_width{\the\dimexpr\displaywidth-2\wd\b_strc_formulas_number\relax}%
1651   \else
1652     \edef\d_strc_math_framed_width{\the\dimexpr\displaywidth-\wd\b_strc_formulas_number\relax}%
1653   \fi}
1654
1655\let\strc_math_number_check_inside\strc_math_number_check_outside
1656
1657% offsets
1658
1659\def\strc_math_number_check_offsets
1660  {\begingroup
1661     \setbox\scratchbox\hbox
1662       {\inheritedformulaframedframed
1663          {\pack_framed_locator_set_lo\pack_framed_locator_set_ro}}%
1664   \endgroup}
1665
1666% tracing
1667
1668\def\strc_math_traced_state_yes
1669  {\llap{\setbox\scratchbox\hbox{\infofont
1670   \ifcase\mathraggedstatus unset\or right\or middle\or left\fi
1671   \space
1672   \ifcase\c_strc_formulas_frame_mode no\or out\or in\fi
1673   \space
1674   \ifconditional\c_strc_math_display_overflow overflow\else fit\fi
1675   \quad}\ht\scratchbox\zeropoint\dp\scratchbox\zeropoint\box\scratchbox}}
1676
1677\let\strc_math_traced_state\relax
1678
1679\installtextracker
1680  {formulas.framed}
1681  {\let\strc_math_traced_state\strc_math_traced_state_yes}
1682  {\let\strc_math_traced_state\relax}
1683
1684% packaging
1685
1686\unexpanded\def\strc_math_box_start#1%
1687  {\hsize\displaywidth % \checkeddisplaymath
1688   \global\mathnumberstatus\plusone
1689   \mathraggedstatus#1\relax
1690   %
1691   \global\d_math_number_correction\zeropoint
1692   %
1693   \edef\p_location{\formulaparameter\c!location}%
1694   \useformulacolorparameter\c!color
1695   \c_strc_math_number_location\ifx\p_location\v!left\plusone\else\ifx\p_location\v!right\plustwo\else\zerocount\fi\fi
1696   %
1697  %\strc_formulas_place_number % not here as we can have inner alignment numbers
1698   \dontcomplain
1699   \setbox\b_strc_math_display\math_hbox\bgroup % \checkeddisplaymath
1700     \mathinnerstrut
1701     \startforceddisplaymath}
1702
1703\def\strc_math_flush_number_no
1704  {\ifcase\c_strc_math_vertical
1705     \ifconditional\c_strc_math_display_overflow
1706       \ifcase\c_strc_formulas_frame_mode
1707         \strc_math_flush_box_normal
1708       \else
1709         \strc_math_flush_box_framed_fit_inline
1710       \fi
1711     \else
1712       \ifcase\c_strc_formulas_frame_mode
1713        %\ifconditional\c_strc_formulas_tight
1714        %  \strc_math_flush_box_normal
1715        %\else
1716           \strc_math_flush_box_normal
1717        %\fi
1718       \else
1719         \ifconditional\c_strc_formulas_tight
1720           \strc_math_flush_box_framed_fit_inline
1721         \else
1722           \strc_math_flush_box_framed_display
1723         \fi
1724       \fi
1725     \fi
1726   \else
1727     \strc_math_flush_box
1728   \fi}
1729
1730\def\strc_math_flush_number_left
1731  {\ifcase\c_strc_math_vertical
1732     \ifconditional\c_strc_math_display_overflow
1733       \ifcase\c_strc_formulas_frame_mode
1734         \strc_math_number_left_overflow
1735       \or
1736         \strc_math_number_left_overflow_outside
1737       \or
1738         \strc_math_number_left_overflow_inside
1739       \fi
1740     \else
1741       \ifcase\c_strc_formulas_frame_mode
1742         \strc_math_number_left_normal
1743       \or
1744         \strc_math_number_left_normal_outside
1745       \or
1746         \strc_math_number_left_normal_inside
1747       \fi
1748     \fi
1749   \else
1750     \box\b_strc_formulas_number
1751     \hfill
1752     \strc_math_flush_aligned
1753   \fi}
1754
1755\def\strc_math_flush_number_right
1756  {\ifcase\c_strc_math_vertical
1757     \ifconditional\c_strc_math_display_overflow
1758       \ifcase\c_strc_formulas_frame_mode
1759         \strc_math_number_right_overflow
1760       \or
1761         \strc_math_number_right_overflow_outside
1762       \or
1763         \strc_math_number_right_overflow_inside
1764       \fi
1765     \else
1766       \ifcase\c_strc_formulas_frame_mode
1767         \strc_math_number_right_normal
1768       \or
1769         \strc_math_number_right_normal_outside
1770       \or
1771         \strc_math_number_right_normal_inside
1772       \fi
1773     \fi
1774   \else
1775     \strc_math_flush_aligned
1776     \hfill
1777     \box\b_strc_formulas_number
1778   \fi}
1779
1780\unexpanded\def\strc_math_box_stop
1781  {\stopforceddisplaymath
1782   \egroup
1783   % check number
1784   \d_strc_math_number_width\wd\b_strc_formulas_number
1785   %
1786   \ifcase\mathnumberstatus
1787     \setfalse\c_strc_math_has_number
1788   \or\ifzeropt\d_strc_math_number_width
1789     \setfalse\c_strc_math_has_number
1790   \else
1791     \settrue\c_strc_math_has_number
1792   \fi\fi
1793   % preroll left and right offsets
1794   \ifcase\c_strc_formulas_frame_mode
1795     % no frame
1796   \else
1797     \strc_math_number_check_offsets
1798   \fi
1799   \ifcase\c_strc_formulas_frame_mode
1800     \strc_math_number_check
1801   \or
1802     \strc_math_number_check_outside
1803   \else
1804     \strc_math_number_check_inside
1805   \fi
1806   \noindent % \noindentation % not \dontleavehmode
1807   \hskip\d_strc_formulas_display_margin_left % was kern but that doesn't indent
1808   \strc_math_traced_state
1809   \ifcase\c_strc_math_vertical
1810     \hbox to \displaywidth \bgroup
1811   \or
1812     \vbox \bgroup \hsize\displaywidth
1813   \or
1814     \bgroup \hsize\displaywidth
1815   \fi
1816   \ifcase\mathnumberstatus
1817     \strc_math_flush_box
1818   \or % status 1
1819     \ifcase\c_strc_math_number_location
1820       \strc_math_flush_box
1821     \or % number left
1822       \ifzeropt\wd\b_strc_formulas_number
1823         \strc_math_flush_number_no
1824       \else
1825         \strc_math_flush_number_left
1826       \fi
1827     \else % number right
1828       \ifzeropt\wd\b_strc_formulas_number
1829         \strc_math_flush_number_no
1830       \else
1831         \strc_math_flush_number_right
1832       \fi
1833     \fi
1834   \or % status 2
1835      \hskip\d_math_number_correction % probably no longer used
1836      \strc_math_flush_box
1837      \hss
1838   \else
1839     \strc_math_flush_box
1840   \fi
1841   \ifcase\c_strc_math_vertical
1842   \or
1843   \or
1844     \par
1845   \fi
1846   \egroup}
1847
1848\defineinnermathhandler\v!left      {\strc_math_box_start\plusone  }{\strc_math_box_stop}
1849\defineinnermathhandler\v!middle    {\strc_math_box_start\plustwo  }{\strc_math_box_stop}
1850\defineinnermathhandler\v!right     {\strc_math_box_start\plusthree}{\strc_math_box_stop}
1851\defineinnermathhandler\v!flushleft {\strc_math_box_start\plusthree}{\strc_math_box_stop}
1852\defineinnermathhandler\v!center    {\strc_math_box_start\plustwo  }{\strc_math_box_stop}
1853\defineinnermathhandler\v!flushright{\strc_math_box_start\plusone  }{\strc_math_box_stop}
1854\defineinnermathhandler\v!normal    {\strc_math_box_start\plustwo  }{\strc_math_box_stop}
1855
1856%D Some inline math tweak.
1857
1858\appendtoks
1859    \ifcase\mathnestinglevel\or
1860        % 4=disable 6=only when no spaces
1861        \mathsurroundskip\mathematicsparameter\c!textdistance\relax
1862        \ifzeropt\mathsurroundskip
1863          \ifzeropt\gluestretch\mathsurroundskip
1864            \ifzeropt\glueshrink\mathsurroundskip
1865              \mathsurroundmode\plussix
1866            \else
1867              \mathsurroundskip\zeropoint
1868              \mathsurroundmode\plusfour
1869            \fi
1870          \else
1871            \mathsurroundmode\plussix
1872          \fi
1873        \else
1874          \mathsurroundmode\plussix
1875        \fi
1876    \else
1877      \mathsurroundmode\plusfour
1878      \mathsurroundskip\zeropoint
1879    \fi
1880\to \everymathematics
1881
1882\setupmathematics
1883  [\c!textdistance=\zeropoint]
1884
1885%D This is an experiment. No fancy spacing and alignments here. If we ever
1886%D go that route it might result in incompatible rendering.
1887
1888\unexpanded\def\startsplitformula
1889  {\ifhmode
1890     \par
1891   \fi
1892   \begingroup
1893   \beforedisplayspace
1894   % subset of \everydisplay:
1895   \c_attr_mathmode\plusone
1896   \settrue \indisplaymath
1897   % end of subset
1898   \informulatrue}
1899
1900\unexpanded\def\stopsplitformula
1901  {\afterdisplayspace
1902   \endgroup}
1903
1904\protect \endinput
1905
1906% \placeformula \startformula[-] \startmatrix
1907% \NC 1 \NC x \NC a \NR
1908% \NC 2 \NC y \NC b \NR
1909% \NC 3 \NC z \NC c \NR
1910% \stopmatrix \stopformula
1911
1912% \definemathmatrix[bordermatrix][left={\left[\mskip\thinmuskip},right={\mskip\thinmuskip\right]}]
1913
1914% \placeformula \startformula[-] \startbordermatrix
1915% \NC 1 \NC x \NC a \NR
1916% \NC 2 \NC y \NC b \NR
1917% \NC 3 \NC z \NC c \NR
1918% \stopbordermatrix \stopformula
1919