% arrow.tex: macros for commutative diagrams.
%
% Copyright (C) 1991,1992 Steven T. Smith.
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2, or (at your option)
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
% Version 0 Released for alpha testing, November 16, 1991.
% Version 0.1 Morphism positions for slanted lines improved, Nov. 17, 1991.
% Version 0.11 \biline changed to \bisline for compatible naming. 11/21/91
% Version 0.2 Equate \lft & \rt w. _ and ^ instead of L_{12} & R_{12}. 1/20/92
% Version 1.0 Distributed with Eplain. 1/20/92
% Version 1.1 Purged \newcount's, etc.; Warner ref.; \getch@nnel logic. 4/21/92
% Syntax: \[arrow](X,Y) or
% \[arrow](X,Y)\lft{MOR} (morphism placed left of arrow) or
% \[arrow](X,Y)\rt{MOR} (morphism placed right of arrow)
%
% [arrow] is one of
% sline (straight line)
% dotline (dotted line) * Unimplemented
% arrow (straight arrow)
% dotarrow (dotted arrow) * Unimplemented
%
% The following allow plain versions and some combination of \lft and \rt.
% biarrow (two straight arrows)
% adjarrow (two adjoint arrows)
% bisline (two straight lines)
%
% Also, for left, right, up, and down mappings:
%
% \mapright (or \mapright^{f_*}, \mapright_{f_*})
% \mapleft (ditto)
% \mapup (use \rt and \lft as above)
% \mapdown (ditto)
%
% And variants of these (can use combinations of ^/_ and lft/rt):
%
% \bimapright (two right arrows)
% \bimapleft (two left arrows)
% \adjmapright (two adjoint arrows; <- over ->)
% \adjmapleft (two adjoint arrows; -> over <-)
% \hline (horizontal line)
% \dothline (dotted horizontal line) * Unimplemented
% \bihline (two horizontal lines)
%
% \bimapdown (two down arrows)
% \bimapup (two left arrows)
% \adjmapdown (two adjoint arrows; down then up)
% \adjmapup (two adjoint arrows; up then down)
% \vline (vertical line)
% \dotvline (dotted vertical line) * Unimplemented
% \bivline (two vertical lines)
% Use \thinlines temporarily to find the current catcode of @, so we can
% restore it at the end.
\edef\thinlines{\the\catcode`@ }%
\catcode`@ = 11
\let\@oldatcatcode = \thinlines
% Adapted LaTeX code for drawing lines and vectors
% Note: to ensure compatibility with LaTeX, all LaTeX control
% sequences have been renamed. Control sequence names containing the
% at sign (@) have been changed to contain an ampersand (&) instead.
\edef\@oldandcatcode{\the\catcode`& }%
\catcode`& = 11
% LaTeX macros changed here:
% \line - changed to \drawline
% \vector - changed to \drawvector
% \@badlinearg - simply uses \errmessage now
% \@height, \@width, and \@depth are changed to height, width, and depth
% \@sline and \@svector - changed so that \hbox{\drawline...} yields
% a box of positive width and positive height for a positive slope
% and positive depth for a negative slope.
% \@hline and \@hvector - likewise
% \unitlength eliminated; pass dimensions to \drawline and \drawvector.
% LaTeX's while loop
\def\&whilenoop#1{}%
\def\&whiledim#1\do #2{\ifdim #1\relax#2\&iwhiledim{#1\relax#2}\fi}%
\def\&iwhiledim#1{\ifdim #1\let\&nextwhile=\&iwhiledim
\else\let\&nextwhile=\&whilenoop\fi\&nextwhile{#1}}%
% LaTeX's \line and \vector macros:
\newif\if&negarg
\newdimen\&wholewidth
\newdimen\&halfwidth
\font\tenln=line10
\def\thinlines{\let\&linefnt\tenln \let\&circlefnt\tencirc
\&wholewidth\fontdimen8\tenln \&halfwidth .5\&wholewidth}%
\def\thicklines{\let\&linefnt\tenlnw \let\&circlefnt\tencircw
\&wholewidth\fontdimen8\tenlnw \&halfwidth .5\&wholewidth}%
\def\drawline(#1,#2)#3{\&xarg #1\relax \&yarg #2\relax \&linelen=#3\relax
\ifnum\&xarg =0 \&vline \else \ifnum\&yarg =0 \&hline \else \&sline\fi\fi}%
\def\&sline{\leavevmode
\ifnum\&xarg< 0 \&negargtrue \&xarg -\&xarg \&yyarg -\&yarg
\else \&negargfalse \&yyarg \&yarg \fi
\ifnum \&yyarg >0 \&tempcnta\&yyarg \else \&tempcnta -\&yyarg \fi
\ifnum\&tempcnta>6 \&badlinearg \&yyarg0 \fi
\ifnum\&xarg>6 \&badlinearg \&xarg1 \fi
\setbox\&linechar\hbox{\&linefnt\&getlinechar(\&xarg,\&yyarg)}%
\ifnum \&yyarg >0 \let\&upordown\raise \&clnht\z@
\else\let\&upordown\lower \&clnht \ht\&linechar\fi
\&clnwd=\wd\&linechar
\&whiledim \&clnwd <\&linelen \do {%
\&upordown\&clnht\copy\&linechar
\advance\&clnht \ht\&linechar
\advance\&clnwd \wd\&linechar
}%
\advance\&clnht -\ht\&linechar
\advance\&clnwd -\wd\&linechar
\&tempdima\&linelen\advance\&tempdima -\&clnwd
\&tempdimb\&tempdima\advance\&tempdimb -\wd\&linechar
\hskip\&tempdimb \multiply\&tempdima \@m
\&tempcnta \&tempdima \&tempdima \wd\&linechar \divide\&tempcnta \&tempdima
\&tempdima \ht\&linechar \multiply\&tempdima \&tempcnta
\divide\&tempdima \@m
\advance\&clnht \&tempdima
\ifdim \&linelen <\wd\&linechar \hskip \wd\&linechar
\else\&upordown\&clnht\copy\&linechar\fi}%
\def\&hline{\vrule height \&halfwidth depth \&halfwidth width \&linelen}%
\def\&getlinechar(#1,#2){\&tempcnta#1\relax\multiply\&tempcnta 8
\advance\&tempcnta -9 \ifnum #2>0 \advance\&tempcnta #2\relax\else
\advance\&tempcnta -#2\relax\advance\&tempcnta 64 \fi
\char\&tempcnta}%
\def\drawvector(#1,#2)#3{\&xarg #1\relax \&yarg #2\relax
\&tempcnta \ifnum\&xarg<0 -\&xarg\else\&xarg\fi
\ifnum\&tempcnta<5\relax \&linelen=#3\relax
\ifnum\&xarg =0 \&vvector \else \ifnum\&yarg =0 \&hvector
\else \&svector\fi\fi\else\&badlinearg\fi}%
\def\&hvector{\ifnum\&xarg<0 \rlap{\&linefnt\&getlarrow(1,0)}\fi \&hline
\ifnum\&xarg>0 \llap{\&linefnt\&getrarrow(1,0)}\fi}%
\def\&vvector{\ifnum \&yarg <0 \&downvector \else \&upvector \fi}%
\def\&svector{\&sline
\&tempcnta\&yarg \ifnum\&tempcnta <0 \&tempcnta=-\&tempcnta\fi
\ifnum\&tempcnta <5
\if&negarg\ifnum\&yarg>0 % 3d quadrant; dp > 0
\llap{\lower\ht\&linechar\hbox to\&linelen{\&linefnt
\&getlarrow(\&xarg,\&yyarg)\hss}}\else % 4th quadrant; ht > 0
\llap{\hbox to\&linelen{\&linefnt\&getlarrow(\&xarg,\&yyarg)\hss}}\fi
\else\ifnum\&yarg>0 % 1st quadrant; ht > 0
\&tempdima\&linelen \multiply\&tempdima\&yarg
\divide\&tempdima\&xarg \advance\&tempdima-\ht\&linechar
\raise\&tempdima\llap{\&linefnt\&getrarrow(\&xarg,\&yyarg)}\else
\&tempdima\&linelen \multiply\&tempdima-\&yarg % 2d quadrant; dp > 0
\divide\&tempdima\&xarg
\lower\&tempdima\llap{\&linefnt\&getrarrow(\&xarg,\&yyarg)}\fi\fi
\else\&badlinearg\fi}%
\def\&getlarrow(#1,#2){\ifnum #2 =\z@ \&tempcnta='33\else
\&tempcnta=#1\relax\multiply\&tempcnta \sixt@@n \advance\&tempcnta
-9 \&tempcntb=#2\relax\multiply\&tempcntb \tw@
\ifnum \&tempcntb >0 \advance\&tempcnta \&tempcntb\relax
\else\advance\&tempcnta -\&tempcntb\advance\&tempcnta 64
\fi\fi\char\&tempcnta}%
\def\&getrarrow(#1,#2){\&tempcntb=#2\relax
\ifnum\&tempcntb < 0 \&tempcntb=-\&tempcntb\relax\fi
\ifcase \&tempcntb\relax \&tempcnta='55 \or
\ifnum #1<3 \&tempcnta=#1\relax\multiply\&tempcnta
24 \advance\&tempcnta -6 \else \ifnum #1=3 \&tempcnta=49
\else\&tempcnta=58 \fi\fi\or
\ifnum #1<3 \&tempcnta=#1\relax\multiply\&tempcnta
24 \advance\&tempcnta -3 \else \&tempcnta=51\fi\or
\&tempcnta=#1\relax\multiply\&tempcnta
\sixt@@n \advance\&tempcnta -\tw@ \else
\&tempcnta=#1\relax\multiply\&tempcnta
\sixt@@n \advance\&tempcnta 7 \fi\ifnum #2<0 \advance\&tempcnta 64 \fi
\char\&tempcnta}%
\def\&vline{\ifnum \&yarg <0 \&downline \else \&upline\fi}%
\def\&upline{\hbox to \z@{\hskip -\&halfwidth \vrule width \&wholewidth
height \&linelen depth \z@\hss}}%
\def\&downline{\hbox to \z@{\hskip -\&halfwidth \vrule width \&wholewidth
height \z@ depth \&linelen \hss}}%
\def\&upvector{\&upline\setbox\&tempboxa\hbox{\&linefnt\char'66}\raise
\&linelen \hbox to\z@{\lower \ht\&tempboxa\box\&tempboxa\hss}}%
\def\&downvector{\&downline\lower \&linelen
\hbox to \z@{\&linefnt\char'77\hss}}%
\def\&badlinearg{\errmessage{Bad \string\arrow\space argument.}}%
%INITIALIZATION
\thinlines
% Allocate registers using the rules of p.~346 of {\sl The \TeX book}.
\countdef\&xarg 0
\countdef\&yarg 2
\countdef\&yyarg 4
\countdef\&tempcnta 6
\countdef\&tempcntb 8
\dimendef\&linelen 0
\dimendef\&clnwd 2
\dimendef\&clnht 4
\dimendef\&tempdima 6
\dimendef\&tempdimb 8
\chardef\@arrbox 0
\chardef\&linechar 2
\chardef\&tempboxa 2 % \&linechar and \&tempboxa don't interfere.
% Macros for abstract nonsense
% Macros for slanted lines and arrows.
\let\lft^%
\let\rt_% distinguish between \rt and \lft
\newif\if@pslope % test for positive slope
\def\@findslope(#1,#2){\ifnum#1>0
\ifnum#2>0 \@pslopetrue \else\@pslopefalse\fi \else
\ifnum#2>0 \@pslopefalse \else\@pslopetrue\fi\fi}%
\def\generalsmap(#1,#2){\getm@rphposn(#1,#2)\plnmorph\futurelet\next\addm@rph}%
% Put arrow in \@arrbox, then add morphisms later.
% Single lines and arrows.
\def\sline(#1,#2){\setbox\@arrbox=\hbox{\drawline(#1,#2){\sarrowlength}}%
\@findslope(#1,#2)\d@@blearrfalse\generalsmap(#1,#2)}%
\def\arrow(#1,#2){\setbox\@arrbox=\hbox{\drawvector(#1,#2){\sarrowlength}}%
\@findslope(#1,#2)\d@@blearrfalse\generalsmap(#1,#2)}%
% Double lines, arrows, and adjoint arrows.
\newif\ifd@@blearr
\def\bisline(#1,#2){\@findslope(#1,#2)%
\if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
\getch@nnel(#1,#2)\setbox\@arrbox=\hbox{\@upordown\@vchannel
\rlap{\drawline(#1,#2){\sarrowlength}}%
\hskip\@hchannel\hbox{\drawline(#1,#2){\sarrowlength}}}%
\d@@blearrtrue\generalsmap(#1,#2)}%
\def\biarrow(#1,#2){\@findslope(#1,#2)%
\if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
\getch@nnel(#1,#2)\setbox\@arrbox=\hbox{\@upordown\@vchannel
\rlap{\drawvector(#1,#2){\sarrowlength}}%
\hskip\@hchannel\hbox{\drawvector(#1,#2){\sarrowlength}}}%
\d@@blearrtrue\generalsmap(#1,#2)}%
\def\adjarrow(#1,#2){\@findslope(#1,#2)%
\if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
\getch@nnel(#1,#2)\setbox\@arrbox=\hbox{\@upordown\@vchannel
\rlap{\drawvector(#1,#2){\sarrowlength}}%
\hskip\@hchannel\hbox{\drawvector(-#1,-#2){\sarrowlength}}}%
\d@@blearrtrue\generalsmap(#1,#2)}%
% Morphism placement.
% Logic for positioning morphisms on slanted arrows:
% If \lft then
% \hskip by -\@hmorphdflt
% if \@pslopetrue then \raise by \@vmorphdflt
% else \lower by \@vmorphdflt
% Else if \rt then
% \hskip by \@hmorphdflt
% if \@pslopetrue then \lower by \@vmorphdflt
% else \raise by \@vmorphdflt
%
% \@hmorphdflt and \@vmorphdflt defined by \getm@rphposn
% Advance \morphdist by .5\channelwidth if double arrows
%
% Use \@shiftmorph to allow users to move morphisms
% Logic for \@shiftmorph:
% If \rtm@rph then
% if \hmorphposnrt=0 then hshift by\hmorphposn else hshift by\hmorphposnrt
% if \vmorphposnrt=0 then vshift by\vmorphposn else vshift by\vmorphposnrt
% Else
% if \hmorphposnlft=0 then hshift by\hmorphposn else hshift by\hmorphposnlft
% if \vmorphposnlft=0 then vshift by\vmorphposn else vshift by\vmorphposnlft
\newif\ifrtm@rph
\def\@shiftmorph#1{\hbox{\setbox0=\hbox{$\scriptstyle#1$}%
\setbox1=\hbox{\hskip\@hm@rphshift\raise\@vm@rphshift\copy0}%
\wd1=\wd0 \ht1=\ht0 \dp1=\dp0 \box1}}%
\def\@hm@rphshift{\ifrtm@rph
\ifdim\hmorphposnrt=\z@\hmorphposn\else\hmorphposnrt\fi \else
\ifdim\hmorphposnlft=\z@\hmorphposn\else\hmorphposnlft\fi \fi}%
\def\@vm@rphshift{\ifrtm@rph
\ifdim\vmorphposnrt=\z@\vmorphposn\else\vmorphposnrt\fi \else
\ifdim\vmorphposnlft=\z@\vmorphposn\else\vmorphposnlft\fi \fi}%
\def\addm@rph{\ifx\next\lft\let\temp=\lftmorph\else
\ifx\next\rt\let\temp=\rtmorph\else\let\temp\relax\fi\fi \temp}%
\def\plnmorph{\dimen1\wd\@arrbox \ifdim\dimen1<\z@ \dimen1-\dimen1\fi
\vcenter{\box\@arrbox}}%
\def\lftmorph\lft#1{\rtm@rphfalse \setbox0=\@shiftmorph{#1}%
\if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
\llap{\@upordown\@vmorphdflt\hbox to\dimen1{\hss % \dimen1=\wd\@arrbox
\llap{\box0}\hss}\hskip\@hmorphdflt}\futurelet\next\addm@rph}%
\def\rtmorph\rt#1{\rtm@rphtrue \setbox0=\@shiftmorph{#1}%
\if@pslope \let\@upordown\lower \else \let\@upordown\raise\fi
\llap{\@upordown\@vmorphdflt\hbox to\dimen1{\hss
\rlap{\box0}\hss}\hskip-\@hmorphdflt}\futurelet\next\addm@rph}%
% Get appropriate shifts for morphisms and double lines at various slopes
% Syntax e.g.: \@getshift(1,2){\@hchannel}{\@vchannel}{\channelwidth}%
\def\getm@rphposn(#1,#2){\ifd@@blearr \dimen@\morphdist \advance\dimen@ by
.5\channelwidth \@getshift(#1,#2){\@hmorphdflt}{\@vmorphdflt}{\dimen@}\else
\@getshift(#1,#2){\@hmorphdflt}{\@vmorphdflt}{\morphdist}\fi}%
\def\getch@nnel(#1,#2){\ifdim\hchannel=\z@ \ifdim\vchannel=\z@
\@getshift(#1,#2){\@hchannel}{\@vchannel}{\channelwidth}%
\else \@hchannel\hchannel \@vchannel\vchannel \fi
\else \@hchannel\hchannel \@vchannel\vchannel \fi}%
\def\@getshift(#1,#2)#3#4#5{\dimen@ #5\relax
\&xarg #1\relax \&yarg #2\relax
\ifnum\&xarg<0 \&xarg -\&xarg \fi
\ifnum\&yarg<0 \&yarg -\&yarg \fi
\ifnum\&xarg<\&yarg \&negargtrue \&yyarg\&xarg \&xarg\&yarg \&yarg\&yyarg\fi
\ifcase\&xarg \or % There is no case 0
\ifcase\&yarg % case 1
\dimen@i \z@ \dimen@ii \dimen@ \or % case (1,0)
\dimen@i .7071\dimen@ \dimen@ii .7071\dimen@ \fi \or
\ifcase\&yarg % case 2
\or % case 0,2 wrong
\dimen@i .4472\dimen@ \dimen@ii .8944\dimen@ \fi \or
\ifcase\&yarg % case 3
\or % case 0,3 wrong
\dimen@i .3162\dimen@ \dimen@ii .9486\dimen@ \or
\dimen@i .5547\dimen@ \dimen@ii .8321\dimen@ \fi \or
\ifcase\&yarg % case 4
\or % case 0,2,4 wrong
\dimen@i .2425\dimen@ \dimen@ii .9701\dimen@ \or\or
\dimen@i .6\dimen@ \dimen@ii .8\dimen@ \fi \or
\ifcase\&yarg % case 5
\or % case 0,5 wrong
\dimen@i .1961\dimen@ \dimen@ii .9801\dimen@ \or
\dimen@i .3714\dimen@ \dimen@ii .9284\dimen@ \or
\dimen@i .5144\dimen@ \dimen@ii .8575\dimen@ \or
\dimen@i .6247\dimen@ \dimen@ii .7801\dimen@ \fi \or
\ifcase\&yarg % case 6
\or % case 0,2,3,4,6 wrong
\dimen@i .1645\dimen@ \dimen@ii .9864\dimen@ \or\or\or\or
\dimen@i .6402\dimen@ \dimen@ii .7682\dimen@ \fi \fi
\if&negarg \&tempdima\dimen@i \dimen@i\dimen@ii \dimen@ii\&tempdima\fi
#3\dimen@i\relax #4\dimen@ii\relax }%
\catcode`\&=4 % Back to alignment tab
% Macros for horizontal and vertical lines and arrows.
% These macros use an idea from Appendix~D, p.~374 of the Texbook.
% Usage: `\mapright^f', `\mapleft', etc.
% `\mapdown\lft{f}', `\mapup\rt{g}', `\mapdown', etc.
% \toks@ will contain the token sequence that defines the arrow and morphisms;
% ensure that \toks@={\mathop{\vcenter{\smash{horiz. arrow}}}\limits} to start.
\def\generalhmap{\futurelet\next\@generalhmap}%
\def\@generalhmap{\ifx\next^ \let\temp\generalhm@rph\else
\ifx\next_ \let\temp\generalhm@rph\else \let\temp\m@kehmap\fi\fi \temp}%
\def\generalhm@rph#1#2{\ifx#1^
\toks@=\expandafter{\the\toks@#1{\rtm@rphtrue\@shiftmorph{#2}}}\else
\toks@=\expandafter{\the\toks@#1{\rtm@rphfalse\@shiftmorph{#2}}}\fi
\generalhmap}%
\def\m@kehmap{\mathrel{\smash{\the\toks@}}}%
\def\mapright{\toks@={\mathop{\vcenter{\smash{\drawrightarrow}}}\limits}%
\generalhmap}%
\def\mapleft{\toks@={\mathop{\vcenter{\smash{\drawleftarrow}}}\limits}%
\generalhmap}%
\def\bimapright{\toks@={\mathop{\vcenter{\smash{\drawbirightarrow}}}\limits}%
\generalhmap}%
\def\bimapleft{\toks@={\mathop{\vcenter{\smash{\drawbileftarrow}}}\limits}%
\generalhmap}%
\def\adjmapright{\toks@={\mathop{\vcenter{\smash{\drawadjrightarrow}}}\limits}%
\generalhmap}%
\def\adjmapleft{\toks@={\mathop{\vcenter{\smash{\drawadjleftarrow}}}\limits}%
\generalhmap}%
\def\hline{\toks@={\mathop{\vcenter{\smash{\drawhline}}}\limits}%
\generalhmap}%
\def\bihline{\toks@={\mathop{\vcenter{\smash{\drawbihline}}}\limits}%
\generalhmap}%
\def\drawrightarrow{\hbox{\drawvector(1,0){\harrowlength}}}%
\def\drawleftarrow{\hbox{\drawvector(-1,0){\harrowlength}}}%
\def\drawbirightarrow{\hbox{\raise.5\channelwidth
\hbox{\drawvector(1,0){\harrowlength}}\lower.5\channelwidth
\llap{\drawvector(1,0){\harrowlength}}}}%
\def\drawbileftarrow{\hbox{\raise.5\channelwidth
\hbox{\drawvector(-1,0){\harrowlength}}\lower.5\channelwidth
\llap{\drawvector(-1,0){\harrowlength}}}}%
\def\drawadjrightarrow{\hbox{\raise.5\channelwidth
\hbox{\drawvector(-1,0){\harrowlength}}\lower.5\channelwidth
\llap{\drawvector(1,0){\harrowlength}}}}%
\def\drawadjleftarrow{\hbox{\raise.5\channelwidth
\hbox{\drawvector(1,0){\harrowlength}}\lower.5\channelwidth
\llap{\drawvector(-1,0){\harrowlength}}}}%
\def\drawhline{\hbox{\drawline(1,0){\harrowlength}}}%
\def\drawbihline{\hbox{\raise.5\channelwidth
\hbox{\drawline(1,0){\harrowlength}}\lower.5\channelwidth
\llap{\drawline(1,0){\harrowlength}}}}%
% Vertical arrows are handled differently because there is no \mathop.
% \toks@ will contain the token sequence that defines the arrow and morphisms;
% ensure that \toks@={\vcenter{vertical arrow}} to start.
\def\generalvmap{\futurelet\next\@generalvmap}%
\def\@generalvmap{\ifx\next\lft \let\temp\generalvm@rph\else
\ifx\next\rt \let\temp\generalvm@rph\else \let\temp\m@kevmap\fi\fi \temp}%
% Prepend or append to \toks@ depending on \rt or \lft.
\toksdef\toks@@=1
\def\generalvm@rph#1#2{\ifx#1\rt % append
\toks@=\expandafter{\the\toks@
\rlap{$\vcenter{\rtm@rphtrue\@shiftmorph{#2}}$}}\else % prepend
\toks@@={\llap{$\vcenter{\rtm@rphfalse\@shiftmorph{#2}}$}}%
\toks@=\expandafter\expandafter\expandafter{\expandafter\the\expandafter
\toks@@ \the\toks@}\fi \generalvmap}%
\def\m@kevmap{\the\toks@}%
\def\mapdown{\toks@={\vcenter{\drawdownarrow}}\generalvmap}%
\def\mapup{\toks@={\vcenter{\drawuparrow}}\generalvmap}%
\def\bimapdown{\toks@={\vcenter{\drawbidownarrow}}\generalvmap}%
\def\bimapup{\toks@={\vcenter{\drawbiuparrow}}\generalvmap}%
\def\adjmapdown{\toks@={\vcenter{\drawadjdownarrow}}\generalvmap}%
\def\adjmapup{\toks@={\vcenter{\drawadjuparrow}}\generalvmap}%
\def\vline{\toks@={\vcenter{\drawvline}}\generalvmap}%
\def\bivline{\toks@={\vcenter{\drawbivline}}\generalvmap}%
\def\drawdownarrow{\hbox to5pt{\hss\drawvector(0,-1){\varrowlength}\hss}}%
\def\drawuparrow{\hbox to5pt{\hss\drawvector(0,1){\varrowlength}\hss}}%
\def\drawbidownarrow{\hbox to5pt{\hss\hbox{\drawvector(0,-1){\varrowlength}}%
\hskip\channelwidth\hbox{\drawvector(0,-1){\varrowlength}}\hss}}%
\def\drawbiuparrow{\hbox to5pt{\hss\hbox{\drawvector(0,1){\varrowlength}}%
\hskip\channelwidth\hbox{\drawvector(0,1){\varrowlength}}\hss}}%
\def\drawadjdownarrow{\hbox to5pt{\hss\hbox{\drawvector(0,-1){\varrowlength}}%
\hskip\channelwidth\lower\varrowlength
\hbox{\drawvector(0,1){\varrowlength}}\hss}}%
\def\drawadjuparrow{\hbox to5pt{\hss\hbox{\drawvector(0,1){\varrowlength}}%
\hskip\channelwidth\raise\varrowlength
\hbox{\drawvector(0,-1){\varrowlength}}\hss}}%
\def\drawvline{\hbox to5pt{\hss\drawline(0,1){\varrowlength}\hss}}%
\def\drawbivline{\hbox to5pt{\hss\hbox{\drawline(0,1){\varrowlength}}%
\hskip\channelwidth\hbox{\drawline(0,1){\varrowlength}}\hss}}%
% Macros for setting commutative diagrams.
% A macro inspired by Ex.~18.46 of the TeXbook.
\def\commdiag#1{\null\,
\vcenter{\commdiagbaselines
\m@th\ialign{\hfil$##$\hfil&&\hfil$\mkern4mu ##$\hfil\crcr
\mathstrut\crcr\noalign{\kern-\baselineskip}
#1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}%
\def\commdiagbaselines{\baselineskip15pt \lineskip3pt \lineskiplimit3pt }%
% A macro inspired by Francis Borceux's Diagram macros for LaTeX
% (FBORCEUX@BUCLLN11.BITNET).
\def\gridcommdiag#1{\null\,
\vcenter{\offinterlineskip
\m@th\ialign{&\vbox to\vgrid{\vss
\hbox to\hgrid{\hss\smash{$##$}\hss}}\crcr
\mathstrut\crcr\noalign{\kern-\vgrid}
#1\crcr\mathstrut\crcr\noalign{\kern-.5\vgrid}}}\,}%
% Default parameters
% Define default heights and widths for arrows using the golden ratio.
% Note that 5:3 (for sline) and 3:2 (for vector) approximate this ratio.
\newdimen\harrowlength \harrowlength=60pt
\newdimen\varrowlength \varrowlength=.618\harrowlength
\newdimen\sarrowlength \sarrowlength=\harrowlength
% Morphism placement
\newdimen\hmorphposn \hmorphposn=\z@
\newdimen\vmorphposn \vmorphposn=\z@
\newdimen\morphdist \morphdist=4pt
\dimendef\@hmorphdflt 0 % These two dimensions are
\dimendef\@vmorphdflt 2 % defined by \getm@rphposn
\newdimen\hmorphposnrt \hmorphposnrt=\z@
\newdimen\hmorphposnlft \hmorphposnlft=\z@
\newdimen\vmorphposnrt \vmorphposnrt=\z@
\newdimen\vmorphposnlft \vmorphposnlft=\z@
\let\hmorphposnup=\hmorphposnrt
\let\hmorphposndn=\hmorphposnlft
\let\vmorphposnup=\vmorphposnrt
\let\vmorphposndn=\vmorphposnlft
% Default grid size for \gridcommdiag
\newdimen\hgrid \hgrid=15pt
\newdimen\vgrid \vgrid=15pt
% Horizontal and vertical distance between double lines and arrows.
\newdimen\hchannel \hchannel=0pt
\newdimen\vchannel \vchannel=0pt
\newdimen\channelwidth \channelwidth=3pt
\dimendef\@hchannel 0 % Defined via the
\dimendef\@vchannel 2 % macro \getch@nnel
\catcode`& = \@oldandcatcode
\catcode`@ = \@oldatcatcode
% Some examples
%\parskip=20pt
%
%The first example:
%$$\commdiag{A&\mapright^f&B&\mapleft^g&C\cr
%\mapdown\lft\psi&\arrow(3,-2)\rt s&\mapup\rt\phi&
%\arrow(-3,2)\lft l&\mapdown\rt\theta\cr
%D&\mapright_h&E&\mapleft_{\int_0^t{\bf A}\,d\sigma}&F\cr}$$
%
%
%Covering homotopy property (Bott and Tu, {\it Differential Forms in
%Algebraic Topology}):
%$$\commdiag{Y&\mapright^f&E\cr \mapdown&\arrow(3,2)\lft{f_t}&\mapdown\cr
%Y\times I&\mapright^{\bar f_t}&X}$$
%
%
%Universal mapping property (Warner, {\it Foundations of Differentiable
%Manifolds and Lie Groups}): $$\varrowlength=20pt
%\commdiag{V\otimes W\cr \mapup\lft\phi&\arrow(3,-1)\rt{\tilde l}\cr
%V\times W&\mapright^l&U\cr}$$
%
%
%A cube (Francis Borceux):
%$$\harrowlength=48pt \varrowlength=48pt \sarrowlength=20pt
%\def\cross#1#2{\setbox0=\hbox{$#1$}%
% \hbox to\wd0{\hss\hbox{$#2$}\hss}\llap{\unhbox0}}
%\gridcommdiag{&&B&&\mapright^b&&D\cr
%&\arrow(1,1)\lft a&&&&\arrow(1,1)\lft d\cr
%A&&\cross{\hmorphposn=12pt\mapright^c}{\vmorphposn=-12pt\mapdown\lft f}
%&&C&&\mapdown\rt h\cr\cr
%\mapdown\lft e&&F&&\cross{\hmorphposn=-12pt\mapright_j}
%{\vmorphposn=12pt\mapdown\rt g}&&H\cr
%&\arrow(1,1)\lft i&&&&\arrow(1,1)\rt l\cr
%E&&\mapright_k&&G\cr}$$
%
%Zassenhaus's Butterfly Lemma (Lang, {\it Algebra}):
%$$\hgrid=16pt \vgrid=8pt \sarrowlength=32pt
%\def\cross#1#2{\setbox0=\hbox{$#1$}%
% \hbox to\wd0{\hss\hbox{$#2$}\hss}\llap{\unhbox0}}
%\def\l#1{\llap{$#1$\hskip.5em}}
%\def\r#1{\rlap{\hskip.5em$#1$}}
%\gridcommdiag{&&U&&&&V\cr &&\bullet&&&&\bullet\cr
%&&\sarrowlength=16pt\sline(0,1)&&&&\sarrowlength=16pt\sline(0,1)\cr
%&&\l{u(U\cap V)}\bullet&&&&\bullet\r{(U\cap V)v}\cr
%&&&\sline(2,-1)&&\sline(2,1)\cr
%&&\cross{=}{\sline(0,1)}&&\bullet&&\cross{=}{\sline(0,1)}\cr\cr
%&&\l{^{\textstyle u(U\cap v)}}\bullet&&\cross{=}{\sline(0,1)}&&
% \bullet\r{^{\textstyle(u\cap V)v}}\cr
%&\sline(2,1)&&\sline(2,-1)&&\sline(2,1)&&\sline(2,-1)\cr
%\l{u}\bullet&&&&\bullet&&&&\bullet\r{v}\cr
%&\sline(2,-1)&&\sline(2,1)&&\sline(2,-1)&&\sline(2,1)\cr
%&&\bullet&&&&\bullet\cr &&u\cap V&&&&U\cap v\cr}$$
|