summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/diagmac
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/diagmac
Initial commit
Diffstat (limited to 'macros/latex/contrib/diagmac')
-rw-r--r--macros/latex/contrib/diagmac/README69
-rw-r--r--macros/latex/contrib/diagmac/diagmac.sty971
l---------macros/latex/contrib/diagmac/diagmac.tex1
-rw-r--r--macros/latex/contrib/diagmac/diagmac.txt779
-rw-r--r--macros/latex/contrib/diagmac/diagmactest.pdfbin0 -> 48428 bytes
-rw-r--r--macros/latex/contrib/diagmac/diagmactest.tex403
6 files changed, 2223 insertions, 0 deletions
diff --git a/macros/latex/contrib/diagmac/README b/macros/latex/contrib/diagmac/README
new file mode 100644
index 0000000000..850781b5d4
--- /dev/null
+++ b/macros/latex/contrib/diagmac/README
@@ -0,0 +1,69 @@
+This directory contains my files that are available by anonymous ftp.
+
+The file reynolds.bib.gz is a large (gzip-encoded) bibliography file
+in an extended bibtex format. It includes all citation used in the
+papers I've written in recent years.
+
+The file ReynoldsJC.bib is an (unencoded) excerpt of reynolds.bib
+limited to my own papers and books, and books in which these papers
+have been republished.
+
+In both of the bibliography files, the field "filename" gives the
+filename by which the paper is made available in this directory.
+Most of these files are gzip-encoded, and are usually available in both
+dvi and postscript form. Some files are in unencoded pdf format; most
+of these are pre-electronic papers that were optically scanned to obtain
+the pdf file. (I apologize for the low image quality of these files.)
+
+One of the pdf files, craftprog.pdf, is very large (28730525 bytes).
+It is an optically scanned image of my book "The Craft of Programming".
+
+There are also six (gzip-encoded) files containing or relating to
+a collection of macros for use with LATEX:
+
+ diagmac.tex (41490 bytes) A collection of macros, both for diagrams
+ in general and category-theory diagrams in particular.
+
+ diagmac.doc (34135 bytes) A user's manual for the diagram macros.
+ This file is meant to be printed directly and not as input to LATEX.
+
+ diagmactest.tex (13069 bytes) A file which, when read by LATEX,
+ will input diagmac.tex and print 8 pages of "Tests of Diagram Macros".
+
+ catmac.tex (50618 bytes) A collection of macros for various notations
+ of category theory and programming language semantics. There is no
+ separate user's manual, but this file contains extensive comments.
+
+ catmactest.tex (16382 bytes) A file which, when read by LATEX,
+ will input catmac.tex and print 15 pages of "Tests of Macros for
+ Category Theory".
+
+ largeoptest.tex (1676 bytes) A file which, when read by LATEX, will
+ input catmac.tex and print 7 pages of "Tests of Large Operator Macros".
+
+These macros are in the public domain, and have not changed in many years.
+Acknowledgement of their usage is not necessary. However, neither I nor CMU
+accept any responsibility for the consequences of errors in these macros or
+their documentation. This is more than the usual disclaimer; TEX is a beastly
+language for programming anything complex, and I am not an expert in its use,
+so that there are probably errors lurking in the macros.
+
+The paper "Separation Logic: A Logic for Shared Mutable Data Structures"
+(seplogic) is copyrighted by the IEEE. They have requested their authors to
+display the following notice:
+
+ "This material is presented to ensure timely dissemination of
+ scholarly and technical work. Copyright and all rights therein
+ are retained by authors or by other copyright holders. All
+ persons copying this information are expected to adhere to the
+ terms and constraints invoked by each author=92s copyright. In
+ most cases, these works may not be reposted without the
+ explicit permission of the copyright holder."
+
+
+ - John C. Reynolds
+ April 29, 2009
+
+
+
+
diff --git a/macros/latex/contrib/diagmac/diagmac.sty b/macros/latex/contrib/diagmac/diagmac.sty
new file mode 100644
index 0000000000..adc96b1aa5
--- /dev/null
+++ b/macros/latex/contrib/diagmac/diagmac.sty
@@ -0,0 +1,971 @@
+%LaTeX style
+%MACROS FOR DIAGRAMS - J. C. Reynolds - December 1987
+
+%This file contains general-purpose macros for drawing diagrams in LATEX,
+%followed by additional macros especially for category-theory diagrams.
+%A user's manual is given in the file diagmac.doc, and a test program is
+%given in the file diagmactest.tex.
+
+%GENERAL-PURPOSE MACROS
+
+%The following control symbols may need to be redefined by the user.
+\def\diagramunit{1pt}%Redefine only in main program or at the beginning
+% of \diagram or \ctdiagram.
+\def\centerheight{3pt}
+\def\edgeheaddisp{4pt}
+\def\circleheaddisp{2pt}
+\def\diameterlist{1pt,2pt,3pt,4pt,5pt,6pt,7pt,8pt,9pt,10pt,11pt,%
+12pt,13pt,14pt,15pt,16pt,20pt,24pt,28pt,32pt,36pt,40pt,}
+%Redefine if circle fonts are different.
+
+%The following registers store the representation of diagram and/or
+%expression programs:
+\newdimen\texpr\newdimen\bexpr\newdimen\lexpr\newdimen\rexpr%current rectangle
+\newdimen\xcenter\newdimen\ycenter%center point
+\newcount\xslope\newcount\yslope%slope of current edge
+\newdimen\xstart\newdimen\ystart%start point of current edge
+\newdimen\xend\newdimen\yend%end point of current edge
+\newdimen\dcircle%diameter of current circle
+\newdimen\xcircle\newdimen\ycircle%center of current circle
+\newcount\zzisedge%1 if current edge is defined, 0 otherwise
+\newcount\zziscircle%1 if current circle is defined, 0 otherwise
+\newbox\zzdiagbox%printable material in state
+\newdimen\zztotlwidth\newdimen\zztotrwidth%horizontal extent of box material
+\newdimen\zztotheight\newdimen\zztotdepth%vertical extent of box material
+
+%The following registers are assigned globally to communicate information
+%across group boundaries:
+\newdimen\zzglobaltotlwidth\newdimen\zzglobaltotrwidth
+\newdimen\zzglobaltotheight\newdimen\zzglobaltotdepth
+\newdimen\zzglobalxcenter\newdimen\zzglobalycenter
+\newcount\zzglobalcnA
+
+%The following registers are used locally for various purposes:
+\newdimen\zzdmA\newdimen\zzdmB\newdimen\zzdmC\newdimen\zzdmD\newdimen\zzdmE
+\newdimen\zzdmF\newdimen\zzdmG\newdimen\zzdmH\newdimen\zzdmI
+\newcount\zzcnA\newcount\zzcnB\newcount\zzcnC
+\newcount\zzcnD\newcount\zzcnE\newcount\zzcnF
+\newcount\zzcnG\newcount\zzcnH\newcount\zzcnI
+
+%Hidden macros and other defined control symbols:
+% generally used macros: \zzsetupbox\zznoshadow\zzissue\zzrecordwidth
+% \zzrecordheight\zzmultdiagramunit\zzmakepicture\zzsqroot\zzdistance
+% \zzreduceterms
+% error-checking macros: \zzisnegside\zzcheckedge\zzcheckslope\zzcheckslopea
+% \zzcheckcircle\zzcheckbool\zzcheckposdimen\zzchecknonnegnum
+% used by \vertex: \zzconsvertexlist\zzconsvertexlista\zzconsvertexlistb
+% used by \rect: \zzprocrect
+% used by \hexagon: \zzprochexagon
+% used by \octagon and \rorect: \zzprococtagon
+% used by \diamond: \zzprocdiamond
+% used by \rorect: \zzprocrorecta\zzsearchdiameterlist\zzsearchdiameterlista
+% \zzsearchdiameterlistb
+% used by \outline: \zzoutlinepoly\zzoutlinepolya\zzoutlinepolyb
+% \zzoutlinepolyc
+% used by \outline with \rorect: \zzoutlinerorect
+% used by \setedge: \zzsearchvertexlist\zzsearchvertexlista
+% \zzsearchvertexlistb
+% used by \shadeedge: \zzcastpoly\zzcastpolya\zzcastpolyb
+% \zzcastpolyc\zzcastpolye\zzcastpolyf\zzcastpolyg
+% used by \drawdashedge, \drawdotedge, and \drawsolidedge: \zzdrawedge
+% used by \drawedgehead: \zzdrawedgeheada
+% used by all abutment macros: \zzslidehoriz\zzslidevert\zzclosestpoly
+% \zzclosestpolya\zzclosestpolyb\zzclosestpolyc\zzclosestpolyd
+% used by edge abutment macros: \zzabut
+% used by circle abutment macros: \zzabutcircle\zzabutcirclea\zzrotate
+% used by \shadeedge and all abutment macros: \zzcastpolyd
+% used by \drawcircle: \zzdrawcirclea
+% multiply defined control symbols: \zzvertexlist\zzshadow\zzglobalshadow
+% \zztesta\zztestb\zzvertexitem\zzprocpoly\zzprocrorect\zznext
+% \zzstartshadow\zzendshadow\zzlocalshadow
+
+%\diagram creates a box, initializes \zztotlwidth, \zztotrwidth, and
+%\zzvertexlist, sets \zzisedge to 0, executes #1, which must be a diagram
+%program, and then issues the resulting box, surrounded by kerns so that
+%there are no horizontal overhangs.
+
+\def\diagram#1{{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt
+\zztotlwidth=0pt\zztotrwidth=0pt\def\zzvertexlist{\end}\zzisedge=0\relax
+#1\relax\kern\zztotrwidth\global\zzglobaltotlwidth=\zztotlwidth $}
+\kern-\zzglobaltotlwidth\box\zzdiagbox}}
+
+%\zzsetupbox sets \zzdiagbox to the expression #1 modified by the program #2.
+%It also sets \zzglobalxcenter and \zzglobalycenter to the coordinates of
+%the center relative to the reference point, \zzglobaltotlwidth to the
+%negative of the left overhang width of the expression, and \zzglobalshadow
+%to the shadow established by the program, relative to the reference point.
+%Before executing #2, it initializes \texpr, \bexpr, \lexpr, \rexpr,
+%\xcenter, and \ycenter appropriately, and sets \zziscircle to 0.
+
+\def\zzsetupbox#1#2{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt
+\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$}
+\texpr=\ht\zzdiagbox\bexpr=-\dp\zzdiagbox\rexpr=\wd\zzdiagbox\lexpr=0pt
+\xcenter=\rexpr\divide\xcenter by 2\ycenter=\centerheight
+\zztotlwidth=0pt\zztotrwidth=\rexpr\def\zzshadow{\zznoshadow0pt,0pt:;}
+\zziscircle=0
+\box\zzdiagbox\kern-\rexpr
+#2\relax
+\global\zzglobalxcenter=\xcenter\global\zzglobalycenter=\ycenter
+\global\zzglobaltotlwidth=\zztotlwidth\kern\zztotrwidth
+\global\let\zzglobalshadow=\zzshadow
+$}}
+
+%\zznoshadow is a dummy shadowing routine that gives an error when executed.
+
+\def\zznoshadow#1,#2:;{\errmessage{ATTEMPT TO OUTLINE OR ABUT AN EXPRESSION
+WITH NO SHADOW}}
+
+%\leftghost (\rightghost) sets \xcenter to \lexpr plus (\rexpr minus)
+%half of the width of its argument.
+
+\def\leftghost#1{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$}
+\xcenter=\wd\zzdiagbox\divide\xcenter by 2\advance\xcenter by \lexpr}
+
+\def\rightghost#1{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$}
+\xcenter=\wd\zzdiagbox\divide\xcenter by -2\advance\xcenter by \rexpr}
+
+%\zzissue should be executed after \zzsetupbox. It issues the contents of
+%\zzdiagbox with its center placed at \zzdmA, \zzdmB (which are modified),
+%and adjusts \zztotlwidth and \zztotrwidth appropriately.
+
+\def\zzissue{\advance\zzdmA by -\zzglobalxcenter
+\advance\zzdmB by -\zzglobalycenter
+\zzdmC=\zzdmA\advance\zzdmC by \wd\zzdiagbox
+\zzdmD=\zzdmA\advance\zzdmD by \zzglobaltotlwidth
+\zzrecordwidth\zzdmD\zzdmC
+\kern\zzdmA\raise\zzdmB\box\zzdiagbox\kern-\zzdmC}
+
+%\zzrecordwidth adjusts \zztotlwidth to be the minimum of its previous value
+%and #1, and adjusts \zztotrwidth to be the maximum of its previous value
+%and #2.
+
+\def\zzrecordwidth#1#2{\relax\ifdim#1<\zztotlwidth\relax\zztotlwidth=#1\fi
+\ifdim\zztotrwidth<#2\relax\zztotrwidth=#2\fi}
+
+%\zzrecordheight adjusts \zztotheight to be the maximum of its previous value
+%and #1, and adjusts \zztotdepth to be the minimum of its previous value
+%and #2.
+
+\def\zzrecordheight#1#2{\relax\ifdim\zztotheight<#1\relax\zztotheight=#1\fi
+\ifdim#2<\zztotdepth\relax\zztotdepth=#2\fi}
+
+%\placed executes \zzsetupbox{#3}{#4} and issues the contents of the resulting
+%\zzdiagbox with its center placed at #1, #2 (which must be dimensions).
+%\place is similar except that #1, #2 must be integer multiples of
+%\diagramunit.
+
+\def\placed#1#2#3#4{\zzsetupbox{#3}{#4}\zzdmA=#1\zzdmB=#2\zzissue}
+
+\def\place#1,#2:#3#4{\zzsetupbox{#3}{#4}\zzmultdiagramunit\zzdmA{#1}
+\zzmultdiagramunit\zzdmB{#2}\zzissue}
+
+%\zzmultdiagramunit sets #1 to #2 times \diagramunit.
+
+\def\zzmultdiagramunit#1#2{#1=\diagramunit\multiply#1 by #2\relax}
+
+%\vertex#1,#2:#3#4 executes \zzsetupbox{#3}{#4}, issues the contents of the
+%resulting \zzdiagbox with its center placed at #1, #2 times \diagramunit,
+%adjusts \zztotlwidth and \zztotrwidth appropriately, and adds \zzglobalshadow
+%to the beginning of \zzvertexlist (unless \zzglobalshadow is a call of
+%\zznoshadow) after readjusting the shadow to be relative
+%to the coordinates of the enclosing box.
+
+\def\vertex#1,#2:#3#4{\place{#1},{#2}:{#3}{#4}\zzcnA=#1\zzcnB=#2\relax
+\expandafter\zzconsvertexlist\zzglobalshadow}
+
+\def\zzconsvertexlist#1#2,#3:#4;{\def\zztesta{#1}\def\zztestb{\zznoshadow}
+\ifx\zztesta\zztestb\else
+\advance\zzdmA by #2\advance\zzdmB by #3\relax
+\edef\zzvertexitem{\the\zzcnA,\the\zzcnB:\noexpand #1\the\zzdmA,\the\zzdmB:#4;}
+\expandafter\zzconsvertexlista\zzvertexlist\fi}
+
+\def\zzconsvertexlista{\expandafter\zzconsvertexlistb\zzvertexitem}
+
+\def\zzconsvertexlistb#1\end{\def\zzvertexlist{#1\end}}
+
+%\rect, \hexagon, \octagon, and \diamond (and, roughly speaking, \rorect)
+%are polygon descriptors. A polygon descriptor defines \zzshadow to have
+% the form \somecontrolsymbol #1,#2:#3; such that executing
+%\zzshadow causes a call \zzprocpoly{#1}{#2}{<edgelist>}, where <edgelist>
+%depends only upon the parameter #3. Here #1, #2 are the
+%coordinates of a vertex of a convex polygon, and <edgelist> is a list of
+%triples describing the edges of the polygon in clockwise order. If an
+%edge is x = xs.t + x0, y = ys.t + y0 for 0 < t < tend (with the start at
+%t = 0 and the end at t = tend when the edge is traversed in clockwise
+%order) the the trip describing the edge is {xs}{ys}{tend}, where xs and
+%ys are numbers (the brackets may be omitted for single-digit numbers)
+%and tend is a dimension. xs and ys must have a least common divisor of one.
+
+\def\rect{\zzdmC=\rexpr\advance\zzdmC by -\lexpr
+\zzdmD=\texpr\advance\zzdmD by -\bexpr
+\zzisnegside{\zzdmC}{RECT}\zzisnegside{\zzdmD}{RECT}
+\edef\zzshadow{\noexpand\zzprocrect
+\the\lexpr,\the\texpr:\the\zzdmC,\the\zzdmD;}}
+
+\def\zzprocrect#1,#2:#3,#4;{\zzprocpoly
+{#1}{#2}{10{#3}0{-1}{#4}{-1}0{#3}01{#4}}}
+
+\def\zzisnegside#1#2{\relax\ifdim#1<0pt\errmessage
+{#2 WITH NEGATIVE SIDE}\fi}
+
+\def\hexagon{\zzdmC=\rexpr\advance\zzdmC by -\lexpr
+\zzdmD=\texpr\advance\zzdmD by -\bexpr\divide\zzdmD by 4
+\zzisnegside{\zzdmC}{HEXAGON}\zzisnegside{\zzdmD}{HEXAGON}
+\edef\zzshadow{\noexpand\zzprochexagon
+\the\lexpr,\the\texpr:\the\zzdmC,\the\zzdmD;}}
+
+\def\zzprochexagon#1,#2:#3,#4;{\zzprocpoly{#1}{#2}
+{10{#3}1{-2}{#4}{-1}{-2}{#4}{-1}0{#3}{-1}2{#4}12{#4}}}
+
+\def\octagon#1{\zzdmC=#1\zzdmD=\zzdmC\multiply\zzdmD by -2\zzdmE=\zzdmD
+\advance\zzdmD by \rexpr\advance\zzdmD by -\lexpr
+\advance\zzdmE by \texpr\advance\zzdmE by -\bexpr
+\zzdmF=\lexpr\advance\zzdmF by \zzdmC
+\zzisnegside{\zzdmC}{OCTAGON}\zzisnegside{\zzdmD}{OCTAGON}
+\zzisnegside{\zzdmE}{OCTAGON}
+\edef\zzshadow{\noexpand\zzprococtagon
+\the\zzdmF,\the\texpr:\the\zzdmC,\the\zzdmD,\the\zzdmE;}}
+
+\def\zzprococtagon#1,#2:#3,#4,#5;{\zzprocpoly{#1}{#2}
+{10{#4}1{-1}{#3}0{-1}{#5}{-1}{-1}{#3}{-1}0{#4}{-1}1{#3}01{#5}11{#3}}}
+
+\def\diamond{\zzdmC=\texpr\advance\zzdmC by -\bexpr
+\advance\zzdmC by \rexpr\advance\zzdmC by -\lexpr\divide\zzdmC by 2
+\zzdmD=\lexpr\advance\zzdmD by \rexpr\divide\zzdmD by 2
+\zzdmE=\texpr\advance\zzdmE by \bexpr\divide\zzdmE by 2\advance\zzdmE by \zzdmC
+\zzisnegside{\zzdmC}{DIAMOND}
+\edef\zzshadow{\noexpand\zzprocdiamond
+\the\zzdmD,\the\zzdmE:\the\zzdmC;}}
+
+\def\zzprocdiamond#1,#2:#3;{\zzprocpoly{#1}{#2}
+{1{-1}{#3}{-1}{-1}{#3}{-1}1{#3}11{#3}}}
+
+\def\rorect#1#2#3{\zzcheckposdimen{#1}{FIRST}{RORECT}
+\zzcheckbool{#2}{SECOND}{RORECT}\zzcheckbool{#3}{THIRD}{RORECT}
+\zzdmD=\rexpr\advance\zzdmD by -\lexpr\zzdmE=\texpr\advance\zzdmE by -\bexpr
+\zzdmC=#1\relax
+\ifnum#2=1\relax\ifdim\zzdmD>\zzdmC\relax\zzdmC=\zzdmD\fi\fi
+\ifnum#3=1\relax\ifdim\zzdmE>\zzdmC\relax\zzdmC=\zzdmE\fi\fi
+\expandafter\zzsearchdiameterlist\diameterlist\end\zzdmC=\zzdmF\relax
+\ifdim\zzdmC>\zzdmD\relax\zzdmD=\zzdmC\fi
+\ifdim\zzdmC>\zzdmE\relax\zzdmE=\zzdmC\fi
+\zzdmF=\lexpr\advance\zzdmF by \rexpr\divide\zzdmF by 2
+\zzdmG=\bexpr\advance\zzdmG by \texpr\divide\zzdmG by 2
+\edef\zzshadow{\noexpand\zzprocrorect
+\the\zzdmF,\the\zzdmG:\the\zzdmC,\the\zzdmD,\the\zzdmE;}}
+
+\def\zzsearchdiameterlist#1{\def\zztesta{#1}\def\zztestb{\end}
+\ifx\zztesta\zztestb\let\zznext=\zzsearchdiameterlista
+\else\let\zznext=\zzsearchdiameterlistb\fi\zznext #1}
+
+\def\zzsearchdiameterlista#1\end{}
+
+\def\zzsearchdiameterlistb#1,{\zzdmF=#1\relax
+\ifdim\zzdmF<\zzdmC\relax\let\zznext=\zzsearchdiameterlist
+\else\let\zznext=\zzsearchdiameterlista\fi\zznext}
+
+%\outline uses \zzoutlinepoly and \zzoutlinerorect to issue an outline of
+%the shadow.
+
+\def\outline{\def\zzprocpoly{\zzoutlinepoly}
+\def\zzprocrorect{\zzoutlinerorect}\zzshadow}
+
+%\zzmakepicture encapsulates all usage of the LATEX picture facility.
+
+\def\zzmakepicture#1{{\setlength{\unitlength}{1sp}\begin{picture}(0,0)
+#1\relax
+\global\zzglobaltotlwidth=\zztotlwidth\global\zzglobaltotrwidth=\zztotrwidth
+\global\zzglobaltotheight=\zztotheight\global\zzglobaltotdepth=\zztotdepth
+\end{picture}\vrule height\zzglobaltotheight depth-\zzglobaltotdepth width0pt}
+\zztotlwidth=\zzglobaltotlwidth\zztotrwidth=\zzglobaltotrwidth}
+
+\def\zzoutlinepoly#1#2#3{\zzmakepicture{\zzdmA=#1\zzdmB=#2\relax
+\zztotheight=\zzdmB\zztotdepth=\zzdmB\zzoutlinepolya #3\end}}
+
+\def\zzoutlinepolya#1{\def\zztesta{#1}\def\zztestb{\end}
+\ifx\zztesta\zztestb\let\zznext=\zzoutlinepolyb
+\else\let\zznext=\zzoutlinepolyc\fi\zznext {#1}}
+
+\def\zzoutlinepolyb#1{}
+
+\def\zzoutlinepolyc#1#2#3{\zzrecordwidth\zzdmA\zzdmA\zzrecordheight\zzdmB\zzdmB
+\zzdmE=#3\multiply\zzdmE by #1\zzdmF=#3\multiply\zzdmF by #2\relax
+\zzcnA=\zzdmA\zzcnB=\zzdmB\relax
+\ifnum #1=0\relax\zzcnC=\zzdmF\else\zzcnC=\zzdmE\fi
+\ifnum\zzcnC<0\relax\zzcnC=-\zzcnC\fi
+\put(\zzcnA,\zzcnB){\line(#1,#2){\zzcnC}}
+\advance\zzdmA by \zzdmE\advance\zzdmB by \zzdmF
+\zzoutlinepolya}
+
+\def\zzoutlinerorect#1,#2:#3,#4,#5;{\zzmakepicture{
+\zzdmA=#1\zzdmB=#2\zzdmC=#3\zzdmD=#4\zzdmE=#5
+\zzcnA=\zzdmA\zzcnB=\zzdmB\zzcnC=\zzdmC\zzcnD=\zzdmD\zzcnE=\zzdmE
+\ifnum\zzcnD=\zzcnC\relax\put(\zzcnA,\zzcnB){\oval(\zzcnD,\zzcnE)}
+\else\ifnum\zzcnE=\zzcnC\relax\put(\zzcnA,\zzcnB){\oval(\zzcnD,\zzcnE)}
+\else\advance\zzcnE by -\zzcnC
+\zzcnF=\zzcnE\divide\zzcnF by 2\advance\zzcnF by \zzcnB
+\put(\zzcnA,\zzcnF){\oval(\zzcnD,\zzcnC)[t]}
+\advance\zzcnF by -\zzcnE
+\put(\zzcnA,\zzcnF){\oval(\zzcnD,\zzcnC)[b]}
+\zzcnC=\zzcnD\divide\zzcnC by 2\advance\zzcnA by \zzcnC
+\put(\zzcnA,\zzcnF){\line(0,1){\zzcnE}}
+\advance\zzcnA by -\zzcnD
+\put(\zzcnA,\zzcnF){\line(0,1){\zzcnE}}\fi\fi
+\zztotheight=\zzdmE\divide\zztotheight by 2\advance\zztotheight by \zzdmB
+\zztotdepth=\zztotheight\advance\zztotdepth by -\zzdmE
+\zzdmC=\zzdmD\divide\zzdmC by -2\advance\zzdmC by \zzdmA
+\advance\zzdmD by \zzdmC\zzrecordwidth\zzdmC\zzdmD}}
+
+%\border, \borderto, and \symmetrize adjust the current rectangle.
+
+\def\border#1#2{\advance\texpr by #2\advance\bexpr by -#2
+\advance\lexpr by -#1\advance\rexpr by #1}
+
+\def\borderto#1#2{\zzdmA=\rexpr\advance\zzdmA by -\lexpr\relax
+\ifdim#1>\zzdmA\relax\advance\zzdmA by -#1\divide\zzdmA by 2
+\advance\rexpr by -\zzdmA\advance\lexpr by \zzdmA\fi
+\zzdmA=\texpr\advance\zzdmA by -\bexpr\relax
+\ifdim#2>\zzdmA\relax\advance\zzdmA by -#2\divide\zzdmA by 2
+\advance\texpr by -\zzdmA\advance\bexpr by \zzdmA\fi}
+
+\def\symmetrize{\zzdmA=\texpr\advance\zzdmA by -\ycenter
+\zzdmB=\ycenter\advance\zzdmB by -\bexpr\relax
+\ifdim\zzdmA<\zzdmB\relax\zzdmA=\zzdmB\fi
+\texpr=\ycenter\advance\texpr by \zzdmA
+\bexpr=\ycenter\advance\bexpr by -\zzdmA}
+
+%\setedge#1,#2,#3,#4: accepts four numbers (giving dimensions as multiples of
+%\diagramunit). It sets \xstart, \ystart, \xend, \yend to #1, #2, #3,
+%#4, each multiplied by \diagramunit, and \xslope, \yslope to numbers
+% giving the slope of the line from \xstart, \ystart to \xend, \yend,
+%reduced to have a least common divisor. It uses \zzsearchvertexlist to set
+%\zzstartshadow (\zzendshadow) to the \zzshadow stored on \zzvertexlist with
+%coordinates #1, #2 (#3, #4). It sets \zzisedge to 1.
+
+\def\setedge#1,#2,#3,#4:{\zzcnA=#1\zzcnB=#2
+\zzmultdiagramunit\xstart\zzcnA\zzmultdiagramunit\ystart\zzcnB
+\expandafter\zzsearchvertexlist\zzvertexlist
+\let\zzstartshadow=\zzshadow
+\zzcnA=#3\zzcnB=#4
+\zzmultdiagramunit\xend\zzcnA\zzmultdiagramunit\yend\zzcnB
+\expandafter\zzsearchvertexlist\zzvertexlist
+\let\zzendshadow=\zzshadow
+\xslope=#3\advance\xslope by -#1\relax
+\yslope=#4\advance\yslope by -#2\relax
+\zzreduceterms\xslope\yslope{START AND END OF EDGE ARE BOTH THE SAME}
+\xslope=\zzcnC\yslope=\zzcnD\zzisedge=1}
+
+%\zzreduceterms sets \zzcnC and \zzcnD to the results of dividing the numbers
+% #1 and #2 by their greatest common divisor. The error message #3 is given
+%if #1 and #2 are both zero.
+
+\def\zzreduceterms#1#2#3{{
+\ifnum#1<0\relax\zzcnA=-#1\else\zzcnA=#1\fi
+\ifnum#2<0\relax\zzcnB=-#2\else\zzcnB=#2\fi
+\loop\ifnum\zzcnB>0\relax
+\zzcnC=\zzcnA\divide\zzcnC by \zzcnB\multiply\zzcnC by -\zzcnB
+\advance\zzcnC by \zzcnA\zzcnA=\zzcnB\zzcnB=\zzcnC
+\repeat\relax
+\ifnum\zzcnA=0\errmessage{#3}\fi
+\global\zzglobalcnA=\zzcnA}
+\zzcnC=#1\divide\zzcnC by \zzglobalcnA\zzcnD=#2\divide\zzcnD by \zzglobalcnA}
+
+%\zzsearchvertexlist\zzvertexlist searches \zzvertexlist for an entry of the
+%form #1,#2:#3; for which #1 = \zzcnA and #2 = \zzcnB. If such an entry is
+%found, \zzshadow is defined to be #3;. Otherwise, \zzshadow is defined to be
+%\zzdmE=\zzdmA\zzdmF=\zzdmB.
+
+\def\zzsearchvertexlist#1{\def\zztesta{#1}\def\zztestb{\end}
+\ifx\zztesta\zztestb\def\zzshadow{\zzdmE=\zzdmA\zzdmF=\zzdmB}
+\let\zznext=\zzsearchvertexlista
+\else\let\zznext=\zzsearchvertexlistb\fi\zznext #1}
+
+\def\zzsearchvertexlista#1\end{}
+
+\def\zzsearchvertexlistb#1,#2:#3;{\relax
+\ifnum\zzcnA=#1\relax\ifnum\zzcnB=#2\relax
+\def\zzshadow{#3;}\let\zznext=\zzsearchvertexlista
+\else\let\zznext=\zzsearchvertexlist\fi
+\else\let\zznext=\zzsearchvertexlist\fi\zznext}
+
+%\shadeedge shades the start and end of the current edge, changing \xstart,
+%\ystart, \xend, \yend.
+
+\def\shadeedge{\zzcheckedge{SHADE}
+\def\zzprocpoly{\zzcastpoly}\def\zzprocrorect{\zzprocrorecta}
+\zzdmA=\xstart\zzdmB=\ystart\zzcnA=\xslope\zzcnB=\yslope
+\zzstartshadow\xstart=\zzdmE\ystart=\zzdmF
+\zzdmA=\xend\zzdmB=\yend\zzcnA=-\xslope\zzcnB=-\yslope
+\zzendshadow\xend=\zzdmE\yend=\zzdmF}
+
+\def\zzcheckedge#1{\relax\ifnum\zzisedge=0\relax\errmessage
+{ATTEMPT TO #1 NONEXISTENT EDGE}\fi}
+
+%\zzprocrorecta is used as the definition of \zzprocrorect within \shadeedge
+%and \zzabut. It causes a rounded rectangle to be treated as the
+%circumscribed octagon for purposes of shadowing or abutment.
+
+\def\zzprocrorecta#1,#2:#3,#4,#5;{\zzdmC=#3
+\multiply\zzdmC by 53\divide\zzdmC by 181
+\zzdmD=\zzdmC\multiply\zzdmD by -2\zzdmE=\zzdmD
+\advance\zzdmD by #4\advance\zzdmE by #5
+\zzdmF=#4\divide\zzdmF by -2\advance\zzdmF by #1\advance\zzdmF by \zzdmC
+\zzdmG=#5\divide\zzdmG by 2\advance\zzdmG by #2
+\edef\zzlocalshadow{\noexpand\zzprococtagon
+\the\zzdmF,\the\zzdmG:\the\zzdmC,\the\zzdmD,\the\zzdmE;}
+\zzlocalshadow}
+
+%\zzcastpoly computes the outgoing intersection of a directed line,
+%x = xs.t+x0, y = ys.t+y0 with a convex polygon. It is called
+%by defining \zzprocpoly to be \zzcastpoly, setting \zzdmA, \zzdmB, \zzcnA,
+%\zzcnB to x0, y0, xs, ys, and executing \zzshadow, which must have been
+%defined by a polygon descriptor. The result is left in \zzdmE, \zzdmF.
+%If the directed line does not intersect the polygon, the result is the
+%point on the line that is closest to the polygon.
+
+\def\zzcastpoly#1#2#3{\zzdmC=#1\zzdmD=#2\zzcnC=0
+\zzcastpolya #3\end}
+
+\def\zzcastpolya#1{\def\zztesta{#1}\def\zztestb{\end}
+\ifx\zztesta\zztestb\let\zznext=\zzcastpolyg
+\else\let\zznext=\zzcastpolyc\fi\zznext {#1}}
+
+\def\zzcastpolyb#1\end{\zzcnC=\zzcnA\multiply\zzcnC by \zzcnA
+\zzcnD=\zzcnB\multiply\zzcnD by \zzcnB\advance\zzcnC by \zzcnD
+\zzdmE=\zzdmC\advance\zzdmE by -\zzdmA\multiply\zzdmE by \zzcnA
+\zzdmF=\zzdmD\advance\zzdmF by -\zzdmB\multiply\zzdmF by \zzcnB
+\advance\zzdmE by \zzdmF\divide\zzdmE by \zzcnC\zzdmF=\zzdmE
+\multiply\zzdmE by \zzcnA\advance\zzdmE by \zzdmA
+\multiply\zzdmF by \zzcnB\advance\zzdmF by \zzdmB}
+
+
+\def\zzcastpolyc#1#2#3{\zzcnD=\zzcnB\multiply\zzcnD by #1\relax
+\zzcnE=\zzcnA\multiply\zzcnE by #2\relax\advance\zzcnD by -\zzcnE\relax
+\ifnum\zzcnD>0\relax
+\ifnum\zzcnC=2\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\else
+\zzdmE=\zzdmA\advance\zzdmE by -\zzdmC\multiply\zzdmE by \zzcnB
+\zzdmF=\zzdmB\advance\zzdmF by -\zzdmD\multiply\zzdmF by \zzcnA
+\advance\zzdmE by -\zzdmF\divide\zzdmE by \zzcnD\relax
+\ifdim\zzdmE>#3\relax\zzcnC=3\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya
+\else\ifnum\zzcnC=3\zzcastpolyf{#1}{#2}\let\zznext=\zzcastpolye\else
+\ifdim\zzdmE<0pt\relax
+\ifnum\zzcnC=1\let\zznext=\zzcastpolyb\else
+\zzcnC=2\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\fi
+\else\zzcastpolyf{#1}{#2}\let\zznext=\zzcastpolye\fi\fi\fi\fi
+\else\ifnum\zzcnC=3\let\zznext=\zzcastpolyb
+\else\zzcnC=1\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\fi\fi
+\zznext}
+
+\def\zzcastpolyd#1#2#3{
+\zzdmE=#3\multiply\zzdmE by #1\advance\zzdmC by \zzdmE
+\zzdmE=#3\multiply\zzdmE by #2\advance\zzdmD by \zzdmE}
+
+\def\zzcastpolye#1\end{}
+
+\def\zzcastpolyf#1#2{\zzdmF=\zzdmE
+\multiply\zzdmE by #1\relax\advance\zzdmE by \zzdmC
+\multiply\zzdmF by #2\relax\advance\zzdmF by \zzdmD}
+
+\def\zzcastpolyg#1{\zzcastpolyb\end}
+
+%\shiftedge changes \xstart, \ystart, \xend, \yend so as to displace
+%the edge from \xstart, \ystart to \xend, \yend by a vector of length
+%#1 (a dimension) that is rotated 90 degrees counterclockwise from the edge.
+
+\def\shiftedge#1{\zzcheckedge{SHIFT}
+\zzdistance\xslope\yslope
+\zzdmA=#1\multiply\zzdmA by 100\divide\zzdmA by \zzglobalcnA\zzdmB=\zzdmA
+\multiply\zzdmA by -\yslope\multiply\zzdmB by \xslope
+\advance\xstart by \zzdmA \advance\xend by \zzdmA
+\advance\ystart by \zzdmB \advance\yend by \zzdmB}
+
+%\zzsqroot#1 accepts an integer and sets \zzglobalcnA to the integer part
+%of its square root. It works for numbers up to at least 1,000,000,000.
+
+\def\zzsqroot#1{{\zzcnA=#1
+%x is \zzcnA, y is \zzcnB, n is \zzcnC, z is \zzcnD
+\zzcnC=0\zzcnD=1
+\loop\zzcnE=\zzcnA\divide\zzcnE by \zzcnD\advance\zzcnE by 1
+\relax\ifnum\zzcnD<\zzcnE\relax
+\advance \zzcnC by 1\multiply\zzcnD by 2
+\repeat
+\zzcnB=0
+\loop\ifnum\zzcnC>0\relax
+\advance\zzcnC by -1\divide\zzcnD by 2
+\zzcnE=\zzcnB\advance\zzcnE by \zzcnD\multiply\zzcnE by \zzcnE\relax
+\ifnum\zzcnA<\zzcnE\relax\else\advance\zzcnB by \zzcnD\fi
+\repeat
+\global\zzglobalcnA=\zzcnB}}
+
+%\zzdistance#1#2 accepts two integers and sets \zzglobalcnA to 100 times
+%the square root of the sum of their squares.
+
+\def\zzdistance#1#2{{\zzcnA=#1\multiply\zzcnA by \zzcnA
+\zzcnB=#2\multiply\zzcnB by \zzcnB
+\advance\zzcnA by \zzcnB\multiply\zzcnA by 10000
+\zzsqroot\zzcnA}}
+
+%\drawdashedge, \drawdotedge, or \drawsolidedge draws a dashed, dotted, or
+%solid line along the current edge.
+
+\def\drawdashedge#1#2#3#4{\zzcnA=1\zzdmA=#1\zzdmB=#2
+\zzcheckposdimen\zzdmA{FIRST}{DRAWDASHEDGE}
+\zzcheckposdimen\zzdmB{SECOND}{DRAWDASHEDGE}
+\zzchecknonnegnum{#3}{THIRD}{DRAWDASHEDGE}
+\zzchecknonnegnum{#4}{FOURTH}{DRAWDASHEDGE}
+\zzcnI=#3\relax\advance\zzcnI by #4\relax
+\ifnum\zzcnI>0\else\errmessage
+{SUM OF THIRD AND FOURTH PARAMETERS OF DRAWDASHEDGE MUST BE POSITIVE}\fi
+\advance\zzdmB by \zzdmA
+\zzdrawedge{\advance\zzcnC by -\zzcnD
+\zzcnG=\zzcnC\divide\zzcnG by \zzcnE\relax
+\ifnum\zzcnG>0\relax
+\zzcnH=\zzcnG\multiply\zzcnH by \zzcnE\advance\zzcnC by -\zzcnH
+\zzcnH=\zzcnI\multiply\zzcnH by \zzcnG
+\advance\zzcnH by #3\divide\zzcnC by \zzcnH
+\zzcnH=#3\multiply\zzcnH by \zzcnC\advance\zzcnD by \zzcnH
+\multiply\zzcnC by \zzcnI\advance\zzcnE by \zzcnC
+\else\advance\zzcnD by \zzcnC\fi}
+{\line(\xslope,\yslope){\zzcnD}}}
+
+\def\zzcheckposdimen#1#2#3{\relax\ifdim#1>0pt\else\errmessage{
+#2 PARAMETER OF #3 MUST BE POSITIVE}\fi}
+
+\def\zzchecknonnegnum#1#2#3{\relax\ifnum#1<0\relax\errmessage{
+#2 PARAMETER OF #3 MUST BE NONNEGATIVE}\fi}
+
+\def\drawdotedge#1#2{\zzcnA=0\zzdmA=0pt\zzdmB=#1
+\zzcheckposdimen\zzdmB{}{DRAWDOTEDGE}\zzcheckbool{#2}{SECOND}{DRAWDOTEDGE}
+\zzdrawedge{\zzcnG=\zzcnC\divide\zzcnG by \zzcnE\relax
+\ifnum\zzcnG<1\relax\zzcnG=1\fi\zzcnE=\zzcnC\divide\zzcnE by \zzcnG\relax
+\ifnum#2=0\relax\advance\zzcnG by -1\fi}
+{\kern-1.39pt\raise-.76pt\hbox{.}}}
+
+\def\drawsolidedge{\zzcnA=1\zzdmA=0pt\zzdmB=0pt
+\zzdrawedge{\zzcnG=0\zzcnD=\zzcnC}
+{\line(\xslope,\yslope){\zzcnD}}}
+
+\def\zzdrawedge#1#2{\zzcheckedge{DRAW}\relax
+\ifnum\zzcnA=1\relax\zzcheckslope\xslope\yslope 6{SOLID OR DASHED EDGE}\fi
+\zzcnA=\xstart\zzcnB=\ystart\zzcnD=\zzdmA\zzcnE=\zzdmB\relax
+\ifnum\xslope=0\relax\zzcnC=\yend\advance\zzcnC by -\zzcnB\zzcnF=\yslope
+\else\zzcnC=\xend\advance\zzcnC by -\zzcnA\zzcnF=\xslope
+\zzdistance\xslope\yslope\relax
+\ifnum\xslope<0\relax\global\zzglobalcnA=-\zzglobalcnA\fi
+\multiply\zzcnD by 100\divide\zzcnD by \zzglobalcnA\multiply\zzcnD by \xslope
+\multiply\zzcnE by 100\divide\zzcnE by \zzglobalcnA\multiply\zzcnE by \xslope
+\fi
+\ifnum\zzcnF<0\relax\zzcnC=-\zzcnC\fi
+\ifnum\zzcnC>0\relax #1\relax
+\ifnum\zzcnF<0\relax\zzcnE=-\zzcnE\fi\zzcnF=\zzcnE\relax
+\ifnum\xslope=0\relax\zzcnE=0
+\else\multiply\zzcnF by \yslope\divide\zzcnF by \xslope\fi
+\zzmakepicture{\loop\put(\zzcnA,\zzcnB){#2}
+\ifnum\zzcnG>0\relax\advance\zzcnG by -1
+\advance\zzcnA by \zzcnE\advance\zzcnB by \zzcnF\repeat
+\zzrecordwidth\xstart\xstart\zzrecordwidth\xend\xend
+\zztotheight=\ystart\zztotdepth=\ystart\zzrecordheight\yend\yend}\fi}
+
+%\drawedgehead draws an arrowhead along the current edge.
+
+\def\drawedgehead#1#2#3{\zzcheckbool{#2}{SECOND}{DRAWEDGEHEAD}
+\zzcheckbool{#3}{THIRD}{DRAWEDGEHEAD}\zzcnB=#3
+\relax\ifnum#2=1\relax\zzcnA=#1\relax
+\zzdrawedgeheada\xstart\ystart\xend\yend\xslope\yslope
+\else\zzcnA=100\advance\zzcnA by -#1\relax
+\zzdrawedgeheada\xend\yend\xstart\ystart{-\xslope}{-\yslope}\fi}
+
+%\zzcheckbool gives an error message unless its first argument is 1 or 0.
+
+\def\zzcheckbool#1#2#3{
+\ifnum#1<0\errmessage{#2 PARAMETER OF #3 MUST BE 1 OR 0}\fi
+\ifnum#1>1\errmessage{#2 PARAMETER OF #3 MUST BE 1 OR 0}\fi}
+
+\def\zzdrawedgeheada#1#2#3#4#5#6{\zzcheckedge{DRAW ARROWHEAD FOR}
+\zzcheckslope{#5}{#6}4{ARROWHEAD}
+\zzdmA=#3\advance\zzdmA by -#1
+\divide\zzdmA by 10\multiply\zzdmA by \zzcnA\divide\zzdmA by 10
+\zzdmB=#4\advance\zzdmB by -#2
+\divide\zzdmB by 10\multiply\zzdmB by \zzcnA\divide\zzdmB by 10
+\relax\ifnum\zzcnB=1\relax
+\zzdistance{#5}{#6}\zzdmC=\edgeheaddisp
+\multiply\zzdmC by 100\divide\zzdmC by \zzglobalcnA\zzdmD=\zzdmC
+\multiply\zzdmC by #5\multiply\zzdmD by #6
+\advance\zzdmA by \zzdmC\advance\zzdmB by \zzdmD\fi
+\advance\zzdmA by #1\zzcnA=\zzdmA\advance\zzdmB by #2\zzcnB=\zzdmB
+\zzmakepicture{\put(\zzcnA,\zzcnB){\vector(#5,#6){0}}
+\zzrecordwidth\zzdmA\zzdmA\zztotheight=\zzdmB\zztotdepth=\zzdmB}}
+
+%\zzcheckslope gives an errormessage if the absolute value of #1 or #2
+%is greater than #3.
+
+\def\zzcheckslope#1#2#3#4{\relax
+\ifnum#1>#3\zzcheckslopea{#1}{#2}{#4}\fi
+\ifnum#1<-#3\zzcheckslopea{#1}{#2}{#4}\fi
+\ifnum#2>#3\zzcheckslopea{#1}{#2}{#4}\fi
+\ifnum#2<-#3\zzcheckslopea{#1}{#2}{#4}\fi}
+
+\def\zzcheckslopea#1#2#3{\errmessage{\the#1,\the#2 IS ILLEGAL SLOPE FOR #3}}
+
+%The following macros each call \zzsetupbox{#2}{#3} and then issue the
+%resulting expression so that its shadow touches the edge x = \xslope.t
+%+\xstart, y = \yslope.t+\ystart. \abutX places the expression to the X
+%of the edge. For \abutleft and \abutright, #1 gives the y-coordinate
+%of the expression as an integer multiple of \diagramunit. For \abutbelow
+%and \abutabove, #1 gives the x-coordinate similarly. The macros \abutXd
+%are similar, except that #1 should be a dimension.
+
+\def\abutleft#1:#2#3{\zzabut{#1}{#2}{#3}{-\yslope}{\zzslidehoriz}{1}}
+\def\abutright#1:#2#3{\zzabut{#1}{#2}{#3}{\yslope}{\zzslidehoriz}{1}}
+\def\abutbelow#1:#2#3{\zzabut{#1}{#2}{#3}{\xslope}{\zzslidevert}{1}}
+\def\abutabove#1:#2#3{\zzabut{#1}{#2}{#3}{-\xslope}{\zzslidevert}{1}}
+
+\def\abutleftd#1#2#3{\zzabut{#1}{#2}{#3}{-\yslope}{\zzslidehoriz}{0}}
+\def\abutrightd#1#2#3{\zzabut{#1}{#2}{#3}{\yslope}{\zzslidehoriz}{0}}
+\def\abutbelowd#1#2#3{\zzabut{#1}{#2}{#3}{\xslope}{\zzslidevert}{0}}
+\def\abutaboved#1#2#3{\zzabut{#1}{#2}{#3}{-\xslope}{\zzslidevert}{0}}
+
+\def\zzabut#1#2#3#4#5#6{\zzcheckedge{ABUT TO}
+\zzsetupbox{#2}{#3}\zzcnA=\xslope\zzcnB=\yslope
+\relax\ifnum#4<0\relax\zzcnA=-\zzcnA\zzcnB=-\zzcnB\fi
+\def\zzprocpoly{\zzclosestpoly}\def\zzprocrorect{\zzprocrorecta}
+\zzglobalshadow
+\advance\zzdmC by -\zzglobalxcenter\advance\zzdmD by -\zzglobalycenter
+\relax\ifnum#6=1\relax\zzmultdiagramunit\zzdmA{#1}\else\zzdmA=#1\fi
+\zzdmB=\zzdmA#5\relax\zzissue}
+
+\def\zzslidehoriz{\relax\ifnum\yslope=0\errmessage
+{ABUTLEFT OR ABUTRIGHT ATTEMPTED FOR HORIZONTAL EDGE}\fi
+\advance\zzdmA by \zzdmD\advance\zzdmA by -\ystart
+\multiply\zzdmA by \xslope\divide\zzdmA by \yslope
+\advance\zzdmA by \xstart\advance\zzdmA by -\zzdmC}
+
+\def\zzslidevert{\relax\ifnum\xslope=0\errmessage
+{ABUTBELOW OR ABUTABOVE ATTEMPTED FOR VERTICAL EDGE}\fi
+\advance\zzdmB by \zzdmC\advance\zzdmB by -\xstart
+\multiply\zzdmB by \yslope\divide\zzdmB by \xslope
+\advance\zzdmB by \ystart\advance\zzdmB by -\zzdmD}
+
+%\zzclosestpoly finds the vertex of a convex polygon that is closest to a
+%directed line, x = xs.t+x0, y = ys.t+y0, assuming that the directed line
+%is to the left (right) of the polygon if ys is positive (negative)
+%and above (below) the polygon if xs is positive (negative).
+%It is called by defining \zzprocpoly to be \zzclosestpoly, setting \zzcnA,
+%\zzcnB to xs, ys, and executing \zzglobalshadow, which must have been
+%defined by a polygon descriptor. The output is left in \zzdmC, \zzdmD.
+
+\def\zzclosestpoly#1#2#3{\zzdmC=#1\zzdmD=#2\zzcnC=0\zzclosestpolya #3\end}
+
+\def\zzclosestpolya#1{\def\zztesta{#1}\def\zztestb{\end}
+\ifx\zztesta\zztestb\let\zznext=\zzclosestpolyb
+\else\let\zznext=\zzclosestpolyc\fi\zznext {#1}}
+
+\def\zzclosestpolyb#1{}
+
+\def\zzclosestpolyc#1#2#3{\zzcnD=\zzcnB\multiply\zzcnD by #1\relax
+\zzcnE=\zzcnA\multiply\zzcnE by #2\relax\advance\zzcnD by -\zzcnE\relax
+\ifnum\zzcnD>0\relax
+\ifnum\zzcnC=1\let\zznext=\zzclosestpolyd
+\else\zzcnC=0\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzclosestpolya\fi
+\else\zzcnC=1\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzclosestpolya\fi
+\zznext}
+
+\def\zzclosestpolyd#1\end{}
+
+%\setcircle initializes \dcircle, \xcircle, and \ycircle to its first
+%three parameters, and sets \zziscircle to 1.
+
+\def\setcircle#1#2#3{\dcircle=#1\xcircle=#2\ycircle=#3\zziscircle=1}
+
+%\shiftcircle#1#2 displaces \xcircle, \ycircle by #1, #2.
+
+\def\shiftcircle#1#2{\zzcheckcircle{SHIFT}
+\advance\xcircle by #1\advance\ycircle by #2}
+
+\def\zzcheckcircle#1{\relax\ifnum\zziscircle=0\errmessage
+{ATTEMPT TO #1 NONEXISTENT CIRCLE}\fi}
+
+%\drawcircle draws quadrants of the current circle.
+
+\def\drawcircle#1#2#3#4{\zzcheckcircle{DRAW}\zzdmA=\dcircle\divide\zzdmA by 2
+\zzmakepicture{\zzcnA=\dcircle\zzcnB=\xcircle\zzcnC=\ycircle
+\zztotheight=\ycircle\zztotdepth=\ycircle
+\zzrecordwidth\xcircle\xcircle\relax
+\zzdrawcirclea{#1}{tr}{\zzdmA}{\zzdmA}\zzdrawcirclea{#2}{br}{\zzdmA}{-\zzdmA}
+\zzdrawcirclea{#3}{bl}{-\zzdmA}{-\zzdmA}
+\zzdrawcirclea{#4}{tl}{-\zzdmA}{\zzdmA}}}
+
+\def\zzdrawcirclea#1#2#3#4{\zzcheckbool{#1}{}{DRAWCIRCLE}\ifnum#1=1\relax
+\put(\zzcnB,\zzcnC){\oval(\zzcnA,\zzcnA)[#2]}
+\zzdmB=\xcircle\advance\zzdmB by #3\zzrecordwidth\zzdmB\zzdmB
+\zzdmB=\ycircle\advance\zzdmB by #4\zzrecordheight\zzdmB\zzdmB\fi}
+
+%\drawcirclehead issues an arrowhead placed on the current circle.
+
+\def\drawcirclehead#1#2#3{\zzcheckcircle{DRAW ARROWHEAD FOR}
+\zzreduceterms{#1}{#2}{0,0 ARE ILLEGAL PARAMETERS FOR DRAWCIRCLEHEAD}
+\zzdistance{\zzcnC}{\zzcnD}\zzcheckbool{#3}{THIRD}{DRAWCIRCLEHEAD}
+\ifnum#3=1\relax\zzcnA=\zzcnD\zzcnB=-\zzcnC\else\zzcnA=-\zzcnD\zzcnB=\zzcnC\fi
+\zzdmA=\dcircle\multiply\zzdmA by 50\divide\zzdmA by \zzglobalcnA
+\zzdmB=\circleheaddisp\multiply\zzdmB by 100\divide\zzdmB by \zzglobalcnA
+\zzdmE=\zzdmA\multiply\zzdmE by \zzcnC\zzdmC=\xcircle\advance\zzdmC by \zzdmE
+\zzdmE=\zzdmB\multiply\zzdmE by \zzcnA\advance\zzdmC by \zzdmE
+\zzdmE=\zzdmA\multiply\zzdmE by \zzcnD\zzdmD=\ycircle\advance\zzdmD by \zzdmE
+\zzdmE=\zzdmB\multiply\zzdmE by \zzcnB\advance\zzdmD by \zzdmE
+\zzcnC=\zzdmC\zzcnD=\zzdmD\zzcheckslope\zzcnA\zzcnB4{ARROWHEAD}
+\zzmakepicture{\put(\zzcnC,\zzcnD){\vector(\zzcnA,\zzcnB){0}}
+\zzrecordwidth\zzdmC\zzdmC\zztotheight=\zzdmD\zztotdepth=\zzdmD}}
+
+%The next four macros cause an expression to be abutted to the current
+%circle.
+
+\def\abutcircleleft#1#2#3{\zzabutcircle{#1}{#2}{#3}{}
+\zzslidehoriz{\relax\ifdim\zzdmA>\zzdmH\relax\zzdmH=\zzdmA\fi}}
+
+\def\abutcircleright#1#2#3{\zzabutcircle{#1}{#2}{#3}{\zzrotate\zzrotate}
+\zzslidehoriz{\relax\ifdim\zzdmA<\zzdmH\relax\zzdmH=\zzdmA\fi}}
+
+\def\abutcirclebelow#1#2#3{\zzabutcircle{#1}{#2}{#3}{\zzrotate}
+\zzslidevert{\relax\ifdim\zzdmB>\zzdmI\relax\zzdmI=\zzdmB\fi}}
+
+\def\abutcircleabove#1#2#3{\zzabutcircle
+{#1}{#2}{#3}{\zzrotate\zzrotate\zzrotate}
+\zzslidevert{\relax\ifdim\zzdmB<\zzdmI\relax\zzdmI=\zzdmB\fi}}
+
+\def\zzabutcircle#1#2#3#4#5#6{\zzcheckcircle{ABUT TO}
+\zzsetupbox{#2}{#3}\def\zzprocpoly{\zzclosestpoly}
+\def\zzprocrorect{\zzprocrorecta}
+\zzdmF=\dcircle\divide\zzdmF by 2
+\zzdmG=\dcircle\multiply\zzdmG by 100\divide\zzdmG by 283
+\xstart=-\zzdmF\ystart=0pt\xslope=0\yslope=-1
+\zzabutcirclea{#1}{#4}{#5}\zzdmH=\zzdmA\zzdmI=\zzdmB
+\xstart=-\zzdmG\ystart=\zzdmG\xslope=-1\yslope=-1
+\zzabutcirclea{#1}{#4}{#5}#6\relax
+\xstart=-\zzdmG\ystart=-\zzdmG\xslope=1\yslope=-1
+\zzabutcirclea{#1}{#4}{#5}#6\relax
+\zzdmA=\zzdmH\advance\zzdmA by \xcircle
+\zzdmB=\zzdmI\advance\zzdmB by \ycircle
+\zzissue}
+
+\def\zzabutcirclea#1#2#3{#2\relax
+\zzcnA=\xslope\zzcnB=\yslope
+\zzglobalshadow
+\advance\zzdmC by -\zzglobalxcenter\advance\zzdmD by -\zzglobalycenter
+\zzdmA=#1\zzdmB=\zzdmA #3\relax}
+
+\def\zzrotate{\zzdmE=\xstart\xstart=-\ystart\ystart=\zzdmE
+\zzcnC=\xslope\xslope=-\yslope\yslope=\zzcnC}
+
+%MACROS FOR CATEGORY-THEORY DIAGRAMS
+
+%The following control symbols may be redefined by the user:
+\def\ctvertexstyle{\displaystyle}
+\def\ctabutstyle{\textstyle}
+\def\ctvertexborderlr{3pt}
+\def\ctvertexbordertb{4pt}
+\def\ctloopdiameter{20pt}
+\def\ctabutcircledisp{5pt}
+\def\ctabutborderlr{2pt}
+\def\ctabutbordertb{2pt}
+\def\ctabutborderinset{3pt}
+\def\ctabutborderinsetdouble{6pt}%Must be twice \ctabutborderinset
+\def\ctdoubleedgedisp{2pt}
+
+%The following registers are used locally:
+\newdimen\zzdmX\newdimen\zzdmY
+
+%Hidden macros and other defined control symbols:
+% used by \ctdiagram: \diagram\ctsolid\cthead
+% used by \ctv and \ctvg: \vertex\border\rect
+% used by \ctgl: \leftghost
+% used by \ctgr: \rightghost
+% used by \ctlptl, \ctlptlcc, \ctlptr, \ctlptrcc, \ctlpbr, \ctlpbrcc,
+% \ctlpbl, \ctlpblcc: \zzctlp\border\setcircle\shiftcircle\drawcircle
+% \drawcirclehead\abutcircleleft\abutcircleright\zzctabutprog
+% \octagon
+% used by \cten, \ctet, \cteb, \ctel, \cter, \ctetg, \ctebg, \ctelg, \cterg,
+% \ctetb, \ctelr, \ctetbg, \ctelrg: \setedge\zzctxmean\zzctymean
+% \zzmultdiagramunit\zzcte\zzctee\shadeedge\abutaboved\abutbelowd
+% \abutleftd\abutrightd\zzctabutprog\border\octagon\shiftedge
+% \drawsolidedge\zzctdrawdashedge\drawdashedge\zzctdrawdotedge
+% \drawdotedge\zzctdrawedgehead\drawedgehead\zzctnodrawedgehead
+% multiply defined control symbols: \zzctdrawedge\zzctdrawhead
+% \zzctxmeanadj\zzctymeanadj
+
+%\ctdiagram is similar to \diagram, except that it executes \ctsolid and
+%\cthead before the expression program #1.
+
+\def\ctdiagram#1{\diagram{\ctsolid\cthead\ctoutermid #1}}
+
+%\ctvg is similar to \vertex except that the expression #3 is printed in
+%\ctvertexstyle mode, and the expression program #4 is followed by a
+%standard program that borders the current rectangle by \ctvertexborderlr
+%on the sides and \ctvertexbordertb on the top and bottom, and then
+%creates a rectangular shadow. \ctv is similar to \ctvg except that the
+%expression program is empty (except for the standard program).
+
+\def\ctvg#1,#2:#3#4{\vertex #1,#2:{\ctvertexstyle #3}{#4\relax
+\border\ctvertexborderlr\ctvertexbordertb\rect}}
+
+\def\ctv#1,#2:#3{\ctvg #1,#2:{#3}{}}
+
+%\ctgl and \ctgr are similar to \leftghost and \rightghost except that
+%the expression #1 is printed in \ctvertexstyle.
+
+\def\ctgl#1{\leftghost{\ctvertexstyle #1}}
+
+\def\ctgr#1{\rightghost{\ctvertexstyle #1}}
+
+%The following eight macros print a three-quarter-circle loop of diameter
+%\ctloopdiameter at one of the corners of an expanded current rectangle,
+%with an arrowhead at one end of the loop.
+
+\def\ctlptl#1{\zzctlp{\lexpr\texpr}{{0pt}\circleheaddisp}{1011}{101}
+{\abutcircleleft\ctabutcircledisp}{#1}}
+
+\def\ctlptlcc#1{\zzctlp{\lexpr\texpr}{{-\circleheaddisp}{0pt}}{1011}{0{-1}0}
+{\abutcircleleft\ctabutcircledisp}{#1}}
+
+\def\ctlptr#1{\zzctlp{\rexpr\texpr}{\circleheaddisp{0pt}}{1101}{0{-1}1}
+{\abutcircleright\ctabutcircledisp}{#1}}
+
+\def\ctlptrcc#1{\zzctlp{\rexpr\texpr}{{0pt}\circleheaddisp}{1101}{{-1}00}
+{\abutcircleright\ctabutcircledisp}{#1}}
+
+\def\ctlpbr#1{\zzctlp{\rexpr\bexpr}{{0pt}{-\circleheaddisp}}{1110}{{-1}01}
+{\abutcircleright{-\ctabutcircledisp}}{#1}}
+
+\def\ctlpbrcc#1{\zzctlp{\rexpr\bexpr}{\circleheaddisp{0pt}}{1110}{010}
+{\abutcircleright{-\ctabutcircledisp}}{#1}}
+
+\def\ctlpbl#1{\zzctlp{\lexpr\bexpr}{{-\circleheaddisp}{0pt}}{0111}{011}
+{\abutcircleleft{-\ctabutcircledisp}}{#1}}
+
+\def\ctlpblcc#1{\zzctlp{\lexpr\bexpr}{{0pt}{-\circleheaddisp}}{0111}{100}
+{\abutcircleleft{-\ctabutcircledisp}}{#1}}
+
+\def\zzctlp#1#2#3#4#5#6{\border\ctvertexborderlr\ctvertexbordertb
+\setcircle\ctloopdiameter #1
+\border{-\ctvertexborderlr}{-\ctvertexbordertb}
+\shiftcircle #2\drawcircle #3\drawcirclehead #4
+#5{\ctabutstyle #6}\zzctabutprog}
+
+\def\zzctabutprog{\border\ctabutborderlr\ctabutbordertb
+\borderto{\ctabutborderinsetdouble}{\ctabutborderinsetdouble}
+\octagon\ctabutborderinset}
+
+%\cten#1,#2,#3,#4: draws a shaded edge from #1,#2 to #3,#4, possibly with
+%an arrowhead at its end.
+
+\def\cten#1:{\setedge#1:\shadeedge\zzctdrawedge\zzctdrawhead1}
+
+%The following four macros draw a shaded edge, possibly with an arrowhead
+%at the end, and abut an expression to the edge at its midpoint.
+
+\def\ctet#1:#2{\setedge#1:\zzctxmean\zzcte\abutaboved{#2}\zzctxmeanadj}
+
+\def\cteb#1:#2{\setedge#1:\zzctxmean\zzcte\abutbelowd{#2}\zzctxmeanadj}
+
+\def\ctel#1:#2{\setedge#1:\zzctymean\zzcte\abutleftd{#2}\zzctymeanadj}
+
+\def\cter#1:#2{\setedge#1:\zzctymean\zzcte\abutrightd{#2}\zzctymeanadj}
+
+\def\zzctxmean{\zzdmX=\xstart\advance\zzdmX by \xend\divide\zzdmX by 2}
+
+\def\zzctymean{\zzdmX=\ystart\advance\zzdmX by \yend\divide\zzdmX by 2}
+
+\def\zzcte#1#2#3{\shadeedge #3\zzctdrawedge\zzctdrawhead1
+#1\zzdmX{\ctabutstyle #2}\zzctabutprog}
+
+%The next four macros behave similarly to those above, but abut an
+%expression to a specified point on the edge.
+
+\def\ctetg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
+\abutaboved{#3}\relax}
+
+\def\ctebg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
+\abutbelowd{#3}\relax}
+
+\def\ctelg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
+\abutleftd{#3}\relax}
+
+\def\cterg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte
+\abutrightd{#3}\relax}
+
+%\ctetb (\ctelr) draws a pair of shaded edges, with two expressions
+%abutted to the top and bottom (left and right) of the midpoint.
+%\ctetbg and \ctelrg are similar, but abut to a specified point on the edge.
+
+\def\ctetb#1:#2#3#4#5{\zzcheckbool{#2}{FIFTH}{CTETB}
+\zzcheckbool{#3}{SIXTH}{CTETB}
+\setedge#1:\zzctxmean\zzctee\xslope\abutaboved\abutbelowd
+{#2}{#3}{#4}{#5}\zzctxmeanadj}
+
+\def\ctelr#1:#2#3#4#5{\zzcheckbool{#2}{FIFTH}{CTELR}
+\zzcheckbool{#3}{SIXTH}{CTELR}
+\setedge#1:\zzctymean\zzctee\yslope\abutleftd\abutrightd
+{#2}{#3}{#4}{#5}\zzctymeanadj}
+
+\def\ctetbg#1;#2,#3:#4#5#6#7{\zzcheckbool{#4}{SEVENTH}{CTETBG}
+\zzcheckbool{#5}{EIGHTH}{CTETBG}\setedge#1:\zzmultdiagramunit\zzdmX{#2}
+\zzctee\xslope
+\abutaboved{\zzmultdiagramunit\zzdmX{#3}\abutbelowd}{#4}{#5}{#6}{#7}\relax}
+
+\def\ctelrg#1;#2,#3:#4#5#6#7{\zzcheckbool{#4}{SEVENTH}{CTELRG}
+\zzcheckbool{#5}{EIGHTH}{CTELRG}\setedge#1:\zzmultdiagramunit\zzdmX{#2}
+\zzctee\yslope
+\abutleftd{\zzmultdiagramunit\zzdmX{#3}\abutrightd}{#4}{#5}{#6}{#7}\relax}
+
+\def\zzctee#1#2#3#4#5#6#7#8{
+\ifnum#1>0\relax\zzdmY=\ctdoubleedgedisp\else\zzdmY=-\ctdoubleedgedisp\fi
+\shiftedge\zzdmY\shadeedge #8\zzctdrawedge\zzctdrawhead{#4}
+#2\zzdmX{\ctabutstyle #6}\zzctabutprog
+\multiply\zzdmY by -2\relax
+\shiftedge\zzdmY\shadeedge #8\zzctdrawedge\zzctdrawhead{#5}
+#3\zzdmX{\ctabutstyle #7}\zzctabutprog}
+
+%\ctinnermid defines \zzctxmeanadj and \zzctymeanadj so that \ctet, \cteb,
+%\ctel, \cter, \ctetb, and \ctelr recompute the midpoint of the current
+%edge after shading. \ctoutermid defines these control symbols so that
+%these routines do not recompute the midpoint.
+
+\def\ctinnermid{\def\zzctxmeanadj{\zzctxmean}\def\zzctymeanadj{\zzctymean}}
+
+\def\ctoutermid{\def\zzctxmeanadj{\relax}\def\zzctymeanadj{\relax}}
+
+%\zzctdrawdashedge draws a dashed edge.
+
+\def\zzctdrawdashedge{\relax
+\ifnum\xslope=0\relax\drawdashedge{7pt}{7pt}11
+\else\ifnum\yslope=0\relax\drawdashedge{7pt}{7pt}11
+\else\drawdashedge{15pt}{7pt}01\fi\fi}
+
+%\zzctdrawdotedge draws a dotted edge.
+
+\def\zzctdrawdotedge{\drawdotedge{8pt}1}
+
+%\ctsolid (\ctdash,\ctdot) defines \zzctdrawedge to be \drawsolidedge
+%(\zzctdrawdashedge,\zzctdrawdotedge), so that edges will be solid
+%(dashed, dotted).
+
+\def\ctsolid{\def\zzctdrawedge{\drawsolidedge}}
+
+\def\ctdash{\def\zzctdrawedge{\zzctdrawdashedge}}
+
+\def\ctdot{\def\zzctdrawedge{\zzctdrawdotedge}}
+
+%\zzctdrawedgehead places a forward-pointing arrowhead at the end of an edge
+%if #1=1 or a backward-pointing arrowhead at the beginning if #1=0.
+%\zzctnodrawedgehead is called in the same way but does nothing.
+
+\def\zzctdrawedgehead#1{\relax\ifnum#1=1\relax
+\drawedgehead{100}10\else\drawedgehead{0}00\fi}
+
+\def\zzctnodrawedgehead#1{}
+
+%\cthead (\ctnohead) defines \zzctdrawhead to be \zzctdrawedgehead
+%(\zzctnodrawedgehead), so that edges will (will not) have arrowheads.
+
+\def\cthead{\def\zzctdrawhead{\zzctdrawedgehead}}
+
+\def\ctnohead{\def\zzctdrawhead{\zzctnodrawedgehead}}
diff --git a/macros/latex/contrib/diagmac/diagmac.tex b/macros/latex/contrib/diagmac/diagmac.tex
new file mode 120000
index 0000000000..46e4176e92
--- /dev/null
+++ b/macros/latex/contrib/diagmac/diagmac.tex
@@ -0,0 +1 @@
+diagmac.sty \ No newline at end of file
diff --git a/macros/latex/contrib/diagmac/diagmac.txt b/macros/latex/contrib/diagmac/diagmac.txt
new file mode 100644
index 0000000000..83cf911deb
--- /dev/null
+++ b/macros/latex/contrib/diagmac/diagmac.txt
@@ -0,0 +1,779 @@
+USER'S MANUAL FOR DIAGRAM MACROS - J. C. Reynolds - December 1987
+
+The file diagmac.tex contains TEX macros for producing various kinds of
+diagrams. It consists of two parts: a collection of general macros for
+producing a wide variety of diagrams, and a second collection of macros
+(which call upon the first) that are specifically oriented to category-theory
+diagrams.
+
+A second file diagmactest.tex is an input file for LATEX that tests the
+macros in diagmac.tex.
+
+USE OF THE LATEX PICTURE FACILITY
+
+These macros use the LATEX picture facility to draw lines, arrows, and
+circles. Thus all lines and arrowheads are subject to the limitations of
+this facility. In particular, the slope of any solid or dashed line must be
+a pair of integers whose magnitudes, after division by their greatest common
+divisor, are no more than six. When an arrowhead is placed on a line or a
+circular arc, the slope of the line (or the tangent to the arc)
+must be a pair of integers whose magnitudes, after division by their
+greatest common divisor, are no more than four. Also, lines (or dashes in
+dashed lines) that are not either horizontal or vertical will not appear
+unless they are longer than a minimum length, which is about 10 to 15 points.
+
+Since circles and circular arcs are also drawn via the LATEX picture
+facility, they are limited to a fixed variety of diameters. A list of these
+diameters is the meaning of the control symbol \diameterlist, which should
+be changed if a different circle font is used. (Note that it is a list
+of dimensions in increasing order that ends with a comma.)
+
+The latex declarations \thinlines and \thicklines may be used to vary
+the thickness of lines, arrowheads, and circles.
+
+PROGRAMS AND STATES
+
+Certain parameters to these macros are ``programs''. A program is a
+TEX text that does not directly produce any output but causes state changes
+by calling macros. For example, in LATEX, the text read in picture mode,
+i.e. the text between \begin{picture} and \end{picture} commands, is a
+program that causes state changes by calling the macro \put. (Internally,
+such macros cause state changes by assigning to hidden registers and
+redefining hidden control symbols. As a consequence, a program cannot
+call state-changing macros within a group.)
+
+The diagram-producing macros use two kinds of program, called diagram
+programs and expression programs. The state manipulated by a diagram
+program, called a diagram state, is a plane containing symbols, lines,
+and circles. Locations on this plane are specified by an x,y-coordinate
+system, in which x specifies horizontal distance, with increasing values
+to the right, and y specifies vertical distance, with increasing values
+upwards. The diagram state also contains a ``vertex list'', which is a
+list of points (i.e. x,y-coordinate pairs) paired with polygonal regions
+called ``shadows''.
+
+The diagram state may also contain a ``current edge'', which is a
+(perhaps invisible) directed line segment. When the current edge is defined,
+it is determined by four dimension registers:
+
+ \xstart: the x-coordinate of the start point
+ \ystart: the y-coordinate of the start point
+ \xend: the x-coordinate of the end point
+ \yend: the y-coordinate of the end point,
+
+and two number registers:
+
+ \xslope: the x-component of the slope
+ \yslope: the y-component of the slope
+
+giving the slope of the edge, reduced to lowest terms. A diagram program may
+refer to any of these quantities, and may also alter the dimension registers
+explicitly (as well as by calling diagram macros), providing this alteration
+preserves the slope of the edge.
+
+The state manipulated by an expression program, called an expression state,
+is also a plane, containing an expression and other symbols, etc.,
+upon which is imposed an x,y-coordinate system. This state contains an
+invisible ``current rectangle'', determined by the four dimension registers:
+
+ \lexpr: the x-coordinate of the left side
+ \rexpr: the x-coordinate of the right side
+ \texpr: the y-coordinate of the top
+ \bexpr: the y-coordinate of the bottom,
+
+and a ``center point'', determined by the two dimension registers:
+
+ \xcenter: the x-coordinate of the center point
+ \ycenter: the y-coordinate of the center point.
+
+An expression program may refer to or alter these six dimension registers
+explicitly (as well as by calling various macros).
+
+The expression state may also contain a (perhaps invisible) polygon called
+the ``current shadow'', and a (perhaps invisible) circle called the
+``current circle''. When the current circle is defined, it is determined
+by three dimension registers:
+
+ \dcircle: the diameter
+ \xcircle: the x-coordinate of the center
+ \ycircle: the y-coordinate of the center.
+
+An expression program may refer to or alter these three dimension registers
+explicitly (as well as by calling various macros).
+
+The qualification ``perhaps invisible'' is meant to indicate that the
+position, shape, and size of edges, shadows, and circles are established
+by one group of macros (e.g. \setedge, \rect, \octagon, \setcircle), but
+that these entities are actually drawn, i.e. made to appear on the plane
+of the diagram or expression state, by another group of macros (e.g.
+\drawsolidedge, \outline, \drawcircle).
+
+In calls of the diagram macros, a coordinate is sometimes specified by a
+dimension, but often it is specified by a number (i.e. integer) that gives
+the coordinate as a multiple of the dimension that is the meaning of the
+control symbol \diagramunit. This control symbol is defined to be 1pt,
+but the user may redefine it to be some other dimension, either in his main
+program or at the beginning of a diagram program.
+
+In addition to the control symbols discussed in this description, this
+collection of macros defines a large number of control symbols that are
+normally no concern of the user. To avoid the accidental redefinition
+of these symbols by the user, they are all given names beginning with \zz.
+
+THE GENERAL MACROS FOR DIAGRAMS
+
+We now describe the general macros for drawing diagrams. The main level
+macro is
+
+ \diagram{<diagram program>}
+
+It executes the diagram program that is its only parameter, and then issues
+the final state produced by this program as a horizontal box whose height,
+width, and depth are just enough to enclose all of the symbols and lines
+in this state, plus the origin (0,0) of the coordinate system. The height
+(depth) will be the distance from the horizontal line y=0 to the highest
+(lowest) extent of any symbol or line.
+
+Within a diagram program, one can call the following macros:
+
+ \vertex<number:x-coord>,<number:y-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+\vertex sets the <balanced mathematical text> in math mode, with text style,
+and creates an expression state containing the resulting expression, with
+the current rectangle just enclosing the expression. The center point is
+placed midway between the left and right sides of the current rectangle,
+at a height above the baseline of the expression given by the control
+symbol \centerheight, which is defined to be 3pt. (The effect is to place
+the center point on the axis of the expression. However, the user may need
+to change the definition of \centerheight if he is using unusual fonts or
+script style.) The reference point of the expression will lie at the
+origin of the coordinate system.
+
+Next, \vertex executes the <expression program> to modify the expression
+state. Then the material in the expression state is placed in the
+current diagram state, at a position so that the center point lies at
+the point <number:x-coord>,<number:y-coord>. Finally, if the expression
+state contains a current shadow, the point <number:x-coord>,<number:y-coord>
+is paired with the shadow and placed on the vertex list.
+
+ \place<number:x-coord>,<number:y-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+ \placed{<dimen:x-coord>}{<dimen:y-coord>}
+ {<balanced mathematical text>}{<expression program>}
+
+\place behaves the same way as \vertex, except that nothing is placed on the
+vertex list. \placed behaves the same way as \place, except that the
+coordinates at which the center point is placed are expressed by dimensions
+rather than numbers.
+
+ \setedge<number:x-start-coord>,<number:y-start-coord>,
+ <number:x-end-coord>,<number:y-end-coord>:
+
+\setedge makes the current edge a directed line segment from the point
+``start'' given by its first two parameters to the point ``end'' given
+by its last two parameters. This line segment is invisible (until it
+is drawn by one of the macros discussed below).
+
+\setedge also examines the vertex list to obtain any shadows that have been
+associated with the start or end points by prior executions of \vertex.
+
+ \shiftedge{<dimen:length>}
+
+\shiftedge displaces the current edge by a vector whose length is determined
+by the <dimen:length> parameter, and whose direction is obtained by rotating
+the current edge 90 degrees counterclockwise.
+
+ \shadeedge
+
+\shadeedge changes the extent of the current edge, without displacing
+or rotating it, to exclude the portions of the edge lying within shadows
+associated with its start and end points. If the execution of \setedge that
+established the current edge found a shadow associated with the start point,
+then \shadedge will shorten (or conceivably lengthen) the current edge
+so that its start point lies on the boundary of the shadow. (If this is
+not possible, the start point will be adjusted to be as close as possible
+to the shadow.) The end point is adjusted similarly.
+
+ \drawsolidedge
+
+\drawsolidedge draws the current edge as a solid line. It is subject to
+the constraints of the LATEX picture facility.
+
+ \drawdashedge{<dimen:length>}{<dimen:length>}{<number>}{<number>}
+
+\drawdashedge draws the current edge as a dashed line. It is subject to
+the constraints of the LATEX picture facility (particularly regarding the
+minimum length of printable dashes for lines that are not horizontal or
+vertical). The dashed line will always begin and end with a dash. The
+number of dashes will be as large as possible subject to the constraint
+that, if one or more blanks occur, the dashes will be at least as long
+as the first parameter and the blanks will be at least as long as the
+second parameter. If one or more blanks occur, the excess length of the
+dashes and of the blanks will be proportional to the third and fourth
+parameters respectively. The first two parameters must be positive
+dimensions, and the last two parameters must be nonnegative numbers whose
+sum is positive.
+
+ \drawdotedge{<dimen:length>}{<1 or 0>}
+
+\drawdotedge draws the current edge as a dotted line. The number of dots
+will be the largest number such that the distance between dots is at least
+as large as the first parameter, which must be a positive dimension.
+A dot will always appear at the start point, and will appear at the end
+point if the second parameter is 1. If the second parameter is 0 then
+the final dot will be omitted.
+
+ \drawedgehead{<number:0 to 100>}{<1 or 0>}{<1 or 0>}
+
+\drawedgehead draws an arrowhead on the current edge at a distance from
+the start point of p times the length of the edge, where p is the first
+parameter divided by 100. The arrowhead will point to the end point if
+the second parameter is 1, or to the start point if the second parameter
+is 0. If the third parameter is 1, the arrowhead will be advanced towards
+its tip by the value of the control symbol \edgeheaddisp, which is defined
+to be 4pt, but may be redefined by the user.
+
+ \abutleft<number:y-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutright<number:y-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutbelow<number:x-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutabove<number:x-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+Each of these macros uses the <balanced mathematical text> to initialize
+an expression state (in the same way as \vertex) and then executes
+the <expression program>, which must establish a shadow. The material in
+the expression state is then placed in the diagram state, at a location
+such that the shadow touches the current edge (or its extension as an
+infinite line), and lies to the left (or to the right, below, or above,
+as determined by the macro name). For \abutleft and \abutright, which
+must not be used when the current edge is horizontal, the first parameter
+gives the y-coordinate of the point at which the center point is to be
+located. For \abutbelow and \abutabove, which must not be used when the
+current edge is vertical, the first parameter gives the x-ccordinate.
+
+ \abutleftd{<dimen:y-coord>}
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutrightd{<dimen:y-coord>}
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutbelowd{<dimen:x-coord>}
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutaboved{<dimen:x-coord>}
+ {<balanced mathematical text>}{<expression program>}
+
+Each of these macros behaves the same way as its cousin, described above,
+except that the first parameter is a dimension instead of a number.
+
+Within an expression program, one can call the following macros:
+
+ \leftghost{<balanced mathematical text>}
+
+ \rightghost{<balanced mathematical text>}
+
+These macros change \xcenter (the x-coordinate of the center point).
+The <balanced mathematical text> is set in an hbox, using math mode,
+text style, which is ignored except for its width. \leftghost sets
+\xcenter to the left of the current rectangle plus half the width of
+the hbox. \rightghost sets \xcenter to the right of the current rectangle
+minus half the width of the hbox. The effect is to place the ``ghost
+expression'' (invisibly) within the current rectangle at the left or
+right side, and to move the center point horizontally to the midpoint of
+the ghost expression.
+
+ \border{<dimen:x-length>}{<dimen:y-length>}
+
+ \borderto{<dimen:x-length>}{<dimen:y-length>}
+
+ \symmetrize
+
+These macros enlarge the current rectangle. \border moves the left and
+right sides outwards by its first parameter, and raises the top and lowers
+the bottom by its second parameter. (If either parameter is negative,
+the rectangle will contract.) \borderto enlarges the current rectangle
+so that its width is at least the first parameter and its height (including
+depth) is at least the second parameter. (Equal amounts will be added at
+the left and right, and at the top and bottom.) \symmetrize raises the top
+or lowers the bottom so that they are equally distant from the center point.
+
+ \place<number:x-coord>,<number:y-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+ \placed{<dimen:x-coord>}{<dimen:y-coord>}
+ {<balanced mathematical text>}{<expression program>}
+
+These macros can be called from expression programs as well as diagram
+programs. They have no effect on the current rectangle or center point.
+
+ \rect
+
+\rect defines the current shadow to be the current rectangle.
+
+ \hexagon
+
+\hexagon defines the current shadow to be a hexagon with two horizontal
+sides identical with the top and bottom of the current rectangle, and
+four sides of slope (+ or - 1), (+ or - 2).
+
+ \octagon{<dimen:length>}
+
+\octagon defines the current shadow to be an octagon inscribed in the
+current rectangle. The horizontal sides and vertical sides are shorter than
+those of the current rectangle by twice the parameter, and the remaining
+sides have slope (+ or - 1), (+ or - 1).
+
+ \diamond
+
+\diamond defines the current shadow to be a square, just large enough to
+enclose the current rectangle, whose sides have slope (+ or - 1), (+ or - 1).
+
+ \rorect{<dimen:diameter>}{<1 or 0>}{<1 or 0>}
+
+\rorect defines the current shadow to be a rectangle with rounded (i.e.
+quarter-circle) corners. The diameter of the corners is determined as
+follows:
+
+ (1) Take the maximum of:
+ (a) The first parameter,
+ (b) If the second parameter is 1, then the width of the current
+ rectangle, else 0,
+ (c) If the third parameter is 1, then the height of the current
+ rectangle, else 0.
+
+ (2) Take the diameter of the smallest printable circle larger or equal
+ to (1), or if no such printable circle exists, take the diameter
+ of the largest printable circle.
+
+The shadow is then the smallest rounded rectangle with corners of this
+diameter such that the corresponding true (unrounded) rectangle encloses
+the current rectangle.
+
+The effect (if there is a sufficiently large printable circle) is to produce:
+
+ A rounded rectangle 00
+ A vertical oblong if the second and third parameters are 10
+ A horizontal oblong 01
+ A circle 11
+
+If the shadow is drawn (using \outline, as described below) its shape will
+be the rounded rectangle just described. However, if the shadow is used
+to shade an edge or to abut an expression to an edge or circle, then a
+slight fudge occurs: the shadow is taken to be the smallest octagon
+(with the same shape as that produced by \octagon) enclosing the specified
+rounded rectangle.
+
+ \outline
+
+\outline draws the current shadow.
+
+ \setcircle{<dimen:diameter>}{<dimen:x-coord>}{<dimen:y-coord>}
+
+\setcircle defines the current circle to have a diameter given by the first
+parameter and a center defined by the second and third parameter.
+
+ \shiftcircle{<dimen:x-length>}{<dimen:y-length>}
+
+\shiftcircle displaces the current circle by the vector described by its
+parameters.
+
+ \drawcircle<1 or 0:upper right quadrant><1 or 0:lower right quadrant>
+ <1 or 0:lower left quadrant><1 or 0:upper left quadrant>
+
+\drawcircle draws the current circle. More precisely, it draws those
+quadrants of the current circle for which the corresponding parameter is 1.
+
+ \drawcirclehead{<number:x-slope>}{<number:y-slope>}{<1 or 0>}
+
+\drawcirclehead draws an arrowhead on the current circle, at the
+intersection with a directed line segment starting at the center with a
+slope determined by the first two parameters. If the third parameter
+is 1 (0) the arrowhead will point in a clockwise (counterclockwise)
+direction. The arrowhead will be advanced towards its tip by the distance
+\circleheaddisp. This control symbol is defined to be 2pt, but may be
+redefined by the user.
+
+ \abutcircleleft{<dimen:y-length>}
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutcircleright{<dimen:y-length>}
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutcirclebelow{<dimen:x-length>}
+ {<balanced mathematical text>}{<expression program>}
+
+ \abutcircleabove{<dimen:x-length>}
+ {<balanced mathematical text>}{<expression program>}
+
+Each of these macros uses the <balanced mathematical text> to initialize
+an expression state (in the same way as \vertex) and then executes the
+<expression program>, which must establish a shadow. The material in the
+final expression state produced by this program is then placed in the
+expression state of the expression program containing the call of
+\abutcircle... , at a location such that shadow touches the current circle
+on the outside of this circle. For \abutcircleleft and \abutcircleright
+the first parameter gives the y-coordinate of the point at which the center
+is to be located. For \abutcirclebelow and \abutcircleabove the first
+parameter gives the x-coordinate.
+
+Actually, the abutment is approximate. For \abutcircleabove, the shadow
+is abutted against three tangents to the current circle, that touch at the
+top of the circle and at the two points 45 degrees to the left and right
+of the top, and is then given the lowest of the three positions obtained
+by these abutments. The other three macros behave similarly.
+
+AN EXAMPLE
+
+As a simple example, consider
+
+$$\diagram{
+\vertex 0,100:{A}{\border{3pt}{4pt}\rect}
+\vertex 150,100:{B}{\border{3pt}{4pt}\rect}
+\vertex 0,0:{A'}{\border{3pt}{4pt}\rect}
+\vertex 150,0:{B'}{\border{3pt}{4pt}\rect}
+\setedge 0,100,150,100:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutabove 75:{\textstyle c}{\border{2pt}{2pt}\octagon{3pt}}
+\setedge 0,0,150,0:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutbelow 75:{\textstyle c'}{\border{2pt}{2pt}\octagon{3pt}}
+\setedge 0,100,0,0:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutleft 50:{\textstyle a}{\border{2pt}{2pt}\octagon{3pt}}
+\setedge 150,100,150,0:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutright 50:{\textstyle b}{\border{2pt}{2pt}\octagon{3pt}}
+}$$
+
+This call of \diagram contains a diagram program in which the four calls
+of \vertex place the expressions A, B, A', and B' at the four corners of
+a 100pt by 150pt rectangle. Then come four groups of five calls that
+draw edges along the sides of this rectangle and abut expressions to
+the middles of these edges.
+
+In each group, \setedge determines the position of the edge, \shadeedge
+adjusts the end points to exclude the shadows of the expressions that
+have been placed at these points by \vertex, \drawsolidedge draws the
+edge as a solid line, and \drawedgehead places an arrowhead at the end
+of the edge. Then \abut... places an expression above, below, to the
+left, or to the right of the midpoint of the edge, so that its shadow
+touches the edge.
+
+In the calls of \vertex, {\border{3pt}{4pt}\rect} is an expression program
+that enlarges the current rectangle by 3pt at the left and right and by 4pt
+at the top and bottom, and then establishes this expanded rectangle as the
+shadow. In the calls of \abut... , {\border{2pt}{2pt}\octagon{3pt}} is an
+expression program that enlarges the current rectangle by 2pt on each side
+and then defines the shadow to be an octagon inscribed in this expanded
+rectangle, with slanted edges of length 4.24pt.
+
+The result is a display that looks approximately like:
+
+ c
+ A --------------------> B
+ | |
+ | |
+ | |
+ a| |b
+ | |
+ | |
+ V V
+ A'--------------------> B'
+ c'
+
+(except, of course that the arrows are solid).
+
+THE MACROS FOR CATEGORY-THEORY DIAGRAMS
+
+Now we describe the additional macros oriented towards category-theory
+diagrams. The main level program is
+
+ \ctdiagram{<diagram program>}
+
+\ctdiagram is similar to \diagram, except that it executes \ctsolid,
+\cthead, and \ctoutermid (described below) before the <diagram program>,
+so that the category-theory macros for drawing edges will draw solid edges
+with arrowheads and will calculate midpoints of edges before shading or
+displacement.
+
+Within a diagram program, one can call the following macros (in addition
+to the general macros described previously):
+
+ \ctvg<number:x-coord>,<number:y-coord>:
+ {<balanced mathematical text>}{<expression program>}
+
+ \ctv<number:x-coord>,<number:y-coord>:{<balanced mathematical text>}
+
+\ctvg is similar to \vertex, except that:
+
+ (1) The <balanced mathematical text> is set in \ctvertexstyle.
+ The control symbol \ctvertexstyle is defined to be \displaystyle,
+ but may be redefined by the user.
+
+ (2) The execution of the <expression program> is followed by a
+ ``standard expression program'' that enlarges the current rectangle
+ by \ctvertexborderlr on the left and right and by \ctvertexbordertb
+ on the top and bottom, and then creates a rectangular shadow of the
+ same size. The control symbols \ctvertexborderlr and \ctvertexbordertb
+ are defined to be 3pt and 4pt respectively, but may be redefined
+ by the user.
+
+\ctv is similar to \ctvg except that only the standard expression program
+is executed.
+
+ \ctsolid
+
+ \ctdash
+
+ \ctdot
+
+These macros cause subsequent executions of the edge-drawing macros described
+below to draw solid, dashed, or dotted edges respectively. Horizontal and
+vertical dashed edges are drawn by \drawdashedge{7pt}{7pt}11, but other
+dashed edges are drawn by \drawdashedge{15pt}{7pt}01. Dotted edges are
+drawn by \drawdotedge{8pt}1. (These conventions can be alter by redefining
+the macros \zzctdrawdashedge and \zzctdrawdotedge.)
+
+ \cthead
+
+ \ctnohead
+
+\cthead (\ctnohead) causes subsequent executions of the edge-drawing macros
+described below to draw (not to draw) arrowheads.
+
+ \cten<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:
+
+\cten draws an edge from x-start to x-end, after shading the start and end
+points with any shadows associated with these points on the vertex list.
+The edge will be solid, dashed, or dotted depending upon whether \ctsolid,
+\ctdash, or \ctdot was called last. An arrowhead will or will not be placed
+at the end point depending upon whether \cthead or \ctnohead was called last.
+
+ \ctetg<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>;<number:x-coord>:{<balanced mathematical text>}
+
+ \ctebg<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>;<number:x-coord>:{<balanced mathematical text>}
+
+ \ctelg<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>;<number:y-coord>:{<balanced mathematical text>}
+
+ \cterg<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>;<number:y-coord>:{<balanced mathematical text>}
+
+Each of these macros draws an edge in the same way as \cten, and then abuts
+the <balanced mathematical text> to the
+
+ top \ctetg
+ bottom for \ctebg
+ left \ctelg
+ right \cterg
+
+of the edge, with its center placed at the x-coordinate (for \ctetg or
+\ctebg) or y-coordinate (for \ctelg or \cterg) specified by the fifth
+parameter. The abutted expression is set in \ctabutstyle, with an octagonal
+shadow (of the shape produced by \octagon). This octagon will be inscribed
+in a rectangle obtained by bordering the expression by \ctabutborderlr
+on the left and right, and by \ctabutbordertb on the top and bottom;
+the length of the slanted sides of the octagon will be \ctabutborderinset
+times the square root of 2.
+
+The relevant control symbols are defined to be:
+
+ \ctabutstyle \textstyle
+ \ctabutborderlr 2pt
+ \ctabutbordertb 2pt
+ \ctabutborderinset 3pt
+
+These symbols may be redefined by the user, but \ctabutborderinsetdouble
+must also be redefined so that its value is twice \ctabutborderinset.
+
+\ctetg and \ctebg should not be used to draw a vertical edge; \ctelg and
+\cterg should not be used to draw a horizontal edge.
+
+ \ctetbg<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>;<number:x-coord>,<number:x-coord>:
+ {<1 or 0>}{<1 or 0>}
+ {<balanced mathematical text>}{<balanced mathematical text>}
+
+\ctetbg draws a pair of edges in the same manner as \cten and then abuts
+the first <balanced mathematical text> above the pair, in the same manner
+as \ctetg, with its center placed at the x-coordinate specified by the
+fifth parameter, and abuts the second <balanced mathematical text> below
+the pair, in the same manner as \ctebg, with its center placed at the
+x-coordinate specified by the sixth parameter. If the seventh parameter
+is 1 (and \cthead has been called most recently), the arrowhead on the upper
+edge will occur at the end point; otherwise it will occur (pointing
+backwards) at the start point. The eighth parameter controls the arrowhead
+on the lower edge similarly. The distance between the edges will be twice
+the control symbol \ctdoubleedgedisp, which is defined to be 2pt, but may
+be redefined by the user.
+
+\ctetbg should not be used to draw a vertical edge.
+
+ \ctelrg<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>;<number:y-coord>,<number:y-coord>:
+ {<1 or 0>}{<1 or 0>}
+ {<balanced mathematical text>}{<balanced mathematical text>}
+
+\ctelrg draws a pair of edges in the same manner as \cten and then abuts
+the first <balanced mathematical text> to the left, in the same manner
+as \ctetg, with its center placed at the y-coordinate specified by the
+fifth parameter, and abuts the second <balanced mathematical text> to
+the right, in the same manner as \ctebg, with its center placed at the
+y-coordinate specified by the sixth parameter. If the seventh parameter
+is 1 (and \cthead has been called most recently), the arrowhead on the left
+edge will occur at the end point; otherwise it will occur (pointing
+backwards) at the start point. The eighth parameter controls the arrowhead
+on the right edge similarly. The distance between the edges will be twice
+the control symbol \ctdoubleedgedisp, which is defined to be 2pt, but may
+be redefined by the user.
+
+\ctelrg should not be used to draw a horizontal edge.
+
+ \ctet<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:{<balanced mathematical text>}
+
+ \cteb<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:{<balanced mathematical text>}
+
+ \ctel<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:{<balanced mathematical text>}
+
+ \cter<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:{<balanced mathematical text>}
+
+ \ctetb<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:{<1 or 0>}{<1 or 0>}
+ {<balanced mathematical text>}{<balanced mathematical text>}
+
+ \ctelr<number:x-start-coord>,<number:y-start-coord>,<number:x-end-coord>,
+ <number:y-end-coord>:{<1 or 0>}{<1 or 0>}
+ {<balanced mathematical text>}{<balanced mathematical text>}
+
+These macros behave similarly to their cousins described above, except that
+the fifth parameter (and also the sixth parameter in the case of \ctetb and
+\ctelr) is omitted. In its place, these macros use the x- or y-coordinate
+of the midpoint between the start and end points of the edge. If \ctoutermid
+(described below) has been called most recently, then the midpoint will
+be calculated from the start and end coordinates given as parameters to the
+macros. If \ctinnermid (described below) has been called most recently,
+then the midpoint will be computed after displacement and shading, so that
+it will be the midpoint of the actual line segment that is printed.
+(In the case of \ctetb and \ctelr, this midpoint will be calculated
+separately for the two edges that are printed.)
+
+ \ctoutermid
+
+ \ctinnermid
+
+These macros control the calculation of edge midpoints as described above.
+
+Within a expression program, one can call the following macros (in addition
+to the general macros described previously):
+
+ \ctgl{<balanced mathematical text>}
+
+ \ctgr{<balanced mathematical text>}
+
+These macros are similar to \leftghost and \rightghost except that the
+<balanced mathematical text> is set in \ctvertexstyle.
+
+ \ctlptl{<balanced mathematical text>}
+
+ \ctlptr{<balanced mathematical text>}
+
+ \ctlpbr{<balanced mathematical text>}
+
+ \ctlpbl{<balanced mathematical text>}
+
+These macros print a loop (three quarters of a circle) of diameter
+\ctloopdiameter on the exterior of the current rectangle, with its center
+at the
+
+ top left \ctlptl
+ top right for \ctlptr
+ bottom right \ctlpbr
+ bottom left \ctlpbl
+
+corner of the current rectangle, and with a clockwise arrowhead at the
+clockwise end of the loop. Then the <balanced mathematical text> is
+abutted to the
+
+ left \ctlptl
+ right for \ctlptr
+ right \ctlpbr
+ left \ctlpbl
+
+of the loop, with its center
+
+ above \ctlptl
+ above for \ctlptr
+ below \ctlpbr
+ below \ctlpbl
+
+the center of the loop by the distance \ctabutcircledisp.
+
+The control symbols \ctloopdiameter and \ctabutcircledisp are defined to be
+20pt and 5pt respectively, but may be redefined by the user.
+
+The current rectangle is expanded by \ctvertexborderlr at the left and right
+and and \ctvertexbordertb at the top and bottom before the loop center
+is determined, and is contracted to its original size afterwards. Thus
+the loop center will lie at a corner of the shadow that will be produced
+by the ``standard expression program'' executed by \ctvg. (Actually, the
+loop center is displaced by \circleheaddisp, so that the tip of the
+arrowhead will just touch the shadow.) The arrowhead is always printed,
+regardless of the use of \cthead and \ctnohead.
+
+The <balanced mathematical text> is set in \ctabutstyle, and is given an
+octagonal shadow in the same manner as by \ctetg. The abutment to the loop
+is similar to that performed by \abutcircleleft or \abutcircleright.
+
+ \ctlptlcc{<balanced mathematical text>}
+
+ \ctlptrcc{<balanced mathematical text>}
+
+ \ctlpbrcc{<balanced mathematical text>}
+
+ \ctlpblcc{<balanced mathematical text>}
+
+These macros are similar to their cousins described above, except that a
+counterclockwise arrowhead is placed at the counterclockwise end of the loop.
+
+AN EXAMPLE
+
+For example, the following produces the same display as the previous
+example:
+
+$$\ctdiagram{
+\ctv 0,100:{A}
+\ctv 150,100:{B}
+\ctv 0,0:{A'}
+\ctv 150,0:{B'}
+\ctet 0,100,150,100:{c}
+\cteb 0,0,150,0:{c'}
+\ctel 0,100,0,0:{a}
+\cter 150,100,150,0:{b}
+}$$
+
+Less trivial examples of the usage of these macros are found in the file
+diagmactest.tex.
+
diff --git a/macros/latex/contrib/diagmac/diagmactest.pdf b/macros/latex/contrib/diagmac/diagmactest.pdf
new file mode 100644
index 0000000000..660d26f133
--- /dev/null
+++ b/macros/latex/contrib/diagmac/diagmactest.pdf
Binary files differ
diff --git a/macros/latex/contrib/diagmac/diagmactest.tex b/macros/latex/contrib/diagmac/diagmactest.tex
new file mode 100644
index 0000000000..7673ae4129
--- /dev/null
+++ b/macros/latex/contrib/diagmac/diagmactest.tex
@@ -0,0 +1,403 @@
+%TESTS OF DIAGRAM MACROS - J. C. Reynolds - December 1987
+
+%This is an input file for LATEX that inputs the macros in diagmac.tex
+%and tests them. A user's manual for these macros is in diagmac.doc
+
+\documentstyle[12pt]{article}
+\oddsidemargin=0in
+\evensidemargin=0in
+\textwidth=6.5in
+\begin{document}
+
+\thispagestyle{empty}
+
+\begin{centering}
+{\large\bf TESTS OF DIAGRAM MACROS} \\[14 pt]
+\today \\[21 pt]
+\end{centering}
+
+\input diagmac
+
+%These are the two examples given in the user's manual.
+
+$$\diagram{
+\vertex 0,100:{A}{\border{3pt}{4pt}\rect}
+\vertex 150,100:{B}{\border{3pt}{4pt}\rect}
+\vertex 0,0:{A'}{\border{3pt}{4pt}\rect}
+\vertex 150,0:{B'}{\border{3pt}{4pt}\rect}
+\setedge 0,100,150,100:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutabove 75:{\textstyle c}{\border{2pt}{2pt}\octagon{3pt}}
+\setedge 0,0,150,0:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutbelow 75:{\textstyle c'}{\border{2pt}{2pt}\octagon{3pt}}
+\setedge 0,100,0,0:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutleft 50:{\textstyle a}{\border{2pt}{2pt}\octagon{3pt}}
+\setedge 150,100,150,0:
+\shadeedge
+\drawsolidedge
+\drawedgehead{100}10
+\abutright 50:{\textstyle b}{\border{2pt}{2pt}\octagon{3pt}}
+}$$
+
+$$\ctdiagram{
+\ctv 0,100:{A}
+\ctv 150,100:{B}
+\ctv 0,0:{A'}
+\ctv 150,0:{B'}
+\ctet 0,100,150,100:{c}
+\cteb 0,0,150,0:{c'}
+\ctel 0,100,0,0:{a}
+\cter 150,100,150,0:{b}
+}$$
+
+\newpage
+
+%This gives a thorough workout to the general macros for diagrams.
+%The result looks like an eye-chart for Martians.
+
+$$\diagram{
+\vertex -150,0:{X+Y}{\border{4pt}{3pt}\rorect{2pt}01\outline}
+\vertex 0,-50:Y{\border{10pt}{10pt}\hexagon\outline}
+\vertex 150,0:\sum{\border{10pt}{10pt}\octagon{10pt}\outline
+ \border{5pt}{5pt}\octagon{12pt}\thicklines\outline\thinlines}
+\vertex -100,150:\alpha{\border{4pt}{3pt}\diamond\outline}
+\vertex 100,150:\sum{\border{10pt}{10pt}\rorect{20pt}00\outline
+ \border{5pt}{5pt}\rorect{24pt}00\thicklines\outline\thinlines}
+\vertex 0,200:{X^2+Y^2}{\border{4pt}{3pt}\rect\outline}
+\place -150,-150:{X+Y^{Z^2}}
+ {\leftghost X\symmetrize\borderto{0pt}{0pt}\border{4pt}{3pt}\rect\outline
+ \setcircle{16pt}{\xcenter}{\bexpr}\drawcircle0110
+ \drawcirclehead{0}{-1}1
+ \abutcirclebelow{-10pt}\alpha{\border{2pt}{2pt}\rect\outline}
+ \abutcirclebelow{10pt}\alpha{\border{2pt}{2pt}\rect\outline}}
+\placed{150pt}{-150pt}{X+Y}
+ {\rightghost Y\symmetrize\borderto{0pt}{26pt}\border{4pt}{0pt}\rect\outline
+ \placed{\lexpr}{\ycenter}{\vrule height3.2pt depth-2.8pt width10pt}{}
+ \place 0,-3:{\vrule height3.2pt depth-2.8pt width10pt}{\xcenter=\lexpr}
+ \setcircle{16pt}{\rexpr}{\texpr}\shiftcircle{8pt}{8pt}\drawcircle1101
+ \drawcirclehead{0}{-1}1\drawcirclehead{-1}00
+ \abutcircleabove{0pt}\alpha{\border{2pt}{2pt}\rect\outline}}
+\vertex 0,-150:{}{\setcircle{40pt}{\xcenter}{\ycenter}\drawcircle1111
+ \drawcirclehead231\drawcirclehead{-2}30
+ \drawcirclehead6{-9}0\drawcirclehead{-4}{-6}1
+ \abutcircleleft{0pt}\alpha{\border{2pt}{2pt}\rect\outline}
+ \abutcircleright{20pt}\alpha{\border{2pt}{2pt}\rect\outline}
+ \abutcircleright{0pt}\alpha{\border{2pt}{2pt}\rect\outline}
+ \abutcircleright{-20pt}\alpha{\border{2pt}{2pt}\rect\outline}}
+\setedge 0,200,-100,150:\shadeedge\drawsolidedge\drawedgehead{100}10
+ \abutleft 185:{\alpha+\beta}{\border{2pt}{2pt}\rorect{5pt}01\outline}
+\setedge 0,200,100,150:\shadeedge\drawsolidedge\drawedgehead{100}10
+ \abutright 185:{\alpha+\beta}{\border{2pt}{2pt}\rorect{5pt}01\outline}
+\setedge -150,0,0,-50:\shadeedge\drawdashedge{11pt}{10pt}01\drawedgehead{80}01
+ \abutleftd{-25pt}{\alpha\beta}
+ {\border{2pt}{2pt}\borderto{25pt}{0pt}\rect\outline}
+\setedge -150,0,150,0:\drawedgehead{50}01\shadeedge\drawsolidedge
+ \abutabove -10:\rho{\border{2pt}{2pt}\diamond\outline}
+\setedge -150,0,-100,150:\shadeedge\drawsolidedge\drawedgehead{100}10
+ \abutleft 75:\rho{\border{10pt}{10pt}\octagon{10pt}\outline}
+\setedge -150,0,100,150:\shadeedge\drawdotedge{7pt}1
+ \abutaboved{-100pt}\rho{\border{10pt}{10pt}\hexagon\outline}
+\setedge 0,-50,150,0:\shadeedge\drawsolidedge\drawedgehead{20}11
+ \abutrightd{-25pt}\rho{\border{2pt}{2pt}\borderto{25pt}{0pt}\rect\outline}
+\setedge 0,-50,-100,150:\shadeedge\drawsolidedge
+\setedge 0,-50,100,150:\shadeedge\drawsolidedge
+\setedge 150,0,-100,150:\shadeedge\drawsolidedge
+ \abutbelowd{100pt}\rho{\border{10pt}{10pt}\hexagon\outline}
+\setedge 150,0,100,150:\shadeedge\drawdashedge{40pt}{40pt}11\drawedgehead000
+ \abutleft 75:\rho{\border{10pt}{10pt}\hexagon\outline}
+ \shiftedge{-10pt}\shadeedge\drawdashedge{30pt}{30pt}10\drawedgehead000
+ \shiftedge{-10pt}\shadeedge\drawdashedge{11pt}{5pt}01\drawedgehead000
+ \shiftedge{-10pt}\shadeedge\drawdotedge{8pt}0\drawedgehead{100}10
+ \abutright 75:\rho{\border{5pt}{5pt}\rorect{5pt}11\outline}
+\setedge -100,150,100,150:\drawedgehead{50}11\shadeedge\drawsolidedge
+ \abutbelow 0:\rho{\border{2pt}{2pt}\rect\outline}
+\setedge 0,-50,-150,-150:\thicklines\drawedgehead{50}01\thinlines
+ \shadeedge\drawdashedge{13pt}{3pt}01\drawedgehead{50}11
+ \abutbelow -50:{X \atop Y}{\border{2pt}{2pt}\rorect{5pt}10\outline}
+\setedge 0,-50,0,-150:\thicklines\shadeedge\drawsolidedge\thinlines
+\setedge 0,-50,150,-150:\shadeedge\drawsolidedge
+ \abutabove 75:{X \atop Y}{\border{2pt}{2pt}\rorect{5pt}10\outline}
+\setedge -175,-50,-175,-100:\drawdashedge{10pt}{31pt}11
+\setedge -165,-100,-165,-50:\drawdashedge{15pt}{15pt}01
+\setedge -155,-50,-155,-100:\drawdashedge{5pt}{5pt}11
+\setedge -145,-100,-145,-50:\drawdotedge{26pt}1
+\setedge -135,-50,-135,-100:\drawdotedge{25pt}1
+\setedge -125,-100,-125,-50:\drawdotedge{5pt}1
+\setedge 125,-50,175,-50:\drawdashedge{10pt}{31pt}11
+\setedge 175,-60,125,-60:\drawdashedge{15pt}{15pt}01
+\setedge 125,-70,175,-70:\drawdashedge{5pt}{5pt}11
+\setedge 175,-80,125,-80:\drawdotedge{26pt}1
+\setedge 125,-90,175,-90:\drawdotedge{25pt}1
+\setedge 175,-100,125,-100:\drawdotedge{5pt}1
+}$$
+
+\newpage
+
+%These three diagrams test the macros for category-theory diagrams.
+
+$$\ctdiagram{
+\ctvg0,0:{Y'}{\ctlpbl{I_{Y'}}}
+\ctvg150,0:{Z=Z_0}{\ctgl{Z}\ctlpbr{I_Z}}
+\ctvg0,100:{X_0=X}{\ctgr{X}\ctlptl{I_X}}
+\ctvg150,100:{Y}{\ctlptr{I_Y}}
+\ctet0,100,150,100:\alpha
+\cteb0,0,150,0:{\beta'}
+\ctel0,100,0,0:{\alpha'}
+\cter150,100,150,0:\beta
+\ctetb0,100,150,0:11{\alpha;\beta}{\alpha';\beta'}
+}$$
+
+$$\ctdiagram{\ctdash
+\ctvg0,0:{Y'}{\ctlpblcc{I_{Y'}}}
+\ctvg150,0:{Z=Z_0}{\ctgl{Z}\ctlpbrcc{I_Z}}
+\ctvg0,100:{X_0=X}{\ctgr{X}\ctlptlcc{I_X}}
+\ctvg150,100:{Y}{\ctlptrcc{I_Y}}
+\ctet0,100,150,100:\alpha
+\ctnohead\cteb0,0,150,0:{\beta'}\cthead
+\ctel0,100,0,0:{\alpha'}
+\cter150,100,150,0:\beta
+\ctelr0,100,150,0:11{\alpha';\beta'}{\alpha;\beta}
+}$$
+
+$$\ctdiagram{
+\ctv0,0:{Y'}
+\ctvg150,0:{Z=Z_0}{\ctgl{Z}}
+\ctvg0,100:{X_0=X}{\ctgr{X}}
+\ctv150,100:Y
+\ctetg0,100,150,100;50:\alpha
+\ctebg0,0,150,0;50:{\beta'}
+\ctelg0,100,0,0;30:{\alpha'}
+\cterg150,100,150,0;30:\beta
+\ctetbg0,100,150,0;50,100:10{\rho}{\rho'}
+\ctelrg0,0,150,100;70,30:01{\theta}{\theta'}
+}$$
+
+\newpage
+
+%The next two diagrams are further tests of the macros for drawing
+%double edges.
+
+$$\ctdiagram{
+\ctv0,0:X
+\ctv-100,100:Y\ctv-100,0:Y\ctv-100,-100:Y
+\ctv100,100:Z\ctv100,0:Z\ctv100,-100:Z
+\ctetb0,0,-100,100:10\alpha\beta
+\ctdash\ctetb0,0,-100,0:00\alpha\beta\ctsolid
+\ctetb0,0,-100,-100:01\alpha\beta
+\ctetb0,0,100,100:10\alpha\beta
+\ctdash\ctetb0,0,100,0:11\alpha\beta\ctsolid
+\ctetb0,0,100,-100:01\alpha\beta
+}$$
+
+$$\ctdiagram{
+\ctv0,0:X
+\ctv-100,100:Y\ctv0,100:Y\ctv100,100:Y
+\ctv-100,-100:Z\ctv0,-100:Z\ctv100,-100:Z
+\ctelr0,0,-100,100:10\alpha\beta
+\ctelr0,0,0,100:00\alpha\beta
+\ctelr0,0,100,100:01\alpha\beta
+\ctelr0,0,-100,-100:10\alpha\beta
+\ctelr0,0,0,-100:11\alpha\beta
+\ctelr0,0,100,-100:01\alpha\beta
+}$$
+
+\newpage
+
+%These two diagrams test the usage of \ctinnermid and \ctoutermid.
+
+$$\ctdiagram{\ctv 0,0:{
+{\displaystyle\sum_{i=0}^{100}x_i\cdot y_i}\over
+{\displaystyle\sqrt{\biggl(\sum_{i=0}^{100}x_i^2\biggr)
++\biggl(\sum_{i=0}^{100}y_i^2\biggr)}}}
+\ctv0,150:A\ctv150,150:B\ctv150,0:C\ctv150,-150:D
+\ctv0,-150:E\ctv-150,-150:F\ctv-150,0:G\ctv-150,150:H
+\cter0,0,0,150:A\ctinnermid\cter0,0,0,150:a\ctoutermid
+\cter150,150,0,0:B\ctinnermid\cter150,150,0,0:b\ctoutermid
+\cteb0,0,150,0:C\ctinnermid\cteb0,0,150,0:c\ctoutermid
+\cteb150,-150,0,0:D\ctinnermid\cteb150,-150,0,0:d\ctoutermid
+\ctel0,0,0,-150:E\ctinnermid\ctel0,0,0,-150:e\ctoutermid
+\ctel-150,-150,0,0:F\ctinnermid\ctel-150,-150,0,0:f\ctoutermid
+\ctet0,0,-150,0:G\ctinnermid\ctet0,0,-150,0:g\ctoutermid
+\ctet-150,150,0,0:H\ctinnermid\ctet-150,150,0,0:h
+}$$
+
+$$\ctdiagram{\ctv 0,0:{
+{\displaystyle\sum_{i=0}^{100}x_i\cdot y_i}\over
+{\displaystyle\sqrt{\biggl(\sum_{i=0}^{100}x_i^2\biggr)
++\biggl(\sum_{i=0}^{100}y_i^2\biggr)}}}
+\ctv-150,150:A\ctv0,150:C\ctv150,150:E\ctv150,0:G
+\ctelr0,0,-150,150:11AB\ctinnermid
+\ctelr0,0,-150,150:11ab\ctoutermid
+\ctelr0,150,0,0:11CD\ctinnermid
+\ctelr0,150,0,0:11cd\ctoutermid
+\ctetb0,0,150,150:11EF\ctinnermid
+\ctetb0,0,150,150:11ef\ctoutermid
+\ctetb150,0,0,0:11GH\ctinnermid
+\ctetb150,0,0,0:11gh
+}$$
+
+\newpage
+
+%This is a ``real'' diagram, relating directed complete relations to
+%Scott's inverse limit construction. It is sufficiently crowded
+%that it has been necessary to place some of the abutted expressions
+%carefully to avoid ambiguity.
+
+$$\ctdiagram{
+\ctvg0,0:{D_0}{\border{2pt}{0pt}}
+\ctv72,0:{D_1}
+\ctv144,0:{D_2}
+\ctv216,0:{\quad\cdots}
+\ctvg288,144:{D_\infty}{\advance\ycenter by 5pt\border{50pt}{10pt}}
+\ctv234,36:{\cdots}
+\ctetbg0,0,72,0;48,48:10{\phi_0}{\psi_0}
+\ctetbg72,0,144,0;114,114:10{\phi_1}{\psi_1}
+\ctetb144,0,216,0:10{\phi_2}{\psi_2}
+\ctelrg0,0,288,144;42,30:10{\Phi_0}{\Psi_0}
+\ctelrg72,0,288,144;42,30:10{\Phi_1}{\Psi_1}
+\ctelrg144,0,288,144;42,30:10{\Phi_2}{\Psi_2}
+\ctvg0,-72:{D'_0}{\border{2pt}{0pt}}
+\ctv72,-72:{D'_1}
+\ctv144,-72:{D'_2}
+\ctv216,-72:{\quad\cdots}
+\ctvg288,-216:{D'_\infty}{\advance\ycenter by -5pt\border{50pt}{10pt}}
+\ctv234,-108:{\cdots}
+\ctetbg0,-72,72,-72;48,48:10{\phi'_0}{\psi'_0}
+\ctetbg72,-72,144,-72;114,114:10{\phi'_1}{\psi'_1}
+\ctetb144,-72,216,-72:10{\phi'_2}{\psi'_2}
+\ctelrg0,-72,288,-216;-114,-102:10{\Phi'_0}{\Psi'_0}
+\ctelrg72,-72,288,-216;-114,-102:10{\Phi'_1}{\Psi'_1}
+\ctelrg144,-72,288,-216;-114,-102:10{\Phi'_2}{\Psi'_2}
+\cter0,0,0,-72:{\alpha_0}
+\cter72,0,72,-72:{\alpha_1}
+\cter144,0,144,-72:{\alpha_2}
+\ctv216,-36:{\cdots}
+\ctdash
+\cter288,144,288,-216:{\alpha_\infty}
+}$$
+
+\newpage
+
+%This shows how a macro can be defined and then used to give two different
+%views of the same diagram.
+
+\def\testcube#1#2#3#4#5#6#7#8{
+$$\ctdiagram{
+\ctv#1,#3:{A_1}
+\ctv#2,#3:{B_1}
+\ctv#1,#4:{A_2}
+\ctv#2,#4:{B_2}
+\ctv#5,#7:{A'_1}
+\ctv#6,#7:{B'_1}
+\ctv#5,#8:{A'_2}
+\ctv#6,#8:{B'_2}
+\ctet#1,#3,#2,#3:{\gamma_1}
+\ctet#1,#4,#2,#4:{\gamma_2}
+\cter#1,#3,#1,#4:{\alpha}
+\cter#2,#3,#2,#4:{\beta}
+\ctet#5,#7,#6,#7:{\gamma'_1}
+\ctet#5,#8,#6,#8:{\gamma'_2}
+\cter#5,#7,#5,#8:{\alpha'}
+\cter#6,#7,#6,#8:{\beta'}
+\cter#1,#3,#5,#7:{a_1}
+\cter#2,#3,#6,#7:{b_1}
+\cter#1,#4,#5,#8:{a_2}
+\cter#2,#4,#6,#8:{b_2}
+}$$}
+
+\testcube{0}{200}{200}{0}{50}{150}{150}{50}
+
+\testcube{0}{150}{150}{0}{100}{250}{200}{50}
+
+\newpage
+
+%An example of a partial ordering with a limit point.
+
+$${\def\diagramunit{0.25in}
+\ctdiagram{\ctnohead
+\ctv0,0:{\geq 0}
+\ctv2,2:{\geq 1}
+\ctv4,4:{\geq 2}
+\ctv7,7:\infty
+\ctv-2,2:{=0}
+\ctv0,4:{=1}
+\ctv2,6:{=2}
+\cten0,0,2,2:
+\cten2,2,4,4:
+\cten0,0,-2,2:
+\cten2,2,0,4:
+\cten4,4,2,6:
+\ctdot
+\cten4,4,7,7:
+}}$$
+
+%An example of a binary tree, produced by user macros.
+
+\newcount\cnx\newcount\cny\newcount\cnxx\newcount\cnyy
+
+\def\treea#1{\cnxx=\cnx\cnyy=\cny
+\ctv\cnx,\cny:{\scriptstyle #1}
+\advance\cnx by -1\advance\cny by 4
+\ctdot
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by 2
+\cten\cnxx,\cnyy,\cnx,\cny:
+\ctsolid
+\cnx=\cnxx\cny=\cnyy}
+
+\def\treeb#1{\ctv\cnx,\cny:{\scriptstyle #1}
+\advance\cnx by -2\advance\cny by 4
+\treea{#10}
+\cnxx=\cnx\advance\cnxx by 2\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by 4
+\treea{#11}
+\cnxx=\cnx\advance\cnxx by -2\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by -2\advance\cny by -4}
+
+\def\treec#1{\ctv\cnx,\cny:{\scriptstyle #1}
+\advance\cnx by -4\advance\cny by 4
+\treeb{#10}
+\cnxx=\cnx\advance\cnxx by 4\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by 8
+\treeb{#11}
+\cnxx=\cnx\advance\cnxx by -4\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by -4\advance\cny by -4}
+
+\def\treed#1{\ctv\cnx,\cny:{\scriptstyle #1}
+\advance\cnx by -8\advance\cny by 4
+\treec{#10}
+\cnxx=\cnx\advance\cnxx by 8\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by 16
+\treec{#11}
+\cnxx=\cnx\advance\cnxx by -8\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by -8\advance\cny by -4}
+
+\def\tree{\ctv\cnx,\cny:\bot\def\centerheight{2pt}
+\advance\cnx by -16\advance\cny by 4
+\treed{0}
+\cnxx=\cnx\advance\cnxx by 16\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by 32
+\treed{1}
+\cnxx=\cnx\advance\cnxx by -16\cnyy=\cny\advance\cnyy by -4
+\cten\cnxx,\cnyy,\cnx,\cny:
+\advance\cnx by -16\advance\cny by -4}
+
+$${\def\diagramunit{7.5pt}
+\ctdiagram{\ctnohead\cnx=0\cny=0\tree}}$$
+
+\end{document}