% Logic Eprints
%Submitted 0635 Sat Oct 09, 1993 by: andretta@di.unito.it (  )
%logic/andretta/how_to_win_some_simple_iteration_games
%logic/andretta/how_to_win_some_simple_iteration_games/diagram.sty
%


% diagram.sty: LaTeX commutative diagram macros
% Author: Paul Burchard <burchard@math.utah.edu>
% Version: 13 Jan 1991
%
% Copyright (c) 1990 by Paul Burchard
%
% Anyone may use this file or its programs for educational or non-profit
% purposes if this file is not altered or renamed in any way.  All other
% rights reserved.  Due credit should be given to Marc-Paul van der Hulst
% whose macros inspired many of the features offered by this package.  Thanks
% also to Bill Richter for his topological torture testing of this package.
%
%
% ---INTRODUCTION---
%
% The "diagram" environment provided by this document-style option allows the
% user to create complex commutative diagrams whose arrows may (in any
% combination):
%
%    * slant in any of the 16 principal compass directions (rounded to grid)
%    * span several rows and/or columns of the diagram
%    * have labels on either or both sides, with adjustable positioning
%    * intersect other arrows
%    * be dotted or headless arrows instead of ordinary arrows
%
% The environment automatically generates a correctly scaled and shaped
% rectangular---not necessarily square---grid so that formulas may be
% comfortably placed at the "nodes" of this grid.  Nodes may then be
% connected with arrows; the environment will automatically leave room so
% that the arrows don't touch the formulas at those nodes.
%
% Here are some examples of commands to produce arrows:
%
%    \arrow{e}                      % simple east-pointing arrow 1 col wide
%    \arrow{s,lr}{\alpha}{\beta}    % south-pointing, labelled on left by
%                                   %    $\alpha$ and on right by $\beta$
%    \arrow[2]{ene,t,-}{bond}       % double-long eastnortheast-pointing
%                                   %    (4 cols right by 2 rows up) headless
%                                   %    arrow, with top label $bond$
%
% Here is an example diagram (the center of the diagram contains two
% intersecting diagonal arrows, in case it's not clear!):
%
%                        \[
%       a       b*       \begin{diagram}[B^*]
%    A ---> B* ---> C      \node{A} \arrow{e,t}{a} \arrow{s,l}{c} \arrow{ese}
%    | \____ _____/ |        \node{B^*} \arrow{e,t}{b^*}
%  c |   ___X____   | d        \node{C} \arrow{s,r}{d} \arrow{wsw} \\
%    v `/_      _\' v      \node{D} \arrow[2]{e,b}{e}
%    D -----------> E        \node[2]{E}
%           e            \end{diagram}
%                        \]
%
%
% ---USER'S MANUAL---
%
% To use the "diagram" macros, make sure that you or your system have the
% "auxdefs.sty" style option available.  Then begin your LaTeX file with:
%
%    \documentstyle[diagram]{DOCSTYLE}
%
% where DOCSTYLE is your document style (e.g., "article").  Now you will be
% able to use the "diagram" environment.  It should be used in MATH MODE only.
% Its usage is as follows:
%
%    \begin{diagram}[BIGNODE]
%       NODE ARROW ARROW ... NODE ARROW ARROW ... .... \\
%       NODE ARROW ARROW ... NODE ARROW ARROW ... .... \\
%       ...
%       NODE ARROW ARROW ... NODE ARROW ARROW ... ....
%    \end{diagram}
%
% where the optional argument BIGNODE is the text of the widest and tallest
% NODE, which is used to determine the correct _size_ and _shape_ for the
% grid.  The _size_ can be adjusted to taste by setting \dgARROWLENGTH; see
% the section on user-adjustable parameters below.  (The _shape_ will be
% determined by \dgCOLUMNWIDTH if you do not specify the BIGNODE.)
%
% Each NODE places a centered formula at a new grid point, and the ARROWs
% which follow this NODE but precede the next NODE will be attached by their
% tails to the same grid point.  A node is specified by:
%
%    \node[NCOLS]{FORMULA}
%
% where the optional argument NCOLS tells how many grid columns to move
% forward from the previous node (default is 1), and the FORMULA is math mode
% material. 
%
% The \\ command moves to the next grid row.  As usual, the final row
% should not end with a \\, and any row may be prematurely terminated.
% More generally, it is possible to move NROWS rows down at once using
%
%   \\[NROWS]
%
%
% An ARROW is specified by the \arrow command, which may also be used in
% MATH MODE independent of the "diagram" environment.  Its usage depends
% on the number of labels desired:
%
%    \arrow[SIZE]{TYPE,OPTIONS}
%    \arrow[SIZE]{TYPE,ONELABEL,OPTIONS}{LABEL}
%    \arrow[SIZE]{TYPE,TWOLABEL,OPTIONS}{LABEL1}{LABEL2}
%
% Here the optional integer argument SIZE tells how many times its normal
% length the arrow should be made (thus \arrow[2]{e} will span two columns
% while \arrow[2]{s} will span two rows).
%
% The arrow TYPE may be chosen from the compass point directions:  
%
%    n,e,s,w,ne,nw,se,sw,nne,nnw,sse,ssw,ene,ese,wnw,wsw
%
% Any LABELs present are math mode material.  The ONELABEL specifier may be
% chosen from:
%
%    t         % top
%    b         % bottom
%    l         % left (use ONLY with vertical arrows)
%    r         % right (use ONLY with vertical arrows)
%
% The TWOLABEL specifier may be chosen from:
%
%    tb        % top and bottom
%    lr        % left and right (use ONLY with vertical arrows)
%
% Any OPTIONs (with their preceding commas) are optional, and may be selected
% from this list:
%
%    ..        % dotted arrow			]
%    -         % headless arrow (i.e. a line)	]--- mutually exclusive
%    !         % invisible arrow		]
%
%    FRAC      % place label at the point FRAC/ARROWPARTS of the way
%              %    from arrow tail to arrow tip
%
% The FRAC option is allowed to be any single digit 1,2,3,...,ARROWPARTS-1.
% The default value of ARROWPARTS is 4 (it can be changed, see below).
%
%
% ---USER-ADJUSTABLE PARAMETERS---
%
% The diagram environment provides a rectangular grid whose size and aspect
% ratio (width:height of grid rectangles) are chosen on the basis of
% BIGNODE.  Due to font limitations, the only grid aspect ratios for which
% LaTeX can provide the full required set of compass-point arrows are 1:2,
% 2:3, 1:1, 3:2, 2:1 (but we don't use the first two).  So the integer
% \dgMAXSQUARE is the maximum aspect ratio of BIGNODE for which the square
% (1:1) grid will be chosen, while \dgMINDBLSQ is the minimum aspect ration
% of BIGNODE for which the ``double-square'' (2:1) grid will be chosen; in
% between, the 3:2 grid is used. 
%
\newcount\dgMAXSQUARE   \dgMAXSQUARE=4\relax
\newcount\dgMINDBLSQ    \dgMINDBLSQ=10\relax
%
% If no BIGNODE is supplied, the default value is:
%    \makebox[\dgCOLUMNWIDTH]{$()$}
%
\newskip\dgCOLUMNWIDTH  \dgCOLUMNWIDTH=2em\relax
%
% Once the grid aspect ratio has been chosen, the grid size is determined
% from BIGNODE and the requirement that horizontal arrows must have at least
% \dgARROWLENGTH of room between two adjacent BIGNODEs, when padding is taken
% into account.  All nodes will be padded (to keep arrows away from them) by
% increasing their apparent horizontal size by \dgHORIZPAD and their apparent
% vertical size by \dgVERTPAD.
%
\newskip\dgARROWLENGTH  \dgARROWLENGTH=2.5em\relax
\newskip\dgHORIZPAD     \dgHORIZPAD=1em\relax
\newskip\dgVERTPAD      \dgVERTPAD=2ex\relax
%
% \dgLABELOFFSET is the (approximate) distance which will separate labels
% from their arrows.  An arrow is divided into \dgARROWPARTS parts for
% custom positioning of labels along the arrow; the only sensible choices for
% this number are 2,4,6,8,10.
%
\newskip\dgLABELOFFSET  \dgLABELOFFSET=.7ex\relax
\newcount\dgARROWPARTS	\dgARROWPARTS=4\relax
%
% The following two parameters regulate the appearance of dotted arrows.
%
\newskip\dgDOTSPACING \dgDOTSPACING=0.35em
\newskip\dgDOTSIZE \dgDOTSIZE=1.5\fontdimen8\tenln
%
% By default, nodes are typeset \displaystyle, and labels \scriptstyle.  This
% is controlled by the commands \dgeverynode (which is executed prior to the
% FORMULA of every node) and \dgeverylabel (which is executed prior to the
% LABEL formula of every label).  They can be changed with \renewcommand.
%
\newcommand{\dgeverynode}{\displaystyle}
\newcommand{\dgeverylabel}{\scriptstyle}
%
%
% ---TECHNICAL NOTES---
%
% In order to modulate the size of horizontal arrows to fit in the gaps left
% between formulas (which may be several columns wide), all the horizontal
% arrows occurring in a row are first saved up (in \dg@ALIST) along with
% the data on node widths (in \dg@NLIST).  Then, once the row is otherwise
% complete, the saved horizontal arrows are drawn in.
%
% All command names defined here except \diagram, \enddiagram, \node,
% \arrow, and \\ begin with "\dg".  All private commands contain an `@'
% in their name.  The commands \node and \\ are only defined within the
% "diagram" environment.
%
% Requires the presence of "auxdefs.sty".
%
% Spaces following the \end{diagram} are ignored.
%
%
% ---INCLUDED MACROS---
%
% Use "auxdefs" to conveniently define macros/environs with an optional arg,
% or environments which ignore subsequent spaces.
%
\ifx\@auxdefsloaded\relax
\else \input{auxdefs.sty}\fi
%
%
% ---INTERNAL VARIABLES---
%
\newcount\dg@HORIZ
\newcount\dg@VERT
\newcount\dg@SIZE
\newcount\dg@USERSIZE
\newcount\dg@X
\newcount\dg@XMAX
\newcount\dg@Y
\newcount\dg@XGRID
\newcount\dg@YGRID
\newcount\dg@DX
\newcount\dg@DY
\newcount\dg@XLBL
\newcount\dg@YLBL
\newcount\dg@XOFFSET
\newcount\dg@YOFFSET
\newcount\dg@LBLOFF
\newcount\dg@XLBLOFF
\newcount\dg@YLBLOFF
\newcount\dg@LBLPOS
\newcount\dg@XNODE
\newcount\dg@YNODE
\newcount\dg@XTEMP
\newcount\dg@YTEMP
\newcount\dg@ZTEMP
\newcount\dg@XEND
\newcount\dg@WEND
\newskip\dg@XPAD
\newskip\dg@YPAD
\newbox\dg@NODEBOX
\newif\ifdg@SAVE
%
%
% ---THE DIAGRAM ENVIRONMENT---
%
% For usage, see above.
% It ignores spaces following the \end{diagram},
% just like most LaTeX built-in environments do (thus the `*').
%
\newoptenvironment*{diagram}{\hbox to\dgCOLUMNWIDTH{$()$\hss}}[1]{%
   % Determine unpadded width and (height+depth) of BIGNODE (first in sp's).
   \setbox\dg@NODEBOX=\hbox{$\dgeverynode{#1}$}%
   \dg@XNODE=\wd\dg@NODEBOX
   \dg@YNODE=\ht\dg@NODEBOX \advance\dg@YNODE by\dp\dg@NODEBOX
   % Choose XGRID:YGRID from 1:1, 3:2, 2:1 (only ones LaTeX can handle).
   % Make decision on basis of aspect ratio of *unpadded* BIGNODE.
   \ifnum\dg@YNODE=\z@ \dg@ZTEMP=\z@
   \else \dg@ZTEMP=\dg@XNODE \divide\dg@ZTEMP by\dg@YNODE \fi
   \ifnum\dg@ZTEMP>\dgMAXSQUARE
      \ifnum\dg@ZTEMP<\dgMINDBLSQ \dg@XGRID=\thr@@ \dg@YGRID=\tw@
      \else \dg@XGRID=\tw@ \dg@YGRID=\@ne \fi
   \else \dg@XGRID=\@ne \dg@YGRID=\@ne \fi
   % Add padding onto BIGNODE for all other computations.
   \advance\dg@XNODE by\dgHORIZPAD \advance\dg@YNODE by\dgVERTPAD
   % Determine \unitlength so that simple horizontal arrows would be
   %    ARROWLENGTH long if every node were (padded) BIGNODE.
   \dg@XTEMP=\dgARROWLENGTH \advance\dg@XTEMP by\dg@XNODE
   \divide\dg@XTEMP by\dg@XGRID \divide\dg@XTEMP by\@m
   \unitlength=1sp\relax \multiply\unitlength by\dg@XTEMP
   % Convert dimensions to \unitlength's.
   \divide\dg@XNODE by\dg@XTEMP \divide\dg@YNODE by\unitlength
   \dg@LBLOFF=\dgLABELOFFSET \divide\dg@LBLOFF by\unitlength
   % Compute padding for entire diagram.
   \dg@XPAD=\unitlength \multiply\dg@XPAD by\dg@XNODE
      \divide\dg@XPAD by \tw@
   \dg@YPAD=\unitlength \multiply\dg@YPAD by\dg@YNODE
      \divide\dg@YPAD by \tw@
   % diagram is padded \vcenter{}.
   \hspace*{\dg@XPAD}%
   \vcenter\bgroup
      \hsize=0pt\relax\parindent=0pt\relax
      \parskip=0pt\relax\baselineskip=0pt\relax
      \vspace*{\dg@YPAD}%
      \begin{picture}(0,0)%
         % \node, \\, and \arrow are only defined within a diagram.
         \let\node=\dg@node \let\\=\dg@cr \let\arrow=\dg@arrow
         % Reset coordinates (X starts at col -1 so first \node will work).
         \dg@X=-\@m \multiply\dg@X by\dg@XGRID
         \dg@Y=\z@ \dg@XMAX=\z@\relax
         % Clear save space for horizontal arrows; enter save mode.
         \let\dg@ALIST=\@empty \let\dg@NLIST=\@empty \dg@SAVEtrue
% \enddiagram
}{%
         % Exit save mode and print out saved horizontal arrows.
         \dg@SAVEfalse \dg@ALIST
         % Compute size of diagram.
         \global\dg@HORIZ=\dg@XMAX\relax
         \global\dg@VERT=-\dg@Y\relax
      \end{picture}
      % Tell TeX how big grid is, since we made it invisible.
      \raisebox{\z@}[\z@][\dg@VERT\unitlength]{}%
      \vspace*{\dg@YPAD}%
   \egroup
   \hspace*{\dg@HORIZ\unitlength}\hspace*{\dg@XPAD}}%
%
%
% ---MAKING NODES---
%
% Usage: \dg@node[NCOLS]{FORMULA}
\newoptcommand{\dg@node}{\@ne}[2]{%
   % Reset coordinates, updating XMAX.
   \dg@XTEMP=\@m \multiply\dg@XTEMP by\dg@XGRID
   \ifnum #1>\@ne \multiply\dg@XTEMP by #1\relax \fi
   \advance\dg@X by\dg@XTEMP\relax
   \ifnum\dg@XMAX<\dg@X \dg@XMAX=\dg@X \fi
   % Measure FORMULA, saving position and padded width on \dg@NLIST like so:
   %    ...,\dg@XTEMP=<X coord>\relax\dg@ZTEMP=<node width>\relax,...
   \setbox\dg@NODEBOX=\hbox{$\dgeverynode{#2}$}%
   \dg@ZTEMP=\wd\dg@NODEBOX \advance\dg@ZTEMP by\dgHORIZPAD
   \divide\dg@ZTEMP by\unitlength
   \toks\z@=\expandafter{\dg@NLIST}%
   \edef\dg@NLIST{\the\toks\z@,\noexpand\dg@XTEMP=\number\dg@X\noexpand\relax
      \noexpand\dg@ZTEMP=\number\dg@ZTEMP\noexpand\relax}%
   % Center FORMULA at current node.
   \put(\dg@X,\dg@Y){\dg@makebox{\box\dg@NODEBOX}}}%

% Go to beginning of NROWS-th next grid row.
% Usage: \dg@cr[NROWS]
\newoptcommand{\dg@cr}{\@ne}[1]{%
   % Print out saved horizontal arrows; clear save space for next row.
   \dg@SAVEfalse \dg@ALIST
   \let\dg@ALIST=\@empty \let\dg@NLIST=\@empty \dg@SAVEtrue
   % Reset coordinates (X starts at column -1 so first \node will work).
   \dg@YTEMP=\@m \multiply\dg@YTEMP by\dg@YGRID
   \ifnum #1>\@ne \multiply\dg@YTEMP by #1\relax \fi
   \advance\dg@Y by -\dg@YTEMP
   \dg@X=-\@m \multiply\dg@X by\dg@XGRID\relax}%
%
%
% ---MAKING ARROWS---
%
\newoptcommand{\dg@arrow}{\@ne}[2]{%
   % Keep all arrow geometry parameters local (\endgroup is in \dg@process).
   \begingroup
   % Get optional arrow USERSIZE.
   \dg@USERSIZE=#1\relax
   \ifnum\dg@USERSIZE<\@ne \dg@USERSIZE=\@ne \fi
   % Parse arrow specification.
   \dg@parse{#2}%
   % Calculate the rest of the geometry parameters, unless save mode is on
   %    and the arrow is horizontal, in which case just save the arrow.
   \let\dg@process=\dg@draw
   \ifdg@SAVE
      \ifnum\dg@DY=\z@
         % Arrow saved with orig LBLTYPE, so don't re-position args.
         \let\dg@process=\dg@save
         \ifx\dg@label\dgl@b \let\dg@label=\dgl@t \fi
         \ifx\dg@label\dgl@r \let\dg@label=\dgl@l \fi
      \else \dg@calc \fi
   \else \dg@calc \fi
   \dg@label{\dg@process{#1}{#2}}}%

% Parse arrow specification: comma-separated list of features.
% Usage: \dg@parse{TYPE,ONEORTWOLABEL,OPTION,...}
\def\dg@parse#1{%
   % Set default labeling and options.
   \let\dg@label=\dgl@ \dgo@
   % Scan list, reading TYPE, LBLTYPE, and OPTIONs in turn.
   \let\dg@type=\@empty \let\dg@lbltype=\@empty
   \@for\dg@list:=#1\do{%
      \ifx\dg@type\@empty \let\dg@type=\dg@list
      \else\ifx\dg@lbltype\@empty \let\dg@lbltype=\dg@list
         % In case LBLTYPE not given, try it as an OPTION.
         % Note: LBLTYPE and OPTION names must not conflict.
         \@ifundefined{dgo@\dg@list}{}{\@nameuse{dgo@\dg@list}}%
      \else
         % Process OPTIONs in turn; ignore bad OPTIONs.
         \@ifundefined{dgo@\dg@list}{}{\@nameuse{dgo@\dg@list}}%
      \fi\fi}%
   % TYPE must be specified (but default to "e" in case of trouble).
   % Get basic geometry parameters.
   \@ifundefined{dgt@\dg@type}{\dgt@e}{\@nameuse{dgt@\dg@type}}%
   % If LBLTYPE valid, get arg handler.
   \@ifundefined{dgl@\dg@lbltype}{}{\dg@letname\dg@label{dgl@\dg@lbltype}}}

% Draw labelled arrow, using computed parameters.
% After using parameters, keep them local by doing an \endgroup to
%    match \dg@arrow's \begingroup.
% Usage: \dg@draw{IGNORE}{IGNORE}{LABEL1}{LABEL2}
\def\dg@draw#1#2#3#4{%
   \put(\dg@X,\dg@Y){\dg@makebox{%
      \begin{picture}(0,0)%
         \thinlines
         \put(\dg@XOFFSET,\dg@YOFFSET){\dg@VECTOR(\dg@DX,\dg@DY){\dg@SIZE}}%
         \put(\dg@XLBL,\dg@YLBL){\dg@makebox{%
            \begin{picture}(0,0)%
               \put(\dg@XLBLOFF,\dg@YLBLOFF){%
                  \dg@makebox[\dg@LBLONE]{$\dgeverylabel{#3}$}}%
               \put(-\dg@XLBLOFF,-\dg@YLBLOFF){%
                  \dg@makebox[\dg@LBLTWO]{$\dgeverylabel{#4}$}}%
            \end{picture}}}%
      \end{picture}}}
   \endgroup}%

% Instead of drawing arrow now, save it on \dg@ALIST, like so:
%    ...\dg@X=<X coord>\relax\dg@arrow[<size>]{<arrow specs>}<labels>...
% If either LABEL1 or LABEL2 is empty, it will simply be ignored.
% Usage: \dg@save{SIZE}{SPEC}{LABEL1}{LABEL2}
\def\dg@save#1#2#3#4{%
   \endgroup % to match \dg@arrow's \begingroup
   \toks\z@=\expandafter{\dg@ALIST}%
   \toks\tw@={\dg@arrow[#1]{#2}{#3}{#4}}%
   \edef\dg@ALIST{\the\toks\z@%
      \noexpand\dg@X=\number\dg@X\noexpand\relax\the\toks\tw@}}%

% Make \arrow command available for use outside of diagrams.
\newoptcommand{\arrow}{\@ne}[2]{%
   % Parse arrow specification just to check how many labels.
   \dg@parse{#2}%
   % Text arrow uses original LBLTYPE, so don't re-position args.
   \ifx\dg@label\dgl@b \let\dg@label=\dgl@t \fi
   \ifx\dg@label\dgl@r \let\dg@label=\dgl@l \fi
   \dg@label{\dg@textarrow{#1}{#2}}}%

\def\dg@textarrow#1#2#3#4{%
   \mathop{{\dgHORIZPAD=0pt\relax\dgVERTPAD=0pt\relax
      \begin{diagram}[]
         \node{}\arrow[#1]{#2}{#3}{#4}\node{}
      \end{diagram}}}}

% Calculate all the arrow geometry parameters:
%    X, Y, DX, DY, SIZE, XOFFSET, YOFFSET, VECTOR,
%    XLBL, YLBL, XLBLOFF, YLBLOFF, LBLONE, LBLTWO,
% from the (preliminary) values of these basic arrow parameters:
%    X, Y, USERSIZE, SIZE, DX, DY, VECTOR, LBLPOS
% using also the diagram parameters:
%    XGRID, YGRID, YNODE, LBLOFF, NLIST, ARROWPARTS.
% No args.  Uses temp vars XTEMP, YTEMP, ZTEMP, XEND, WEND.
\def\dg@calc{%
   % Adjust arrow direction to GRIDTYPE (1:1, 3:2, or 2:1).
   \multiply\dg@DX by\dg@XGRID \multiply\dg@DY by\dg@YGRID
   \dg@rmcommondiv\tw@\dg@DX\dg@DY
   \dg@rmcommondiv\thr@@\dg@DX\dg@DY
   % Scale arrow to requested USERSIZE.
   \multiply\dg@SIZE by\dg@USERSIZE \multiply\dg@SIZE by\@m
   \ifnum\dg@DX=\z@
      %
      % Vertical arrow.
      %
      % SIZE measures vertical extent.
      \multiply\dg@SIZE by\dg@YGRID
      % Arrow shortened by YNODE and offset by YNODE/2 (sign change below).
      \dg@XOFFSET=\z@ \dg@YOFFSET=\dg@YNODE \divide\dg@YOFFSET by\tw@
      \advance\dg@SIZE by -\dg@YNODE
      % Labels at (YNODE/2 + SIZE*LBLPOS/ARROWPARTS) [SIZE already corrected].
      \def\dg@LBLONE{r}\def\dg@LBLTWO{l}%
      \dg@XLBL=\z@ \dg@YLBL=\dg@SIZE
      \multiply\dg@YLBL by\dg@LBLPOS \divide\dg@YLBL by\dgARROWPARTS\relax
      \advance\dg@YLBL by\dg@YOFFSET
      \dg@changesign\dg@YLBL by\dg@DY
      \dg@changesign\dg@YOFFSET by\dg@DY
   \else
      % Nonvertical arrow, so SIZE measures horizontal extent.
      \multiply\dg@SIZE by\dg@XGRID
      \ifnum\dg@DY=\z@
         %
         % Horizontal arrow---uses info in NLIST.
         %
         % Let padded width of source (target) node be WSOURCE (WTARGET).
         % Arrow tail offset by XOFFSET=WSOURCE/2 (sign corrected below).
         \dg@XEND=\dg@X
         \dg@getwidth{\dg@NLIST}{\dg@XEND}{\dg@WEND}%
         \dg@XOFFSET=\dg@WEND \divide\dg@XOFFSET by\tw@
         \dg@YOFFSET=\z@
         % Arrow SIZE shortened by (WSOURCE+WTARGET)/2.
         \dg@XTEMP=\@m \multiply\dg@XTEMP by\dg@XGRID
         \multiply\dg@XTEMP by\dg@USERSIZE \dg@changesign\dg@XTEMP by\dg@DX
         \advance\dg@XEND by\dg@XTEMP\relax
         \dg@getwidth{\dg@NLIST}{\dg@XEND}{\dg@WEND}%
         \divide\dg@WEND by\tw@
         \advance\dg@SIZE by -\dg@XOFFSET
         \advance\dg@SIZE by -\dg@WEND
         % Labels at (WSOURCE/2 + SIZE*LBLPOS/ARROWPARTS)
         % [SIZE already corrected].
         \def\dg@LBLONE{b}\def\dg@LBLTWO{t}%
         \dg@XLBL=\dg@SIZE
         \multiply\dg@XLBL by\dg@LBLPOS \divide\dg@XLBL by\dgARROWPARTS\relax
         \advance\dg@XLBL by\dg@XOFFSET
         \dg@changesign\dg@XLBL by\dg@DX
         \dg@YLBL=\z@
         \dg@changesign\dg@XOFFSET by\dg@DX
      \else
         %
         % Slanted arrow.
         %
         % Offset arrow in its own dir so as to leave vertical space YNODE/2.
         % SIZE is reduced so other end has same offset.
         \dg@YOFFSET=\dg@YNODE \dg@changesign\dg@YOFFSET by\dg@DY
         \dg@XOFFSET=\dg@YOFFSET
         \multiply\dg@XOFFSET by\dg@DX \divide\dg@XOFFSET by\dg@DY
         \ifnum\dg@XOFFSET>\z@ \advance\dg@SIZE by -\dg@XOFFSET
         \else \advance\dg@SIZE by \dg@XOFFSET \fi
         \divide\dg@XOFFSET by\tw@ \divide\dg@YOFFSET by\tw@
         % Labels at ( XOFFSET+-SIZE*LBLPOS/ARROWPARTS ,
         %             YOFFSET+-SIZE*LBLPOS*DY/(ARROWPARTS*DX) )
         % [SIZE already corrected].
         \def\dg@LBLONE{br}\def\dg@LBLTWO{tl}%
         \ifnum\dg@DX<\z@ \ifnum\dg@DY>\z@
            \def\dg@LBLONE{bl}\def\dg@LBLTWO{tr}\fi\fi
         \ifnum\dg@DX>\z@ \ifnum\dg@DY<\z@
            \def\dg@LBLONE{bl}\def\dg@LBLTWO{tr}\fi\fi
         \dg@XLBL=\dg@SIZE
         \multiply\dg@XLBL by\dg@LBLPOS \divide\dg@XLBL by\dgARROWPARTS\relax
         \dg@changesign\dg@XLBL by\dg@DX
         \dg@YLBL=\dg@XLBL \multiply\dg@YLBL by\dg@DY \divide\dg@YLBL by\dg@DX
         \advance\dg@XLBL by\dg@XOFFSET \advance\dg@YLBL by\dg@YOFFSET
      \fi
   \fi
   % (XLBL,YLBL) is the displacement from the tail NODE to the point along
   % the arrow where the labels will be attached.  The offset of first label
   % from this attachment point is the vector 
   %    (XLBLOFF,YLBLOFF) := LBLOFF*sgn(DX)*(-DY,DX)/max(|DX|,|DY|)
   % if DX is nonzero, and otherwise
   %    (XLBLOFF,YLBLOFF) := LBLOFF*(-1,0);
   % The second label is offset from the same point by (-XLBLOFF,-YLBLOFF).
   \dg@XLBLOFF=-\dg@DY \dg@changesign\dg@XLBLOFF by\dg@DX
   \dg@YLBLOFF=\dg@DX \dg@changesign\dg@YLBLOFF by\dg@DX
   \ifnum\dg@DX=\z@ \dg@XLBLOFF=\m@ne \fi
   \dg@XTEMP=\dg@DX \dg@changesign\dg@XTEMP by\dg@DX
   \dg@YTEMP=\dg@DY \dg@changesign\dg@YTEMP by\dg@DY
   \ifnum\dg@YTEMP>\dg@XTEMP \dg@XTEMP=\dg@YTEMP \fi
   \multiply\dg@XLBLOFF by\dg@LBLOFF \divide\dg@XLBLOFF by\dg@XTEMP
   \multiply\dg@YLBLOFF by\dg@LBLOFF \divide\dg@YLBLOFF by\dg@XTEMP
   \relax}%

% Remove common divisor DIV from two number registers \NUM1 and \NUM2.
% Usage: \dg@rmcommondiv{DIV}{\NUM1}{\NUM2}
% NOTE: uses XTEMP and YTEMP.
\def\dg@rmcommondiv#1#2#3{%
   \dg@XTEMP=#2\relax
   \divide\dg@XTEMP by#1\relax \multiply\dg@XTEMP by#1\relax
   \dg@YTEMP=#3\relax
   \divide\dg@YTEMP by#1\relax \multiply\dg@YTEMP by#1\relax
   \ifnum\dg@XTEMP=#2\relax \ifnum\dg@YTEMP=#3\relax
      \divide#2 by#1\relax \divide#3 by#1\relax \fi\fi}%

% Multiply number register \NUM1 by sign of \NUM2.
% Usage: \dg@changesign\NUM1 by\NUM2   (no space between "by" and \NUM2)
\def\dg@changesign#1by#2{%
   \ifnum #2<\z@ \multiply#1 by\m@ne
   \else\ifnum #2=\z@ #1=\z@ \fi\fi}%

% Determine from NLIST the width of the node at XCOORD and store the
%    answer in number register \WIDTH (if no such node, set \WIDTH=0).
% Usage: \dg@getwidth{NLIST}{XCOORD}{\WIDTH}
% NOTE: Uses XTEMP, ZTEMP.  See \dg@node.
\def\dg@getwidth#1#2#3{%
   #3=\z@
   \expandafter\@for\expandafter\dg@list\expandafter:\expandafter=#1\do{%
      \dg@XTEMP=\m@ne % impossible X in case \dg@list is empty
      \dg@list
      \ifnum #2=\dg@XTEMP #3=\dg@ZTEMP\fi}}%

% \makebox(0,0)[POS]{TEXT} with POS expanded beforehand.
% Usage: \dg@makebox[POS]{TEXT}
\newoptcommand{\dg@makebox}{}[2]{%
   \expandafter\makebox\expandafter(\expandafter
      0\expandafter,\expandafter0\expandafter)\expandafter[#1]{#2}}%

% Produces nothing.
% Usage:\dg@novector(X,Y){LaTeX_LENGTH}
\def\dg@novector(#1,#2)#3{}%

% Dotted arrow.
% Uses temp vars XTEMP, YTEMP, ZTEMP, XEND, WEND.
% Usage:\dg@dotvector(X,Y){LaTeX_LENGTH}
\def\dg@dotvector(#1,#2)#3{%
   \begingroup
   \dg@XTEMP=#1\relax \dg@YTEMP=#2\relax
   \let\dg@NDOTS=\dg@XEND \let\dg@DOTDIAM=\dg@WEND
   % Compute number of dots: make x-spacing be DOTSPACING for arrows
   % of |slope| <= 1, and make y-spacing be DOTSPACING otherwise.
   % This way true spacing is never more than 30 percent off from DOTSPACING.
   \dg@NDOTS=\unitlength \multiply\dg@NDOTS by#3\relax
   \dg@ZTEMP=\dg@YTEMP \dg@changesign\dg@YTEMP by\dg@ZTEMP
   \ifnum\dg@XTEMP>\z@
      \ifnum\dg@YTEMP>\dg@XTEMP
         \multiply\dg@NDOTS by\dg@YTEMP \divide\dg@NDOTS by\dg@XTEMP \fi
   \else\ifnum\dg@XTEMP<\z@
      \ifnum\dg@YTEMP>-\dg@XTEMP
         \multiply\dg@NDOTS by\dg@YTEMP \divide\dg@NDOTS by-\dg@XTEMP \fi
   \fi\fi
   \dg@YTEMP=\dg@ZTEMP
   \divide\dg@NDOTS by\dgDOTSPACING
   % Compute increment vector between dots and round to \unitlength's.
   % Use NDOTS for this, not DOTSPACING, since DOTSPACING not exactly obeyed.
   \dg@ZTEMP=\unitlength \multiply\dg@ZTEMP by#3\relax
   \divide\dg@ZTEMP by\dg@NDOTS
   \ifnum\dg@XTEMP=\z@
      \dg@changesign\dg@ZTEMP by\dg@YTEMP \dg@YTEMP=\dg@ZTEMP
   \else
      \dg@changesign\dg@ZTEMP by\dg@XTEMP
      \multiply\dg@YTEMP by\dg@ZTEMP \divide\dg@YTEMP by\dg@XTEMP
      \dg@XTEMP=\dg@ZTEMP
   \fi
   \divide\dg@XTEMP by\unitlength \divide\dg@YTEMP by\unitlength
   % draw dotted line with \multiput; add arrowhead as zero-length \vector.
   \begin{picture}(0,0)
      \dg@DOTDIAM=\dgDOTSIZE \divide\dg@DOTDIAM by\unitlength
      \multiput(0,0)(\dg@XTEMP,\dg@YTEMP){\dg@NDOTS}{\circle*{\dg@DOTDIAM}}%
      \multiply\dg@XTEMP by\dg@NDOTS \multiply\dg@YTEMP by\dg@NDOTS
      \put(\dg@XTEMP,\dg@YTEMP){\vector(#1,#2){0}}%
   \end{picture}%
   \endgroup}%

% \let command \CMD equal funny-name command \NAME.
% Usage: \dg@letname{\CMD}{NAME}.
\def\dg@letname#1#2{%
   \relax\expandafter\let\expandafter #1\csname #2\endcsname\relax}%

% Arg handlers, one for each LBLTYPE.
% Grab specified labels from following input and feed them to \PROCESS.
% Usage: \dgl@LBLTYPE{\PROCESS}...
\def\dgl@#1{#1{}{}}%
\def\dgl@t#1#2{#1{#2}{}}%
\def\dgl@b#1#2{#1{}{#2}}%
\def\dgl@tb#1#2#3{#1{#2}{#3}}%
\def\dgl@l#1#2{#1{#2}{}}%
\def\dgl@r#1#2{#1{}{#2}}%
\def\dgl@lr#1#2#3{#1{#2}{#3}}%

% Arrow variations, one for each OPTION (plus default).
% Usage: \dgo@OPTION
\@namedef{dgo@}{\let\dg@VECTOR=\vector
   \dg@LBLPOS=\dgARROWPARTS \divide\dg@LBLPOS by\tw@}%
\@namedef{dgo@..}{\let\dg@VECTOR=\dg@dotvector}%
\@namedef{dgo@-}{\let\dg@VECTOR=\line}%
\@namedef{dgo@!}{\let\dg@VECTOR=\dg@novector}%
\@namedef{dgo@1}{\dg@LBLPOS=\@ne\relax}%
\@namedef{dgo@2}{\dg@LBLPOS=\tw@\relax}%
\@namedef{dgo@3}{\dg@LBLPOS=3\relax}%
\@namedef{dgo@4}{\dg@LBLPOS=4\relax}%
\@namedef{dgo@5}{\dg@LBLPOS=5\relax}%
\@namedef{dgo@6}{\dg@LBLPOS=6\relax}%
\@namedef{dgo@7}{\dg@LBLPOS=7\relax}%
\@namedef{dgo@8}{\dg@LBLPOS=8\relax}%
\@namedef{dgo@9}{\dg@LBLPOS=9\relax}%

% Depending on the TYPE, set preliminary values of basic arrow parameters:
%    \dg@DX, \dg@DY, \dg@SIZE,
% to values which would be appropriate for a 1x1, 1:1 grid.
% Usage: \dgt@TYPE
\def\dgt@e{\dg@DX=\@ne \dg@DY=\z@ \dg@SIZE=\@ne}%
\def\dgt@w{\dg@DX=\m@ne \dg@DY=\z@ \dg@SIZE=\@ne}%
\def\dgt@n{\dg@DX=\z@ \dg@DY=\@ne \dg@SIZE=\@ne}%
\def\dgt@s{\dg@DX=\z@ \dg@DY=\m@ne \dg@SIZE=\@ne}%
\def\dgt@ne{\dg@DX=\@ne \dg@DY=\@ne \dg@SIZE=\@ne}%
\def\dgt@se{\dg@DX=\@ne \dg@DY=\m@ne \dg@SIZE=\@ne}%
\def\dgt@nw{\dg@DX=\m@ne \dg@DY=\@ne \dg@SIZE=\@ne}%
\def\dgt@sw{\dg@DX=\m@ne \dg@DY=\m@ne \dg@SIZE=\@ne}%
\def\dgt@nne{\dg@DX=\@ne \dg@DY=\tw@ \dg@SIZE=\@ne}%
\def\dgt@nnw{\dg@DX=\m@ne \dg@DY=\tw@ \dg@SIZE=\@ne}%
\def\dgt@sse{\dg@DX=\@ne \dg@DY=-\tw@ \dg@SIZE=\@ne}%
\def\dgt@ssw{\dg@DX=\m@ne \dg@DY=-\tw@ \dg@SIZE=\@ne}%
\def\dgt@ene{\dg@DX=\tw@ \dg@DY=\@ne \dg@SIZE=\tw@}%
\def\dgt@ese{\dg@DX=\tw@ \dg@DY=\m@ne \dg@SIZE=\tw@}%
\def\dgt@wnw{\dg@DX=-\tw@ \dg@DY=\@ne \dg@SIZE=\tw@}%
\def\dgt@wsw{\dg@DX=-\tw@ \dg@DY=\m@ne \dg@SIZE=\tw@}%


