summaryrefslogtreecommitdiff
path: root/support/graphbase
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 /support/graphbase
Initial commit
Diffstat (limited to 'support/graphbase')
-rw-r--r--support/graphbase/Makefile113
-rw-r--r--support/graphbase/README90
-rw-r--r--support/graphbase/abstract.pdfbin0 -> 57807 bytes
-rw-r--r--support/graphbase/abstract.plaintex260
-rw-r--r--support/graphbase/anna.dat383
-rw-r--r--support/graphbase/assign_mona.w692
-rw-r--r--support/graphbase/boilerplate.w38
-rw-r--r--support/graphbase/book_components.w486
-rw-r--r--support/graphbase/cities.texmap160
-rw-r--r--support/graphbase/david.dat157
-rw-r--r--support/graphbase/econ.dat891
-rw-r--r--support/graphbase/econ_order.w289
-rw-r--r--support/graphbase/football.w620
-rw-r--r--support/graphbase/games.dat792
-rw-r--r--support/graphbase/gb_basic.w2415
-rw-r--r--support/graphbase/gb_books.w542
-rw-r--r--support/graphbase/gb_dijk.w445
-rw-r--r--support/graphbase/gb_econ.w635
-rw-r--r--support/graphbase/gb_flip.w254
-rw-r--r--support/graphbase/gb_games.w477
-rw-r--r--support/graphbase/gb_gates.w1924
-rw-r--r--support/graphbase/gb_graph.w887
-rw-r--r--support/graphbase/gb_io.w574
-rw-r--r--support/graphbase/gb_miles.w404
-rw-r--r--support/graphbase/gb_mona.w633
-rw-r--r--support/graphbase/gb_plane.w986
-rw-r--r--support/graphbase/gb_raman.w715
-rw-r--r--support/graphbase/gb_rand.w575
-rw-r--r--support/graphbase/gb_roget.w224
-rw-r--r--support/graphbase/gb_save.w872
-rw-r--r--support/graphbase/gb_sort.w177
-rw-r--r--support/graphbase/gb_words.w561
-rw-r--r--support/graphbase/girth.w308
-rw-r--r--support/graphbase/homer.dat675
-rw-r--r--support/graphbase/huck.dat123
-rw-r--r--support/graphbase/jean.dat442
-rw-r--r--support/graphbase/ladders.w405
-rw-r--r--support/graphbase/miles.dat701
-rw-r--r--support/graphbase/miles_span.w1659
-rw-r--r--support/graphbase/mona.dat3605
-rw-r--r--support/graphbase/multiply.w314
-rw-r--r--support/graphbase/queen.w51
-rw-r--r--support/graphbase/queen_wrap.ch91
-rw-r--r--support/graphbase/roget.dat1038
-rw-r--r--support/graphbase/roget_components.w391
-rw-r--r--support/graphbase/sample.correct109
-rw-r--r--support/graphbase/take_risc.w173
-rw-r--r--support/graphbase/test.correct115
-rw-r--r--support/graphbase/test.dat8
-rw-r--r--support/graphbase/test_sample.w268
-rw-r--r--support/graphbase/word_components.w126
-rw-r--r--support/graphbase/words.dat5683
52 files changed, 34556 insertions, 0 deletions
diff --git a/support/graphbase/Makefile b/support/graphbase/Makefile
new file mode 100644
index 0000000000..3281487ff4
--- /dev/null
+++ b/support/graphbase/Makefile
@@ -0,0 +1,113 @@
+#
+# Makefile for the Stanford GraphBase
+#
+
+# Change DATADIR to the directory where the data files will go (425K bytes)
+DATADIR = /usr/local/lib
+
+# Uncomment the next line if your C uses <string.h> but not <strings.h>
+# SYS = -DSYSV
+
+# If you prefer optimization to debugging, change CFLAGS to something like -O
+CFLAGS = -g
+
+# Change MLIB, if necessary, to the code that loads the C math library
+MLIB = -lm
+
+install:
+ - mkdir $(DATADIR)
+ install -c -m 444 *.dat $(DATADIR)
+
+%.c: %.w
+ ctangle $*
+
+%.o: %.c
+ cc $(CFLAGS) -c $*.c
+
+IFGS = gb_io.o gb_flip.o gb_graph.o gb_sort.o
+IFG = gb_io.o gb_flip.o gb_graph.o
+IG = gb_io.o gb_graph.o
+FG = gb_flip.o gb_graph.o
+
+assign_mona: assign_mona.c $(IG) gb_mona.o
+ cc $(CFLAGS) assign_mona.c $(IG) gb_mona.o -o assign_mona
+
+book_components: book_components.c $(IFGS) gb_books.o
+ cc $(CFLAGS) book_components.c $(IFGS) gb_books.o -o book_components
+
+econ_order: econ_order.c $(IFG) gb_econ.o
+ cc $(CFLAGS) econ_order.c $(IFG) gb_econ.o -o econ_order
+
+football: football.c $(IFGS) gb_games.o
+ cc $(CFLAGS) football.c $(IFGS) gb_games.o -o football
+
+gb_graph.o: gb_graph.c
+ cc $(CFLAGS) $(SYS) -c $*.c
+
+gb_io.o: gb_io.c
+ echo "#define DATA_DIRECTORY \"$(DATADIR)/\"" >localdefs.h
+ cc $(CFLAGS) $(SYS) -c $*.c
+ rm localdefs.h
+
+gb_plane.o: gb_miles.o
+
+girth: girth.c $(FG) gb_raman.o
+ cc $(CFLAGS) girth.c $(FG) gb_raman.o -o girth $(MLIB)
+
+miles_span: miles_span.c $(IFGS) gb_miles.o
+ cc $(CFLAGS) miles_span.c $(IFGS) gb_miles.o -o miles_span
+
+multiply: multiply.c $(FG) gb_gates.o
+ cc $(CFLAGS) multiply.c $(FG) gb_gates.o -o multiply
+
+queen: queen.c $(IG) gb_basic.o gb_save.o
+ cc $(CFLAGS) queen.c $(IG) gb_basic.o gb_save.o -o queen
+
+queen_wrap.c: queen.w queen_wrap.ch
+ ctangle queen_wrap.w queen_wrap.ch queen_wrap.c
+
+queen_wrap: queen_wrap.c $(IG) gb_basic.o gb_save.o
+ cc $(CFLAGS) queen_wrap.c $(IG) gb_basic.o gb_save.o -o queen_wrap
+
+roget_components: roget_components.c $(IFG) gb_roget.o
+ cc $(CFLAGS) roget_components.c $(IFG) gb_roget.o -o roget_components
+
+take_risc: take_risc.c $(FG) gb_gates.o
+ cc $(CFLAGS) take_risc.c $(FG) gb_gates.o -o take_risc
+
+word_components: word_components.c $(IFGS) gb_words.o
+ cc $(CFLAGS) word_components.c $(IFGS) gb_words.o -o word_components
+
+ladders: ladders.c $(IFGS) gb_words.o gb_dijk.o
+ cc $(CFLAGS) ladders.c $(IFGS) gb_words.o gb_dijk.o -o ladders
+
+test_io: gb_io.o
+ cc $(CFLAGS) test_io.c gb_io.o -o test_io
+
+test_graph: gb_graph.o
+ cc $(CFLAGS) test_graph.c gb_graph.o -o test_graph
+
+test_flip: gb_flip.o
+ cc $(CFLAGS) test_flip.c gb_flip.o -o test_flip
+
+test_sample: test_sample.c $(IFGS) gb_basic.o gb_books.o gb_econ.o \
+ gb_games.o gb_gates.o gb_miles.o gb_mona.o gb_plane.o gb_raman.o \
+ gb_rand.o gb_roget.o gb_save.o gb_words.o
+ cc $(CFLAGS) test_sample.c $(IFGS) gb_basic.o gb_books.o gb_econ.o \
+ gb_games.o gb_gates.o gb_miles.o gb_mona.o gb_plane.o gb_raman.o \
+ gb_rand.o gb_roget.o gb_save.o gb_words.o -o test_sample
+
+test_all: test_io test_graph test_flip test_sample
+ test_io
+ test_graph
+ test_flip
+ test_sample > sample.out
+ diff test.gb test.correct
+ diff sample.out sample.correct
+ rm test.gb sample.out test_io test_graph test_flip test_sample
+
+veryclean:
+ rm -f *.o *.c *.h \
+ assign_mona book_components econ_order football \
+ girth ladders miles_span multiply roget_components \
+ take_risc word_components
diff --git a/support/graphbase/README b/support/graphbase/README
new file mode 100644
index 0000000000..0f3ee5cf30
--- /dev/null
+++ b/support/graphbase/README
@@ -0,0 +1,90 @@
+The Stanford GraphBase is copyright 1992 by Stanford University
+
+These files may be freely copied and distributed, provided that
+no changes whatsoever are made. All users are asked to help keep
+the Stanford GraphBase sources consistent and ``uncorrupted,''
+identical everywhere in the world. Changes are permissible only
+if the changed file is given a new name, different from the names of
+existing files listed below, and only if the changed file is
+clearly identified as not being part of the Stanford GraphBase.
+The author has tried his best to produce correct and useful programs,
+in order to help promote computer science research, but no warranty
+of any kind should be assumed.
+
+FILES INCLUDED IN STANDARD GRAPHBASE DISTRIBUTION
+
+The standard Stanford GraphBase consists of the following files:
+
+1) Data files
+ anna.dat Anna Karenina (used by gb_books)
+ david.dat David Copperfield (used by gb_books)
+ econ.dat US economic input and output (used by gb_econ)
+ games.dat College football scores, 1990 (used by gb_games)
+ homer.dat The Iliad (used by gb_books)
+ huck.dat Huckleberry Finn (used by gb_books)
+ jean.dat Les Miserables (used by gb_books)
+ miles.dat Mileage between North American cities (used by gb_miles)
+ mona.dat Mona Lisa pixels (used by gb_mona)
+ roget.dat Cross references in Roget's Thesaurus (used by gb_roget)
+ words.dat Five-letter words of English (used by (gb_words)
+2) CWEB program files
+ a) Kernel routines
+ gb_flip.w System-independent random number generator
+ gb_graph.w Data structures for graphs
+ gb_io.w Input/output routines
+ gb_sort.w Sorting routine for linked lists
+ b) Graph generating routines
+ gb_basic.w Standard building blocks and graph operations
+ gb_books.w Graphs based on world literature
+ gb_econ.w Graphs based on US inter-industry flow
+ gb_games.w Graphs based on college football games
+ gb_gates.w Graphs based on combinational logic
+ gb_miles.w Graphs based on highway distances
+ gb_mona.w Graphs based on Leonardo's Mona Lisa
+ gb_plane.w Planar graphs
+ gb_raman.w Ramanujan graphs (expanders)
+ gb_rand.w Random graphs
+ gb_roget.w Graphs based on Roget's Thesaurus
+ gb_words.w Graphs based on 5-letter words of English
+ c) Demonstration routines
+ assign_mona.w The assignment problem, using Mona Lisa
+ book_components.w Biconnected components, using the plots of books
+ econ_order.w Heuristic solution to an optimum permutation problem
+ football.w Heuristic solution to a longest-path problem
+ girth.w Empirical study of Ramanujan graphs
+ ladders.w Shortest paths in word graphs
+ miles_span.w Comparison of algorithms for minimum spanning tree
+ multiply.w Using a parallel multiplication circuit
+ queen.w Graphs based on queen moves
+ roget_components.w Strong components of a directed graph
+ take_risc.w Using a simple RISC computer circuit
+ word_components.w Connected components of word graphs
+ d) Miscellaneous routines
+ boilerplate.w Legalese incorporated into all GraphBase programs
+ gb_dijk.w Variants of Dijkstra's algorithm for shortest paths
+ gb_save.w Converting graphs to ASCII files and vice versa
+ test_sample.w Test routine for GraphBase installation
+3) Miscellaneous files
+ Makefile Instructions to build everything with UNIX
+ README What you're now reading
+ abstract.plaintex Short explanation of what it's all about
+ cities.texmap TeXable map of the 128 cities in miles.dat
+ queen_wrap.ch Demonstration changefile
+ sample.correct Correct primary output of test_sample
+ test.correct Correct secondary output of test_sample
+ test.dat Weird data used to test gb_io
+
+TO INSTALL THESE PROGRAMS
+
+First install CWEB (version 2.4 or greater), which can be found in
+various archives; the master files reside at labrea.stanford.edu.
+Then, on a UNIX-like system, edit the Makefile as instructed there,
+and "make install".
+
+Complete instructions will appear in a book by D. E. Knuth entitled
+ The Stanford GraphBase: A Platform for Combinatorial Algorithms.
+
+Note: The system is presently in alpha-test state, meaning that everything
+appears to work on at least one system; but experience on a broad range
+of computers is lacking. Please communicate all suggested improvements to
+winkler@sunburn.stanford.edu, with subject line "GraphBase Alpha Test".
diff --git a/support/graphbase/abstract.pdf b/support/graphbase/abstract.pdf
new file mode 100644
index 0000000000..a532f0555e
--- /dev/null
+++ b/support/graphbase/abstract.pdf
Binary files differ
diff --git a/support/graphbase/abstract.plaintex b/support/graphbase/abstract.plaintex
new file mode 100644
index 0000000000..8fb5ba36d8
--- /dev/null
+++ b/support/graphbase/abstract.plaintex
@@ -0,0 +1,260 @@
+% EXTENDED ABSTRACT DESCRIBING THE STANFORD GRAPHBASE --- PRELIMINARY DRAFT
+\magnification\magstep1
+\baselineskip12pt
+\parskip3pt
+\font\sc=cmcsc10 %use lower case as (Monthly)
+
+\def\happyface % new experimental version (DEK, November 88)
+{{\ooalign{\hfil\lower.06ex % a smiley face
+ \hbox{$\scriptscriptstyle\smile$}\hfil\crcr
+ \hfil\lower.7ex\hbox{\"{}}\hfil\crcr
+ \mathhexbox20D}}}
+\def\display#1:#2:#3\par{\par\hangindent #1 \noindent
+ \hbox to #1{\hfill #2 \hskip .1em}\ignorespaces#3\par}
+\def\disleft#1:#2:#3\par{\par\hangindent#1\noindent
+ \hbox to #1{#2 \hfill \hskip .1em}\ignorespaces#3\par}
+\def\TeX{T\hbox{\hskip-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}
+\def\biba{\par\parindent 40pt\hangindent 60pt}
+
+\centerline{\bf The Stanford GraphBase: A Platform for Combinatorial
+Algorithms}
+
+\bigskip
+A highly portable collection of programs and data will soon be
+available to researchers who study combinatorial algorithms and data
+structures. All files will be in the public domain, and usable with
+only one restriction: They must not be changed! A~``change file''
+mechanism will allow local customization while the master files stay
+intact.
+
+The programs are intended to be interesting in themselves as examples
+of ``literate programming.'' Thus, the Stanford GraphBase can also be
+regarded as a collection of approximately 30 essays for programmers to enjoy
+reading, whether or not they are doing algorithmic research. The
+programs are written in {\tt CWEB}, a~combination of \TeX\ and~C that
+is easy to use by anyone who knows those languages and easy to read by
+anyone familiar with the rudiments of~C. (The {\tt CWEB} system is
+itself portable and in the public domain.)
+
+Four program modules constitute the {\it kernel\/} of the GraphBase:
+
+{
+
+\biba
+{\sc gb\_$\,$flip} is a portable random number generator;
+
+\biba
+{\sc gb\_$\,$graph} defines standard data structures for graphs and
+includes routines for storage allocation;
+
+\biba
+{\sc gb\_$\,$io} reads data files and makes sure they are uncorrupted;
+
+\biba
+{\sc gb\_$\,$sort} is a portable sorting routine for 32-bit keys
+in linked lists of nodes.
+
+}
+
+\noindent
+All of the other programs rely on {\sc gb\_$\,$graph} and some subset
+of the other three parts of the kernel.
+
+A dozen or so {\it generator modules\/} construct graphs that are of
+special interest in algorithmic studies. For example {\tt
+gb\_$\,$basic} contains 12~subroutines to produce standard graphs,
+such as the graphs of queen moves on $d$-dimensional rectangular
+boards with ``wrap-around'' on selected coordinates. Another generator
+module, {\sc gb\_$\,$rand}, produces several varieties of
+random graphs.
+
+Each graph has a unique identifier that allows researchers all over
+the world to work with exactly the same graphs, even when those graphs
+are ``random.'' Repeatable experiments and standard benchmarks will
+therefore be possible and widely available.
+
+Most of the generator modules make use of {\it data sets}, which the
+author has been collecting for 20~years in an attempt to provide
+interesting and instructive examples for some forthcoming books on
+combinatorial algorithms ({\sl The Art of Computer Programming},
+Volumes 4A, 4B, and~4C). For example, one of the data sets is {\tt
+words.dat}, a~collection of 5-letter words of English that the author
+believes is ``complete'' from his own reading experience. Each word is
+accompanied by frequency counts in various standard corpuses of text,
+so that the most common terms can be singled out if desired. {\sc
+gb\_$\,$words} makes a subset of words into a graph by saying that two
+words are adjacent when they agree in~4 out of~5 positions. Thus, we
+can get from {\tt words} to {\tt graph} in seven steps:
+
+\disleft 30pt::
+{\tt words, wolds, golds, goads, grads, grade, grape, graph.}
+
+\noindent
+This is in fact the shortest such chain obtainable from {\tt
+words.dat}.
+
+A dozen or so {\it demonstration modules\/} are also provided, as
+illustrations of how the generated graphs can be used. For example,
+the {\tt LADDERS} module is an interactive program to construct chains
+of 5-letter words like the one just exhibited, using arbitrary subsets
+of the data. If we insist on restricting our choices to the 2000 most
+common words, instead of using the entire collection of about 5700, the
+shortest path from {\tt words} to {\tt graph} turns out to have
+length~20:
+
+\disleft 30pt::
+{\tt words, lords, loads, leads, leaps, leapt, least,}
+\vskip-5pt
+\disleft 30pt::
+{\tt lease, cease, chase, chose, chore, shore, shone,}
+\vskip-5pt
+\disleft 30pt::
+{\tt phone, prone, prove, grove, grave,
+grape, graph.}
+
+Several variations on this theme have also been implemented: If we consider
+the distance between adjacent words to be alphabetic distance, for
+example, the shortest path from {\tt words} to {\tt graph} turns out
+to be
+
+\disleft 30pt::
+{\tt words} (3) {\tt woods} (16) {\tt goods} (14) {\tt goads} (3)
+{\tt grads} (14) {\tt grape} (3) {\tt graph},
+
+\noindent
+total length 65.
+
+The {\tt LADDERS} module makes use of another GraphBase module called
+{\sc gb\_$\,$dijk}, which carries out Dijkstra's algorithm for
+shortest paths and allows the user to plug in arbitrary
+implementations of priority queues so that the performance of
+different queuing methods can be compared.
+
+The graphs produced by {\sc gb\_$\,$words} are undirected. Other
+generator modules, like {\sc gb\_$\,$roget}, produce directed graphs.
+Roget's {\sl Thesaurus\/} of 1882 classified all concepts into 1022
+categories, which we can call the vertices of a graph; an arc goes
+from~$u$ to~$v$ when category~$u$ contains a cross reference to
+category~$v$ in Roget's book. A~demonstration module called {\sc
+roget\_$\,$components} determines the strong components of graphs
+generated by {\sc gb\_$\,$roget}. This program is an exposition of
+Tarjan's algorithm for strong components and topological sorting of
+directed graphs.
+
+Similarly,
+world literature leads to further interesting families of undirected
+graphs via
+the {\sc gb\_$\,$books} module. Five data sets {\tt anna.dat}, {\tt
+david.dat}, {\tt homer.dat}, {\tt huck.dat}, and {\tt jean.dat} give
+information about {\sl Anna Karenina}, {\sl David Copperfield}, {\sl
+The Iliad}, {\sl Huckleberry Finn}, and {\sl Les Mis\'erables\/}; as
+you might expect, the characters of each work become the vertices of a
+graph. Two vertices are adjacent if the corresponding characters
+encounter each other, in selected chapters of the book.
+A~demonstration program called
+{\sc book\_$\,$components} finds the blocks (i.e., biconnected
+components) of these graphs using the elegant algorithm of Hopcroft
+and Tarjan.
+
+Another module, {\sc gb\_$\,$games}, generates graphs based on college
+football scores. All the games from the 1990 season
+ between America's leading 120
+teams are recorded in {\tt games.dat}; this data leads to ``cliquey''
+graphs, because most of the teams belong to leagues and they play
+every other team in their league. The overall graph is, however,
+connected. A~demonstration module called {\sc football} finds long
+chains of scores, to prove for instance that Stanford might have trounced
+Harvard by more than 2000 points if the two teams had met---because
+Stanford beat Notre Dame by~5, and Notre Dame beat Air Force by~30,
+and Air Force beat Hawaii by~24, and \dots~, and Yale beat Harvard
+by~15. (Conversely, a~similar ``proof'' also ranks Harvard over
+Stanford by more than 2000 points.) No good algorithm is known for
+finding the optimum solution to problems like this, so the data
+provides an opportunity for researchers to exhibit better and better
+solutions with better and better techniques as algorithmic
+progress is made.
+
+The {\sc gb\_$\,$econ} module generates directed graphs based on the
+flow of money between industries in the US economy. A~variety of
+graphs can be obtained, as the economy can be divided into any number of
+sectors from~2 to~80 in this model.
+ A~demonstration program {\sc econ\_$\,$order}
+attempts to rank the sectors in order from ``suppliers'' to
+``consumers,'' namely to permute rows and columns of a matrix so as to
+minimize the sum of entries above the diagonal. Again, no good
+algorithms for this problem are known; two heuristics are implemented
+for comparison, one ``greedy'' and the other ``cautious.'' Greed
+appears to be victorious, at least in the economic sphere.
+
+The highway mileage between 128 North American cities appears in {\tt
+miles.dat}, and the {\sc gb\_$\,$miles} module generates a variety of
+graphs from~it. Of special interest is a demonstration module called
+{\sc miles\_$\,$span}, which computes the minimum spanning trees of
+graphs output by {\sc gb\_$\,$miles}. Four algorithms for minimum
+spanning trees are implemented and compared, including some that are
+theoretically appealing but do not seem to fare so well in practice.
+An approach to comparison of algorithms called ``mem counting'' is
+shown in this demonstration to be an easily implemented
+machine-independent measure of efficiency that gives a reasonably fair
+comparison between competing techniques.
+
+A generator module called {\sc gb\_$\,$raman} produces ``Ramanujan
+graphs,'' which are important because of their role as expander
+graphs, useful for communication. A~demonstration module called {\sc
+girth} computes the shortest circuit and the diameter of Ramanujan
+graphs.
+Notice that some graphs, like those produced by {\sc gb\_$\,$basic} or
+{\sc gb\_$\,$raman}, have a rigid mathematical structure; others, like
+those produced by {\sc gb\_$\,$roget} or {\sc gb\_$\,$miles}, are more
+``organic'' in nature. It is interesting and important to test
+algorithms on both kinds of graphs, in order to see if there is any
+significant difference in performance.
+
+A generator module called {\sc gb\_$\,$gates} produces graphs of logic
+circuits. One family of graphs is equivalent to a simple {\sc risc}
+chip, a~programmable microcomputer with a variable number of registers
+and a variable number of bits per word. Using such a ``meta-network''
+of gates, algorithms for design automation can be tested for a range
+of varying parameters. A~demonstration module {\sc take\_$\,$risc}
+simulates the execution of the chip on a sample program. Another
+meta-network of gates will perform parallel multiplication of $m$-bit
+numbers by $n$-bit numbers or by an $n$-bit constant; the {\sc
+multiply} module demonstrates this network.
+
+Planar graphs are generated by {\sc gb\_$\,$plane}, which includes
+among other things an implementation of the best currently known
+algorithm for Delaunay triangulation.
+
+Pixel data can lead to interesting bipartite graphs. Leonardo's {\sl
+Giaconda\/} is represented by {\tt mona.dat}, an array of pixels that
+is converted into graphs of different kinds by {\sc gb\_$\,$mona}.
+A~demonstration routine {\sc assign\_$\,$mona} solves the assignment
+problem by choosing one pixel in each row and in each column so that
+the total brightness of selected pixels is maximized. Although the
+assignment problem being solved here has no relevance whatever to art
+criticism or art appreciation, it does have great pedagogical value,
+because there is probably no better way to understand the
+characteristics of a large array of numbers than to perceive the array
+as an image.
+
+This lecture might well have been called ``Fun and games with the
+Stanford GraphBase,'' because the demonstration programs are great
+toys to play with. Indeed, the author firmly believes that the best
+serious work is also good fun, and we shouldn't apologize if we enjoy
+doing research.
+
+The Stanford GraphBase is now being beta-tested, and it should be
+released in 1993. A~book about it, containing in particular all the
+programs together with indexes and typographic aids to the reader,
+will also be published in 1993. A~module called {\sc gb\_$\,$save}
+converts GraphBase graphs to and from an ASCII format that
+readily interfaces with other systems for graph manipulation.
+
+
+\bigskip
+\rightline{\sl ---\vtop{\hbox{Donald E. Knuth}
+\hbox{Stanford University}
+\hbox{March 31, 1992}}}
+
+\bye
+
diff --git a/support/graphbase/anna.dat b/support/graphbase/anna.dat
new file mode 100644
index 0000000000..04387d1ed0
--- /dev/null
+++ b/support/graphbase/anna.dat
@@ -0,0 +1,383 @@
+* File "anna.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* Anna Karenina, by Leo Nikolaevitch Tolstoy
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 378,911441608)
+AA Annushka, maid of AN
+AG Agafea Mihalovna, housekeeper of LE
+AL Alexey Alexandrovitch Karenin, minister of state
+AN Anna Arkadyevna Karenina, wife of AL
+AO Aliosha, son of DO and ST
+AP Anna Pavlovna, wife of PV
+BA Annie, baby of AN and VR
+BD Dmitri (Mitya), baby of LE and KI
+BE Madame Berthe, blind woman
+BL Count Bol, friend of KI in Moscow
+BN Bartnyansky, rich man in Petersburg
+BO Countess Bola, wife of BL
+BT Princess Betsy Tverskaya, cousin of VR
+CA Count Anitchkin, supervisor of ST
+CB Countess Bonina, dance partner of YK
+CD Colonel Demin, colleague of VR
+CN Countess Nordston, friend of KI
+CO Cord, English horse trainer
+CV Countess Vronskaya, mother of VR
+DO Princess Darya Alexandrovna Oblonskaya (Dolly), wife of ST
+ED Miss Edwards, English governor of SE
+EF Marya Efimovna, nurse of AL
+FC Fyodor 1, coachman of AA
+FR Fyodor Ryezunov, carpenter
+FY Fyodor 2, peasant
+GA Gagin, officer from Petersburg
+GO Golenishtchev, friend of VR
+GR Grisha, young son of ST and DO
+GV Grinevitch (Mihail Stanislavitch), board member
+HA Hannah, pupil of AN
+HO Miss Hoole, English governess to DO's children
+IG Ignat, coachman of LE
+IV Ivan 1, cowherd
+IW Ivan 2, coachmen of LE
+JL Jules Landau (Count Bezzubov), psychic
+KA Captain Kamerovsky, cavalry officer
+KE Prince Kedrov, member of VR's regiment
+KI Princess Ekaterina Alexandrovna Shtcherbatskaya (Kitty), wife of LE
+KO Sergei Ivanovitch Koznishev, half-brother of LE
+KP Kapitonitch, hall porter of AL
+KR Kritsky, friend of NI
+KT Professor Katavasov, natural scientist
+KU Prince Kuzovlev, fearful horseman
+KV Krivin, bald socialite
+KY Korney, valet of AL
+KZ Kouzma, elderly servant of LE
+LE Konstantin Dmitrievitch Levin, proprietor of Pokrovskoe
+LI Countess Lidia Ivanovna, Petersburg dogooder
+LK Lidi Korsunskaya, wife of YK
+LL Lily, youngest child of DO and ST
+LM Liza Merkalova, thin brunette admired by SM
+LP Lizaveta Petrovna, midwife
+LV Arseny Lvov, husband of NA
+MA Matvey, valet of ST
+MB Princess Marya Borissovna, KI's godmother
+MC Mihail, coachman
+MD Marya Dmitrievna, aunt of KI
+ME Mariette, governess of SE
+MH Mahotin, rival horseman to VR
+MI Mihailov, painter
+MJ Mihailitch, beekeeper
+MK Mishka, peasant lad
+ML Mademoiselle Linon, French governess of KI
+MM Masha 3, little daughter of ST and DO
+MN Marya Nikolaevna, companion of NI
+MO Metrov, Petersburg social scientist
+MP Mihael Petrovitch, landowner
+MQ Masha 2, maid of KI
+MR Mademoiselle Roland, French governess
+MS Madame Stahl, invalid philanthropist
+MT Masha Tchibisova, dancer
+MV Marya Vlasyevna, midwife
+MX Masha 1, young relative of BT
+MY Princess Myakaya, enfant terrible
+MZ Madame Sviazhskaya, wife of SV
+NA Princess Natalia Lvova, sister of DO and KI
+ND Nadinka, niece of LI
+NI Nikolay Levin, brother of LE
+NL Nikolinka, son of DO and ST
+NN Nikitin (Philip Ivanovitch), board member
+NS Nikolay Shtcherbatsky, cousin of KI
+NT Nastia, sister of MV
+NV Madame Nikolaevna, KI's maid of honor
+NY Nevyedovsky, malignant gentleman
+PA Parmenitch, old beekeeper
+PC Prince Tchetchensky, man with two families
+PD Pyotr Dmitrievitch, doctor
+PE Pestsov, eccentric enthusiast
+PH Matrona Marya Philimonovna, nurse
+PK Prince Kaluzhsky, Petersburg party guest
+PO Princess Oblonskaya, unmarried aunt of AN
+PP Prince Pyotr Oblonsky, man of sixty
+PR Prince Alexander Shtcherbatsky, father of DO and KI
+PS Princess Shtcherbatskaya, mother of DO and KI
+PT Lieutenant Petritsky, friend of VR
+PV Mihail Alexeyevitch Petrov, painter
+PX Pyotr, servant of AN
+PY Prohor Yermilin, mower
+RT Marya Yevgenyevna Rtishtcheva, lady of Moscow
+RY Mihail Ignatitch Ryabinin, merchant
+SA Sasha, wife of MI
+SE Sergey Alexeyevitch Karenin (Seryozha), son of AL and AN
+SH Baroness Shilton, friend of PT
+SI Vassily Lukitch Sitnikov, tutor of SE
+SL Mihail Vassilievitch Sludin, secretary of AL's department
+SM Stremov, opponent of AL
+SN Stepan Vassilievitch, landowner
+SO Princess Sorokina, young friend of CV
+SP General Serpuhovskoy, rival of VR
+SQ Snetkow, marshal of Kashinsky province
+SS Sappho Shtolz, blonde beauty
+ST Prince Stepan Arkadyevitch Oblonsky (Stiva), brother of AN
+SU Shuraev, peasant
+SV Nikolay Ivanovitch Sviazhsky, landowner
+SY Semyon, contractor to LE
+TA Tanya, oldest daughter of ST and DO
+TB Madame Trubetskaya, wedding guest
+TC Tchirikov, best man of LE
+TT Tit, mower
+TU Tushkevitch, croquet player
+TV Turovtsin, party guest
+VA Varya, wife of XV
+VE Venden, mustachioed clerk
+VF Vassily Fedorovitch, bailiff of LE
+VG Volgarinoff, Jew
+VI Pyotr Ilyitch Vinovsky, club friend of ST
+VK Varvara Andreevna (Varenka), adopted daughter of MS
+VO Ivan Petrovich Vorkuev, publisher
+VP Princess Varvara, aunt of ST
+VR Count Alexey Kirillovitch Vronsky, young officer
+VS Vaska, admirer of SS
+VV Vassenka Veslovsky, distant cousin of KI
+VY Voytov, horse purchaser
+XV Alexander Vronsky, brother of VR
+YG Yegor, servant in hotel
+YK Yegorushka Korsunsky, handsome dancer
+YS Young Shtcherbatsky, brother of KI
+YV Captain Yashvin, gambling friend of VR
+
+1.1:ST,DO
+1.2:ST,MR;ST,PH,MA;MA,DO
+1.3:ST,GR,TA;ST,MA
+1.4:DO,ST;ST,MA;DO,PH
+1.5:ST,NN,GV,LE
+1.6:NA,DO,KE,LE;NA,LV
+1.7:KO,LE
+1.8:KO,LE
+1.9:LE,NS,KI;LE,PS,ST,KI;LE,ML,KI
+1.10:LE,ST
+1.11:LE,ST
+1.12:PR,PS;PS,KI,VR
+1.13:LE,KI
+1.14:LE,KI,PS,CN,VR,PR
+1.15:KI,PS,PR
+1.16:VR
+1.17:VR,ST
+1.18:VR,ST,AN,CV
+1.19:AN,DO,GR,TA
+1.20:AN,DO,ST,KI;DO,KI,GR,TA
+1.21:AN,DO,ST,KI;AN,VR
+1.22:KI,PS,YK;CB,YK;LI,KV,ST,AN,VR;KI,YK,AN,VR
+1.23:KI,VR,PS,CN;KI,VR,AN;CN,YK;YK,KI;YK,AN
+1.24:LE,NI,MN,KR
+1.25:LE,NI,MN,KR
+1.26:LE,IG;LE,AG,KZ;LE,VF,SY
+1.27:LE,AG
+1.28:AN,DO,ST
+1.29:AN,ST;AN,AA
+1.30:VR,AN;AN,AL
+1.31:VR,AN,AL
+1.32:SE,AN;LI,AN
+1.33:AL,AN;AN,SE
+1.34:PT,SH,KA,VR
+2.1:KI,PS;PS,PR
+2.2:DO,PS,PR,KI
+2.3:DO,KI
+2.4:BT,AN,VR
+2.5:VR,BT;PT,KE,VE,VR
+2.6:BT,MY,VR
+2.7:BT,MY,VR,AN,AL;AN,LI
+2.8:AL
+2.9:AN,AL
+2.10:AN,AL,BT,VR
+2.11:VR,AN
+2.12:LE,NI;LE,AG
+2.13:LE,VF;LE,IG
+2.14:ST,LE,AG,KZ
+2.15:ST,LE
+2.16:ST,LE,RY
+2.17:ST,LE,AG
+2.18:VR
+2.19:VR,YV
+2.20:VR,PT,YV
+2.21:VR,CO
+2.22:VR,AN
+2.23:VR,AN
+2.24:VR,CO,MH;VR,XV;VR,ST;VR,KU
+2.25:VR,KU,MH;VR,YV
+2.26:AL,LI;AL,SL
+2.27:AN,AA;AN,AL,SL;AN,AL,SE
+2.28:AN,BT,AL;BT,ST
+2.29:AN,BT,AL
+2.30:PR,PS,KI,RT;KI,MS,VK;KI,NI,MN
+2.31:PS,KI,NI;NI,VK,MN;PS,KI,VK
+2.32:MS,VK;VK,PS,KI,RT
+2.33:KI,MS,VK;PS,KI;KI,PV,AP
+2.34:PR,PS,KI;PR,KI,BE;PR,KI,VK,MS;PR,KI,PV,AP
+2.35:PR,KI,RT,VK,PS
+3.1:KO,LE
+3.2:KO,LE,AG
+3.3:KO,LE;LE,VF
+3.4:KO,LE;LE,VF;LE,TT
+3.5:LE,MK,PY
+3.6:LE,KO,KZ
+3.7:ST,DO;DO,PH
+3.8:DO,PH,TA,HO;DO,AO,LL,TA;DO,HO,GR,TA,NL
+3.9:DO,LE,PH,LL
+3.10:DO,LE,TA;DO,TA,GR
+3.11:LE,PA
+3.12:LE,DO
+3.13:AL,AN
+3.14:AL
+3.15:AN,VR;AN,AA;AN,SE,ME
+3.16:AN,AA
+3.17:AN,BT,TU,MX
+3.18:AN,BT,SS,VS,PK,SM,LM;LM,AN,SM,TU
+3.19:VR,PT
+3.20:VR
+3.21:VR,PT,CD,SP,YV
+3.22:VR,AN
+3.23:AL,SM;AL,AN
+3.24:VF,LE
+3.25:LE
+3.26:LE,SV,MZ,NT
+3.27:LE,SV,MP,SN
+3.28:LE,SV
+3.29:LE,VF;LE,IV;LE,FR;LE,SU
+3.30:LE,VF;LE,AG
+3.31:LE,NI,AG
+3.32:LE,NI;LE,NS
+4.1:AL,AN;AN,VR
+4.2:AL,VR;VR,AN
+4.3:VR,AN;AN,LM
+4.4:AL,AN
+4.5:AL
+4.6:AL,SM;BT,MY;AL,ST,DO
+4.7:ST,MT;ST,LE;ST,CA
+4.8:AL,ST
+4.9:ST,KO,PE,PR,YS,TV,KI,AL,DO,LE,MA
+4.10:PE,KO,AL,ST,TV,PR,DO
+4.11:LE,KI,DO,TV
+4.12:PE,ST,AL,KO,TV;AL,DO,YS
+4.13:LE,PE,KO;LE,KI,YS;LE,KI,PR
+4.14:LE,ST;LE,DO;KE,KO,SV;LE,YG
+4.15:ML,LE;LE,KI,PR,PS
+4.16:PS,PR,KI,LE;KI,LE,ML;LE,KO;LE,SV;KI,CN
+4.17:AL,KP;AL,VR,AN;AN,BA
+4.18:VR,KP;VR,VA
+4.19:AL,BA;AL,SE,ED;AL,AN,BT
+4.20:AL,AN
+4.21:BT,ST;ST,AN
+4.22:ST,AL
+4.23:VR,VA;VR,BT;VR,AN
+5.1:PS,LE;LE,KO;LE,ST;LE,KI
+5.2:LE,KO,KT,TC;LE,KI,PS;KE,KO,SO,ST;LE,KZ
+5.3:KI,NA;LE,ST,KZ
+5.4:ST,DO,TC,LE,KI;LE,KI,CN;LE,KI,CA;KI,MD
+5.5:DO,NA;LK,YK;LK,TB;PR,NV;KO,DO;ST,NA;NA,CN;CN,DO
+5.6:LE,KI,PR,TC
+5.7:VR,AN,GO
+5.8:VR,AN
+5.9:VR,AN,GO
+5.10:MI,SA;MI,VR,GO,AN
+5.11:MI,VR,GO,AN
+5.12:MI,VR,GO,AN
+5.13:MI,VR,AN,GO
+5.14:LE,KI,AG,MQ
+5.15:KE,KI,KZ
+5.16:LE,KI,AG
+5.17:NI,LE,KI;LE,MN,KI
+5.18:NI,LE,KI,MN
+5.19:LE,KI
+5.20:NI,LE,KI,MN
+5.21:AL,BT,ST;AL,ED;AL,KY;AL,SL
+5.22:LI,AL,SE;AL,KY
+5.23:LI
+5.24:AL,LI
+5.25:AL,LI
+5.26:SE,KP;SE,SI;SE,ND
+5.27:SE,SI;SE,AL
+5.28:VR,CV,VA;VR,XV,AN;VR,BT,AN
+5.29:AN,KP;AN,SE
+5.30:KY,KP;KY,EF;EF,AN,SE,SI,AL
+5.31:AN,BA;AN,VR,YV
+5.32:AN,PO,VR,TU;AN,YV,VR,TU
+5.33:VR,YV;VR,SP;AN,VV,YV;VA,VR,CV,SO;XV,VR;AN,VR,SM
+6.1:DO,VK,KO,KI;KO,LE,KI,TV,VK;KI,PS
+6.2:AG,PS,KI,DO,LE
+6.3:KI,LE,PS
+6.4:VK,KO
+6.5:VK,GR,MM,KO,KI,LE
+6.6:VK,KO,KI,LE,PS,DO,AG;LE,GR,ST,VV;ST,TA;ST,DO;PS,VV;VV,VK;KO,ST
+6.7:KI,AG;LE,VV,ST,DO,KI;LE,PS,VK
+6.8:VV,ST,LE;LE,KI
+6.9:VV,ST,LE
+6.10:VV,ST,LE
+6.11:VV,ST,LE
+6.12:LE
+6.13:KI,MV;LE,ST,VV
+6.14:LE,VV,ST,KI,PS,MV,DO;HO,TA
+6.15:GR,MM;MM,DO,LE;LE,VV;LE,ST;DO,VK
+6.16:DO,LE
+6.17:VR,VV,AN,VP,SV,DO
+6.18:DO,AN,VV,VR
+6.19:DO,AA,AN;DO,AN,BA
+6.20:DO,AN,VP,VV,VR,SV,TU
+6.21:VR,DO
+6.22:AN,DO,VP,VR,SV,VV,TU
+6.23:AN,DO
+6.24:DO,AN;AN,AL
+6.25:AN,VR
+6.26:LE,KO;LE,KI
+6.27:LE,KO,SV,ST
+6.28:LE,KO;KE,SQ
+6.29:KO,ST,SV,VR;SV,LE,SN
+6.30:SV,LE,VR,ST,KO,NY
+6.31:NY,VR,SV,ST;AN,BA,VP
+6.32:AN,BA;AN,VP,VR
+7.1:LE,KI;KI,PR,MB,VR
+7.2:KE,KI;LE,KZ
+7.3:LE,KT,MO
+7.4:LE,LV,NA
+7.5:LE,NA;PE,LE;LE,BL
+7.6:LE,BO;LE,SV;LE,ST;LE,NA;LE,KI
+7.7:LE,PR;YV,VR,LE,ST,TV,GA,VI
+7.8:LE,ST,VR,GA;LE,PR;VR,YV
+7.9:LE,ST;AN,VO;LE,AN
+7.10:LE,AN,VO,ST,HA
+7.11:LE,ST;LE,KZ;LE,KI
+7.12:AN,VR
+7.13:LE,KI;LE,KZ;LE,LP
+7.14:LE,LP,PS,KI,PD,DO
+7.15:LE,PD,DO,LP,KI,PS,BD
+7.16:PR,KO,ST,LE;LE,KI,PS,BD
+7.17:ST,AL;ST,VG
+7.18:ST,AL
+7.19:ST,AL,SE;ST,AL,KY
+7.20:ST,PC;ST,BN;ST,PP;ST,BT,MY
+7.21:ST,BN;ST,LI,AL,JL
+7.22:ST,PP;ST,LI,AL,JL
+7.23:AN,VR,HA
+7.24:AN,VR
+7.25:AN,VR,AA;AN,VR,YV,VY
+7.26:AN,VR;VR,SO
+7.27:AN,BA;AN,AA;AN,MC;AN,PX
+7.28:AN,DO,KI
+7.29:AN,PX,AA
+7.30:AN,PX,FC
+7.31:AN,PX;AN,MC
+8.1:KO
+8.2:KO,KT,ST;ST,VR,CV
+8.3:KO,KT
+8.4:KO,CV
+8.5:KO,VR
+8.6:KO,KV,KI;KI,DO,PR;KI,AG,BD
+8.7:AG,KI,BD;PR,KT
+8.8:LE
+8.9:LE,KO
+8.10:LE
+8.11:LE,FY
+8.12:LE
+8.13:LE,DO
+8.14:LE,IW;GR,TA,KV,KO,DO,PR
+8.15:DO,LE,KT,KO,PR,MJ,GR
+8.16:LE,KT,KO,PR
+8.17:DO,LE,KV,GR,TA;KO,PR;LE,AG;LE,KI,BD
+8.18:LE,KT,KO,KI;LE,KI,BD
+8.19:LE,KI
+* End of file "anna.dat"
diff --git a/support/graphbase/assign_mona.w b/support/graphbase/assign_mona.w
new file mode 100644
index 0000000000..3a1ab9db8a
--- /dev/null
+++ b/support/graphbase/assign_mona.w
@@ -0,0 +1,692 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{ASSIGN\_\thinspace MONA}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+\def\dash{\mathrel-\joinrel\joinrel\mathrel-} % adjacent vertices
+\def\ddash{=\joinrel\joinrel=} % matched vertices
+
+\prerequisite{GB\_\thinspace MONA}
+@* The assignment problem.
+This demonstration program takes a matrix
+constructed by the |gb_mona| module and chooses at most one number from
+each row and column in such a way as to maximize the sum of the numbers
+chosen. It also reports the number of ``mems'' (memory references)
+expended during its computations, so that the algorithm it uses
+can be compared with alternative procedures.
+
+The matrix has $m$ rows and $n$ columns. If $m\le n$, one number will
+be chosen in each row; if $m\ge n$, one number will be chosen in each column.
+The numbers in the matrix are brightness levels (i.e., pixel values) in
+a digitized version of the Mona Lisa.
+
+Of course the author does not pretend that the location of ``highlights'' in
+da Vinci's painting, one per row and one per column, has any application
+to art appreciation. However, this program does seem to have pedagogic value,
+because the relation between pixel values and shades of gray allows us
+to visualize the data underlying this special case of the
+assignment problem; ordinary matrices of numeric data are much harder
+to perceive. The non-random nature of pixels
+in a work of art may also have similarities to the ``organic'' properties
+of data in real-world applications.
+
+This program is optionally able to produce an encapsulated PostScript file
+from which the solution can be displayed graphically, with halftone shading.
+
+@ As explained in |gb_mona|, the subroutine call |mona(m,n,d,m0,m1,n0,n1,d0,d1,
+area)| constructs an $m\times n$ matrix of integers between $0$ and~$d$,
+inclusive, based on the brightness levels in a rectangular region of
+a digitized Mona Lisa, where |m0|, |m1|, |n0|, and |n1| define that
+region. The raw data is obtained as a sum of |(m1-m0)(n1-n0)| pixel
+values between $0$ and~$255$, then scaled in such a way that sums |<=d0|
+are mapped to zero, sums |>=d1| are mapped to~$d$, and intermediate sums are
+mapped linearly to intermediate values. Default values |m1=360|, |n1=250|,
+|m=m1-m0|, |n=n1-n0|, |d=255|, and |d1=255(m1-m0)(n1-n0)| are substituted if
+any of the parameters |m|, |n|, |d|, |m1|, |n1|, or |d1| are zero.
+
+The user can specify the nine parameters |(m,n,d,m0,m1,n0,n1,d0,d1)|
+on the command line, at least in a \UNIX\ implementation, thereby
+obtaining a variety of special effects; the relevant
+command-line options are \.{m=}\<number>, \.{m0=}\<number>, and so on,
+with no spaces before or after the \.= signs that separate parameter
+names from parameter values. Additional options are also provided:
+\.{-s} (use only Mona's $16\times32$ ``smile'');
+\.{-c} (complement black/white); \.{-p} (print the matrix and solution);
+\.{-P} (produce a PostScript file \.{mona.eps} for graphic output);
+\.{-h} (use a heuristic that applies only when $m=n$); and
+\.{-v} or \.{-V} (print verbose or Very verbose commentary about the
+ algorithm's performance).
+@^UNIX dependencies@>
+
+Here is the overall layout of this \Cee\ program:
+
+@p
+#include "gb_graph.h" /* the GraphBase data structures */
+#include "gb_mona.h" /* the |mona| routine */
+@#
+@<Global variables@>@;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{@+@<Local variables@>;
+ @<Scan the command line options@>;
+ mtx=mona(m,n,d,m0,m1,n0,n1,d0,d1,working_storage);
+ if (mtx==NULL) {
+ fprintf(stderr,"Sorry, can't create the matrix! (error code %d)\n",
+ panic_code);
+ return -1;
+ }
+ printf("Assignment problem for %s%s\n",mona_id,(compl?", complemented":""));
+ sscanf(mona_id,"mona(%u,%u,%lu",&m,&n,&d); /* adjust for defaults */
+ if (m!=n) heur=0;
+ if (printing) @<Display the input matrix@>;
+ if (PostScript) @<Output the input matrix in PostScript format@>;
+ mems=0;
+ @<Solve the assignment problem@>;
+ if (printing) @<Display the solution@>;
+ if (PostScript) @<Output the solution in PostScript format@>;
+ printf("Solved in %d mems%s.\n",mems,
+ (heur?" with square-matrix heuristic":""));
+}
+
+@ @f Vertex int /* |gb_graph| defines these data types */
+@f Arc int
+@f Graph int
+@f Area int
+
+@<Glob...@>=
+Area working_storage; /* where to put the input data and auxiliary arrays */
+long *mtx; /* input data for the assignment problem */
+long mems; /* the number of memory references counted
+ while solving the problem */
+
+@ The following local variables are related to the command-line options:
+
+@<Local v...@>=
+unsigned m=0,n=0; /* number of rows and columns desired */
+unsigned long d=0; /* number of pixel values desired, minus~1 */
+unsigned m0=0,m1=0; /* input will be from rows $[|m0|\,.\,.\,|m1|)$ */
+unsigned n0=0,n1=0; /* and from columns $[|n0|\,.\,.\,|n1|)$ */
+unsigned long d0=0,d1=0; /* lower and upper threshold of raw pixel scores */
+int compl=0; /* should the input values be complemented? */
+int heur=0; /* should the square-matrix heuristic be used? */
+int printing=0; /* should the input matrix and solution be printed? */
+int PostScript=0; /* should an encapsulated PostScript file be produced? */
+
+@ @<Scan the command line options@>=
+while (--argc) {
+@^UNIX dependencies@>
+ if (sscanf(argv[argc],"m=%u",&m)==1) ;
+ else if (sscanf(argv[argc],"n=%u",&n)==1) ;
+ else if (sscanf(argv[argc],"d=%lu",&d)==1) ;
+ else if (sscanf(argv[argc],"m0=%u",&m0)==1) ;
+ else if (sscanf(argv[argc],"m1=%u",&m1)==1) ;
+ else if (sscanf(argv[argc],"n0=%u",&n0)==1) ;
+ else if (sscanf(argv[argc],"n1=%u",&n1)==1) ;
+ else if (sscanf(argv[argc],"d0=%u",&d0)==1) ;
+ else if (sscanf(argv[argc],"d1=%u",&d1)==1) ;
+ else if (strcmp(argv[argc],"-s")==0) smile; /* sets |m0|, |m1|, |n0|, |n1| */
+ else if (strcmp(argv[argc],"-c")==0) compl=1;
+ else if (strcmp(argv[argc],"-h")==0) heur=1;
+ else if (strcmp(argv[argc],"-v")==0) verbose=1;
+ else if (strcmp(argv[argc],"-V")==0) verbose=2; /* terrifically verbose */
+ else if (strcmp(argv[argc],"-p")==0) printing=1;
+ else if (strcmp(argv[argc],"-P")==0) PostScript=1;
+ else {
+ fprintf(stderr,
+ "Usage: %s [param=value] [-s] [-c] [-h] [-v] [-p] [-P]\n",argv[0]);
+ return -2;
+ }
+}
+
+@ @<Display the input matrix@>=
+for (k=0;k<m;k++) {
+ for (l=0;l<n;l++) printf("% 4d",compl?d-*(mtx+k*n+l):*(mtx+k*n+l));
+ printf("\n");
+}
+
+@ We obtain a crude but useful estimate of the computation time
+by counting mem units, as explained in the |miles_span| program.
+
+@d o mems++
+@d oo mems+=2
+@d ooo mems+=3
+
+@* Algorithmic overview. The {\it assignment problem\/} is the classical
+problem of weighted bipartite matching, the problem of choosing
+a maximum-weight set of disjoint edges in a bipartite graph. We will consider
+only the case of complete bipartite graphs, when the weights are
+specified by an $m\times n$ matrix.
+
+An algorithm is most easily developed if we begin with the assumption
+that the matrix is square (i.e., that $m=n$), and if we change from
+maximization to minimization. Then the assignment problem is the task
+of finding a permutation $\pi[0]\ldots\pi[n-1]$ of $\{0,\ldots,n-1\}$
+such that $\sum_{k=0}^{n-1} a_{k\pi[k]}$ is minimized, where
+$A=(a_{kl})$ is a given matrix of numbers $a_{kl}$ for $0\le k,l<n$.
+The algorithm below works for arbitrary real numbers $a_{kl}$, but we
+will assume in our implementation that the matrix entries are integers.
+
+One way to approach the assignment problem is to make three simple
+observations: (a)~Adding a constant to any row of the matrix does not
+change the solution $\pi[0]\ldots\pi[n-1]$. (b)~Adding a constant to
+any column of the matrix does not change the solution. (c)~If $a_{kl}\ge0$
+for all $k$ and~$l$, and if $\pi[0]\ldots\pi[n-1]$ is a permutation
+with the property that $a_{k\pi[k]}=0$ for all~$k$, then $\pi[0]\ldots\pi[n-1]$
+solves the assignment problem.
+
+The remarkable fact is that these three observations actually suffice. In
+other words, there is always a sequence of constants $(\sigma_0,\ldots,\sigma_
+{n-1})$ and $(\tau_0,\ldots,\tau_{n-1})$ and a permutation $\pi[0]\ldots
+\pi[n-1]$ such that
+$$\vbox{\halign{$#$,\hfil&\quad for #\hfil\cr
+a_{kl}-\sigma_k+\tau_{\,l}\ge0& $0\le k<n$ and $0\le l<n$;\cr
+a_{k\pi[k]}-\sigma_k+\tau_{\pi[k]}=0& $0\le k<n$.\cr}}$$
+
+@ To prove the remarkable fact just stated, we start by reviewing the
+theory of {\it unweighted\/} bipartite matching. Any $m\times n$ matrix
+$A=(a_{kl})$ befines a bipartite graph on the vertices $(r_0,\ldots,r_{m-1})$
+and $(c_0,\ldots,c_{n-1})$ if we say that $r_k\dash c_l$ whenever
+$a_{kl}=0$; in other words, the edges of the bipartite graph are the zeroes
+of the matrix. Two zeroes of~$A$ are called {\it independent\/} if they appear
+in different rows and columns; this means that the corresponding edges have
+no vertices in common. A set of mutually independent zeroes of the matrix
+therefore corresponds to a set of mutually disjoint edges, also called a
+{\it matching\/} between rows and columns.
+
+The Hungarian mathematicians Egerv\'ary and K\"onig proved
+[{\sl Matematikai \'es Fizikai Lapok\/ \bf38} (1931), 16--28, 116--119]
+that the maximum number of independent zeroes in a matrix is equal to
+the minimum number of rows and/or columns that are needed to ``cover''
+every zero. In other words, if we can find $p$ independent zeroes but
+not~$p+1$, then there is a way to choose $p$ lines in such a way that
+every zero of the matrix is included in at least one of the chosen lines,
+where a ``line'' is either a row or a column.
+
+Their proof was constructive, and it leads to a useful computer algorithm.
+Given a set of $p$ independent zeroes of a matrix, let us write
+$r_k\ddash c_l$ or $c_l\ddash r_k$ and say that $r_k$ is matched with $c_l$
+if $a_{kl}$ is one of these $p$ special
+zeroes, while we continue to write $r_k\dash c_l$ or $c_l\dash r_k$
+if $a_{kl}$ is one of the nonspecial zeroes. A given set of $p$
+special zeroes defines a choice of $p$ lines in the following way: Column~$c$
+is chosen if and only if it is reachable by a path of the form
+$$r_0\dash c_1\ddash r_1\dash c_2\ddash\cdots\dash c_q\ddash r_q\,,\eqno(*)$$
+where $r_0$ is unmatched, $q\ge1$, and $c=c_q$. Row~$r$ is chosen if
+and only if it is matched with a column that is not chosen. Thus exactly
+$p$ lines are chosen. We can now prove that the chosen lines cover
+all the zeroes, unless there is a way to find $p+1$ independent zeroes.
+
+For if $c\ddash r$, either $c$ or $r$ has been chosen. And
+if $c\dash r$, one of the following cases must arise. (1)~If $r$ and~$c$
+are both unmatched, we can increase~$p$ by matching them to each other.
+(2)~If $r$ is unmatched and $c\ddash r'$, then $c$ has been chosen, so
+the zero has been covered. (3)~If $r$ is matched to $c'\ne c$, then
+either $r$ has been chosen or $c'$ has been chosen. In the latter case
+there is a path of the form
+$$r_0\dash c_1\ddash r_1\dash c_2\ddash\cdots\ddash
+ r_{q-1}\dash c'\ddash r\dash c\,,$$
+where $r_0$ is unmatched and $q\ge1$.
+If $c$ is matched, it has therefore been chosen; otherwise we can increase $p$
+by redefining the matching to include
+$$r_0\ddash c_1\dash r_1\ddash c_2\dash\cdots\dash
+ r_{q-1}\ddash c'\dash r\ddash c\,.$$
+
+@ Now suppose $A$ is a {\it nonnegative\/} matrix.
+Cover the zeroes of~$A$ with a minimum number of lines, $p$, using the
+algorithm of Egerv\'ary and K\"onig. If $p<n$, some elements are still
+uncovered, so those elements are positive; suppose the minimum uncovered
+value is $\delta>0$. We can subtract $\delta$ from each unchosen row
+and add $\delta$ to each chosen column; the net effect is to subtract~$\delta$
+from all uncovered elements and to add~$\delta$ to all doubly-covered
+elements, while leaving all singly-covered elements unchanged. This
+transformation causes a new zero to appear, while preserving
+$p$ independent zeroes of the previous matrix (since they were each
+covered only once). If we repeat the Egerv\'ary-K\"onig construction
+with the same $p$ independent zeroes, we find that either $p$~is no
+longer maximum or at least one more column has been chosen.
+(The new zero $r\dash c$ occurs in a row~$r$ that was either unmatched
+or matched to a previously chosen column, because row~$r$ was not
+chosen.) Therefore if we repeat the process, we must eventually
+be able to increase $p$ until finally $p=n$. This will solve the
+assignment problem, proving the remarkable claim made earlier.
+
+@ If the given matrix $A$ has $m$ rows and $n>m$ columns,
+we can extend it artificially
+until it is square, by setting $a_{kl}=0$ for all $m\le k<n$ and
+$0\le l<n$. The construction above will then apply. But we need not
+waste time making such an extension, because it suffices to run the
+algorithm on the original $m\times n$ matrix until $m$ independent zeroes
+have been found. The reason is that the set of matched vertices always
+grows monotonically in the Egerv\'ary-K\"onig construction: If a
+column is matched at some stage, it will remain matched from that time on,
+although it may well change partners. The $n-m$ dummy rows at the bottom
+of~$A$ are always chosen to be part of the covering; so the dummy entries
+become nonzero only in the columns that are part of some covering.
+Such columns are part of some matching, so they are part of the
+final matching. Therefore at most $m$ columns of the dummy entries
+become nonzero during the procedure. We can always find $n-m$ independent
+zeroes in the $n-m$ dummy rows of the matrix, so we need not deal with the
+dummy elements explicitly.
+
+@ It has been convenient to describe the algorithm by saying that
+we add and subtract constants to and from the colums and rows of~$A$.
+But all those additions and subtractions can take a lot of time. So we will
+merely pretend to make the adjustments that the method calls for; we will
+represent them implicitly by two vectors $(\sigma_0,\ldots,\sigma_{m-1})$
+and $(\tau_0,\ldots,\tau_{n-1})$. Then the current value of each matrix
+entry will be $a_{kl}-\sigma_k+\tau_{\,l}$, instead of $a_{kl}$. The
+``zeroes'' will be positions such that $a_{kl}=\sigma_k-\tau_{\,l}$.
+
+Initially we will set $\tau_{\,l}=0$ for $0\le l<n$ and $\sigma_k=
+\min\{a_{k0},\ldots,a_{k(n-1)}\}$ for $0\le k<m$. If $m=n$ we can also
+make sure that there's a zero in every column by subtracting
+$\min\{a_{0l},\ldots,a_{(n-1)l}\}$ from $a_{kl}$ for all $k$ and~$l$.
+(This initial adjustment can conveniently be made to the original
+matrix entries, instead of indirectly via the $\tau$'s.) Users can
+discover if such a transformation is worthwhile by trying the program
+both with and without the \.{-h} option.
+
+We have been saying a lot of things and proving a bunch of theorems,
+without writing any code. Let's get back into programming mode
+by writing the routine that is called into
+action when the \.{-h} option has been specified:
+
+@d aa(k,l) *(mtx+k*n+l) /* a macro to access the matrix elements */
+
+@<Subtract column minima in order to start with lots of zeroes@>=
+{
+ for (l=0; l<n; l++) {
+ o,s=aa(0,l); /* the |o| macro counts one mem */
+ for (k=1;k<n;k++)
+ if (o,aa(k,l)<s) s=aa(k,l);
+ if (s>0)
+ for (k=0;k<n;k++)
+ oo,aa(k,l)-=s; /* |oo| counts two mems */
+ }
+ if (verbose) printf(" The heuristic has cost %d mems.\n",mems);
+}
+
+@ @<Local var...@>=
+register int k; /* the current row of interest */
+register int l; /* the current column of interest */
+register int j; /* another interesting column */
+register long s; /* the current matrix element of interest */
+
+@* Algorithmic details.
+The algorithm sketched above is quite simple, except that we did not
+discuss how to determine the chosen columns~$c_q$ that
+are reachable by paths of the stated form $(*)$. It is easy to find
+all such columns by constructing an unordered forest whose nodes are rows,
+beginning with all unmatched rows~$r_0$ and adding a row~$r$
+for which $c\ddash r$ when $c$ is adjacent to a row already in the forest.
+
+Our data structure, which is based on suggestions of Papadimitriou and
+Steiglitz [{\sl Combinatorial Optimization\/} (Prentice-Hall, 1982),
+$\mathchar"278$11.1], will use several arrays. If row~$r$ is matched
+with column~$c$ we will have |matching_col[r]=c| and |matching_row[c]=r|;
+if row~$r$ is unmatched, |matching_col[r]| will be |-1|, and
+if column~$c$ is unmatched, |matching_row[c]| will be |-1|.
+If column~$c$ has a mate and is also reachable in a path of the form $(*)$,
+we will have $|parent_row|[c]=r'$ for some $r'$ in the forest. Otherwise
+column~$c$ is not chosen, and we will have |parent_row[c]=-1|. The rows
+in the current forest will be called |unchosen_row[0]| through
+|unchosen_row[t-1]|, where |t| is the current total number of nodes.
+
+The amount $\sigma_k$ subtracted from row $k$ is called |row_dec[k]|; the
+amount $\tau_{\,l}$ added to row~$l$ is called |col_inc[l]|. In order to
+compute the minimum uncovered element efficiently, we maintain a
+quantity called |slack[l]| representing the minimum uncovered element
+in each column. More precisely, if column~$l$ is not chosen,
+|slack[l]| is the minimum of $a_{kl}
+-\sigma_k+\tau_{\,l}$ for $k\in\{|unchosen_row|[0],\ldots,
+|unchosen_row|[q-1]\}$, where $q\le t$ is the number of rows in the
+forest that we have explored so far. We also remember |slack_row[l]|,
+the number of a row where the stated minimum occurs.
+
+Column $l$ is chosen if and only if |parent_row[l]>=0|. We will arrange
+things so that we also have |slack[l]=0| in every chosen column.
+
+@<Local var...@>=
+int* matching_col; /* the column matching a given row, or $-1$ */
+int* matching_row; /* the row matching a given column, or $-1$ */
+int* parent_row; /* ancestor of a given column's mate, or $-1$ */
+int* unchosen_row; /* node in the forest */
+int t; /* total number of nodes in the forest */
+int q; /* total number of explored nodes in the forest */
+long* row_dec; /* $\sigma_k$, the amount subtracted from a given row */
+long* col_inc; /* $\tau_{\,l}$, the amount added to a given column */
+long* slack; /* minimum uncovered entry seen in a given column */
+int* slack_row; /* where the |slack| in a given column can be found */
+int unmatched; /* this many rows have yet to be matched */
+
+@ @<Allocate the intermediate data structures@>=
+matching_col=gb_alloc_type(m,@[int@],working_storage);
+matching_row=gb_alloc_type(n,@[int@],working_storage);
+parent_row=gb_alloc_type(n,@[int@],working_storage);
+unchosen_row=gb_alloc_type(m,@[int@],working_storage);
+row_dec=gb_alloc_type(m,@[long@],working_storage);
+col_inc=gb_alloc_type(n,@[long@],working_storage);
+slack=gb_alloc_type(n,@[long@],working_storage);
+slack_row=gb_alloc_type(n,@[int@],working_storage);
+if (gb_alloc_trouble) {
+ fprintf(stderr,"Sorry, out of memory!\n"); return -3;
+}
+
+@ The algorithm operates in stages, where each stage terminates
+when we are able to increase the number of matched elements.
+
+The first stage is different from the others; it simply goes through
+the matrix and looks for zeroes, matching as many rows and columns
+as it can. This stage also initializes table entries that will be
+useful in later stages.
+
+@d INF 0x7fffffff /* infinity (or darn near) */
+
+@<Do the initial stage@>=
+t=0; /* the forest starts out empty */
+for (l=0; l<n; l++) {
+ o,matching_row[l]=-1;
+ o,parent_row[l]=-1;
+ o,col_inc[l]=0;
+ o,slack[l]=INF;
+}
+for (k=0; k<m; k++) {
+ o,s=aa(k,0); /* get ready to calculate the minimum entry of row $k$ */
+ for (l=1; l<n; l++) if (o,aa(k,l)<s) s=aa(k,l);
+ o,row_dec[k]=s;
+ for (l=0; l<n; l++)
+ if ((o,s==aa(k,l)) && (o,matching_row[l]<0)) {
+ o,matching_col[k]=l;
+ o,matching_row[l]=k;
+ if (verbose>1) printf(" matching col %d==row %d\n",l,k);
+ goto row_done;
+ }
+ o,matching_col[k]=-1;
+ if (verbose>1) printf(" node %d: unmatched row %d\n",t,k);
+ o,unchosen_row[t++]=k;
+row_done:;
+}
+
+@ If a subsequent stage has not succeeded in matching every row,
+we prepare for a new stage by reinitializing the forest as follows.
+
+@<Get ready for another stage@>=
+t=0;
+for (l=0; l<n; l++) {
+ o,parent_row[l]=-1;
+ o,slack[l]=INF;
+}
+for (k=0; k<m; k++)
+ if (o,matching_col[k]<0) {
+ if (verbose>1) printf(" node %d: unmatched row %d\n",t,k);
+ o,unchosen_row[t++]=k;
+ }
+
+@ Here, then, is the algorithm's overall control structure.
+There are at most $m$ stages, and each stage does $O(mn)$ operations,
+so the total running time is $O(m^2n)$.
+
+@<Do the Hungarian algorithm@>=
+@<Do the initial stage@>;
+if (t==0) goto done;
+unmatched=t;
+while(1) {
+ if (verbose) printf(" After %d mems I've matched %d rows.\n",mems,m-t);
+ q=0;
+ while(1) {
+ while (q<t) {
+ @<Explore node |q| of the forest;
+ if the matching can be increased, |goto breakthru|@>;
+ q++;
+ }
+ @<Introduce a new zero into the matrix by modifying |row_dec| and |col_inc|;
+ if the matching can be increased, |goto breakthru|@>;
+ }
+breakthru: @<Update the matching by pairing row $k$ with column $l$@>;
+ if(--unmatched==0) goto done;
+ @<Get ready for another stage@>;
+}
+done: @<Doublecheck the solution@>;
+
+@ @<Explore node |q| of the forest;
+ if the matching can be increased, |goto breakthru|@>=
+{
+ o,k=unchosen_row[q];
+ o,s=row_dec[k];
+ for (l=0; l<n; l++)
+ if (o,slack[l]) {@+register long del;
+ oo,del=aa(k,l)-s+col_inc[l];
+ if (del<slack[l]) {
+ if (del==0) { /* we found a new zero */
+ if (o,matching_row[l]<0) goto breakthru;
+ o,slack[l]=0; /* this column will now be chosen */
+ o,parent_row[l]=k;
+ if (verbose>1) printf(" node %d: row %d==col %d--row %d\n",
+ t,matching_row[l],l,k);
+ oo,unchosen_row[t++]=matching_row[l];
+ } else {
+ o,slack[l]=del;
+ o,slack_row[l]=k;
+ }
+ }
+ }
+}
+
+@ At this point, column $l$ is unmatched, and row $k$ is in
+the forest. By following parent links in the forest,
+we can rematch rows and columns so that a previously unmatched row~$r_0$
+gets a mate.
+
+@<Update the matching by pairing row $k$ with column $l$@>=
+if (verbose) printf(" Breakthrough at node %d of %d!\n",q,t);
+while (1) {
+ o,j=matching_col[k];
+ o,matching_col[k]=l;
+ o,matching_row[l]=k;
+ if (verbose>1) printf(" rematching col %d==row %d\n",l,k);
+ if (j<0) break;
+ o,k=parent_row[j];
+ l=j;
+}
+
+@ If we get to this point, we have explored the entire forest; none of
+the unchosen rows has led to a breakthrough. An unchosen column with
+smallest |slack| will allow us to make further progress.
+
+@<Introduce a new zero into the matrix by modifying |row_dec| and |col_inc|;
+ if the matching can be increased, |goto breakthru|@>=
+s=INF;
+for (l=0; l<n; l++)
+ if (o,slack[l] && slack[l]<s)
+ s=slack[l];
+for (q=0; q<t; q++)
+ ooo,row_dec[unchosen_row[q]]+=s;
+for (l=0; l<n; l++)
+ if (o,slack[l]) { /* column $l$ is not chosen */
+ o,slack[l]-=s;
+ if (slack[l]==0) @<Look at a new zero, and |goto breakthru| with
+ |col_inc| up to date if there's a breakthrough@>;
+ } else oo,col_inc[l]+=s;
+
+@ There may be several columns tied for smallest slack. If any of them
+leads to a breakthough, we are very happy; but we must finish the loop on~|l|
+before going to |breakthru|, because the |col_inc| variables
+need to be maintained for the next stage.
+
+Within column |l|, there may be several rows that produce the same slack;
+we have remembered only one of them, |slack_row[l]|. Fortunately, one is
+sufficient for our purposes. We either have a breakthrough, or we choose
+column~|l|, regardless of which row or rows led us to consider that column.
+
+@<Look at a new zero, and |goto breakthru| with
+ |col_inc| up to date if there's a breakthrough@>=
+{
+ o,k=slack_row[l];
+ if (verbose>1)
+ printf(" Decreasing uncovered elements by %d produces zero at [%d,%d]\n",
+ s,k,l);
+ if (o,matching_row[l]<0) {
+ for (j=l+1; j<n; j++)
+ if (o,slack[j]==0) oo,col_inc[j]+=s;
+ goto breakthru;
+ } else { /* not a breakthrough, but the forest continues to grow */
+ o,parent_row[l]=k;
+ if (verbose>1) printf(" node %d: row %d==col %d--row %d\n",
+ t,matching_row[l],l,k);
+ oo,unchosen_row[t++]=matching_row[l];
+ }
+}
+
+@ The code in the present section is redundant, unless cosmic
+radiation has cause the hardware to malfunction. But there is some
+reassurance whenever we find that mathematics still appears to be
+consistent, so the author could not resist writing these few unnecessary lines,
+which verify that the assignment problem has indeed been solved optimally.
+(We don't count the mems.)
+
+@<Doublecheck...@>=
+for (k=0;k<m;k++)
+ for (l=0;l<n;l++)
+ if (aa(k,l)<row_dec[k]-col_inc[l]) {
+ fprintf(stderr,"Oops, I made a mistake!\n");
+ return -6; /* can't happen */
+ }
+for (k=0;k<m;k++) {
+ l=matching_col[k];
+ if (l<0 || aa(k,l)!=row_dec[k]-col_inc[l]) {
+ fprintf(stderr,"Oops, I blew it!\n"); return-66; /* can't happen */
+ }
+}
+k=0;
+for (l=0;l<n;l++) if (col_inc[l]) k++;
+if (k>m) {
+ fprintf(stderr,"Oops, I adjusted too many columns!\n");
+ return-666; /* can't happen */
+}
+
+@* Interfacing.
+A few nitty-gritty details still need to be handled: Our algorithm
+is not symmetric between rows and columns, and it works only for $m\le n$;
+so we will transpose the matrix when
+$m>n$. Furthermore, our algorithm minimizes, but we actually want
+it to maximize (except when |compl| is nonzero).
+
+Hence, we want to make the following transformations to the data before
+processing it with the algorithm developed above.
+
+@<Solve the assignment problem@>=
+if (m>n) @<Transpose the matrix@>@;
+else transposed=0;
+@<Allocate the intermediate data structures@>;
+if (compl==0)
+ for (k=0; k<m; k++) for (l=0; l<n; l++)
+ aa(k,l)=d-aa(k,l);
+if (heur) @<Subtract column minima...@>;
+@<Do the Hungarian algorithm@>;
+
+@ @<Transpose...@>=
+{
+ if (verbose>1) printf("Temporarily transposing rows and columns...\n");
+ tmtx=gb_alloc_type(m*n,@[long@],working_storage);
+ if (tmtx==NULL) {
+ fprintf(stderr,"Sorry, out of memory!\n"); return -4;
+ }
+ for (k=0; k<m; k++) for (l=0; l<n; l++)
+ *(tmtx+l*m+k)=*(mtx+k*n+l);
+ m=n;@+n=k; /* |k| holds the former value of |m| */
+ mtx=tmtx;
+ transposed=1;
+}
+
+@ @<Local v...@>=
+long* tmtx; /* the transpose of |mtx| */
+int transposed; /* has the data been transposed? */
+
+@ @<Display the solution@>=
+{
+ printf("The following entries produce an optimum assignment:\n");
+ for (k=0; k<m; k++)
+ printf(" [%d,%d]\n",@|
+ transposed? matching_col[k]:k,@|
+ transposed? k:matching_col[k]);
+}
+
+@* Encapsulated PostScript.
+A special output file called \.{mona.eps} is written if the user has
+selected the \.{-P} option. This file will contain a sequence of
+PostScript commands that can be used to generate an illustration
+within many kinds of documents. For example, if \TeX\ is being used
+with the \.{dvips} output driver from Radical Eye Software and the
+@.dvips@>
+associated \.{epsf.tex} macros, one can say
+$$\.{\\epsfxsize=10cm \\epsfbox\{mona.eps\}}$$
+within a \TeX\ document and the illustration will be typeset in
+a box that is 10 centimeters wide.
+
+The conventions of PostScript allow the illustration to be scaled to
+any size. Best results are probably obtained if each pixel is at
+least one millimeter wide (about 1/25 inch) when printed.
+
+The illustration is formed by first
+``painting'' the input data as a rectangle of pixels,
+with up to 256 shades of gray. Then the solution pixels are
+framed in black, with a white trim just inside the black edges
+to help make the frame visible in already-dark places. The frames are
+created by painting over the original image; the
+center of each solution pixel retains its original color.
+
+Encapsulated PostScript files have a simple format that is recognized
+by many software packages and printing devices. We use a subset of
+PostScript that should be easy to convert to other languages if necessary.
+
+@<Output the input matrix in PostScript format@>=
+{
+ eps_file=fopen("mona.eps","w");
+ if (!eps_file) {
+ fprintf("Sorry, I can't open the file `mona.eps'!\n");
+ PostScript=0;
+ } else {
+ fprintf(eps_file,"%%!PS-Adobe-3.0 EPSF-3.0\n"); /* 1.0 and 2.0 also OK */
+ fprintf(eps_file,"%%%%BoundingBox: -1 -1 %d %d\n",n+1,m+1);
+ fprintf(eps_file,"/buffer %d string def\n",n);
+ fprintf(eps_file,"%d %d 8 [%d 0 0 -%d 0 %d]\n",n,m,n,m,m);
+ fprintf(eps_file,"{currentfile buffer readhexstring pop} bind\n");
+ fprintf(eps_file,"gsave %d %d scale image\n",n,m);
+ for (k=0;k<m;k++) @<Output row |k| as a hexadecimal string@>;
+ fprintf(eps_file,"grestore\n");
+ }
+}
+
+@ @<Glob...@>=
+FILE *eps_file; /* file for encapsulated PostScript output */
+
+@ This program need not produce machine-independent output, so we may
+safely use floating-point arithmetic here. At most 64 characters
+(32 pixel-bytes) are output on each line.
+
+@<Output row |k|...@>=
+{@+register float conv=255.0/(float)d; register int x;
+ for (l=0; l<n; l++) {
+ x=(int)(conv*(float)(compl?d-aa(k,l):aa(k,l)));
+ fprintf(eps_file,"%02x",x>255?255:x);
+ if ((l&0x1f)==0x1f) fprintf(eps_file,"\n");
+ }
+ if (n&0x1f) fprintf(eps_file,"\n");
+}
+
+@ @<Output the solution in PostScript format@>=
+{
+ fprintf(eps_file,
+ "/bx {moveto 0 1 rlineto 1 0 rlineto 0 -1 rlineto closepath\n");
+ fprintf(eps_file," gsave .3 setlinewidth 1 setgray clip stroke");
+ fprintf(eps_file," grestore stroke} bind def\n");
+ fprintf(eps_file," .1 setlinewidth\n");
+ for (k=0; k<m; k++)
+ fprintf(eps_file," %d %d bx\n",@|
+ transposed? k:matching_col[k],@|
+ transposed? n-1-matching_col[k]:m-1-k);
+ fclose(eps_file);
+}
+
+@* Index. As usual, we close with a list of identifier definitions and uses.
+
diff --git a/support/graphbase/boilerplate.w b/support/graphbase/boilerplate.w
new file mode 100644
index 0000000000..64f6e9be5d
--- /dev/null
+++ b/support/graphbase/boilerplate.w
@@ -0,0 +1,38 @@
+% This material goes at the beginning of all Stanford GraphBase CWEB files
+
+\def\topofcontents{
+ \leftline{\sc\today\ at \hours}\bigskip\bigskip
+ \centerline{\titlefont\title}}
+
+\font\ninett=cmtt9
+\def\botofcontents{\vskip 0pt plus 1filll
+ \ninerm\baselineskip10pt
+ \noindent\copyright\ 1992 Stanford University
+ \bigskip\noindent
+ This file may be freely copied and distributed, provided that
+ no changes whatsoever are made. All users are asked to help keep
+ the Stanford GraphBase files consistent and ``uncorrupted,''
+ identical everywhere in the world. Changes are permissible only
+ if the modified file is given a new name, different from the names of
+ existing files in the Stanford GraphBase, and only if the modified file is
+ clearly identified as not being part of that GraphBase.
+ (The {\ninett CWEB} system has a ``change file'' facility by
+ which users can easily make minor alterations without modifying
+ the master source files in any way. Everybody is supposed to use
+ change files instead of changing the files.)
+ The author has tried his best to produce correct and useful programs,
+ in order to help promote computer science research,
+ but no warranty of any kind should be assumed.
+ \smallskip\noindent
+ Preliminary work on the Stanford GraphBase project
+ was supported in part by National Science
+ Foundation grant CCR-86-10181.}
+
+\def\prerequisite#1{\def\startsection{\noindent
+ Important: Before reading {\sc\title},
+ please read or at least skim the program for {\sc#1}.\bigskip
+ \let\startsection=\stsec\stsec}}
+\def\prerequisites#1#2{\def\startsection{\noindent
+ Important: Before reading {\sc\title}, please read
+ or at least skim the programs for {\sc#1} and {\sc#2}.\bigskip
+ \let\startsection=\stsec\stsec}}
diff --git a/support/graphbase/book_components.w b/support/graphbase/book_components.w
new file mode 100644
index 0000000000..854c140f10
--- /dev/null
+++ b/support/graphbase/book_components.w
@@ -0,0 +1,486 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{BOOK\_\kern.05emCOMPONENTS}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+
+\prerequisite{GB\_\thinspace BOOKS}
+@* Bicomponents. This demonstration program computes the
+biconnected components of GraphBase graphs derived from world literature,
+using a variant of Hopcroft and Tarjan's algorithm [R. E. Tarjan, ``Depth-first
+search and linear graph algorithms,'' {\sl SIAM Journal on Computing\/
+\bf1} (1972), 146--160]. Articulation points and ordinary (connected)
+components are also obtained as byproducts of the computation.
+
+Two edges belong to the same biconnected component---or ``bicomponent''
+for short---if and only if they are identical or both belong to a
+simple cycle. This defines an equivalence relation on edges.
+The bicomponents of a connected graph with more than one vertex form a
+free tree, if we say that two bicomponents are adjacent when they have
+a common vertex (i.e., when there is a vertex belonging to at least one edge
+in each of the bicomponents). Such a vertex is called an articulation
+point; there is a unique articulation point between any two adjacent
+bicomponents. If we choose one bicomponent to be the ``root'' of the
+free tree, the other bicomponents can be represented conveniently as
+lists of vertices, with the articulation point that leads toward the root
+listed last. This program displays the bicomponents in exactly that way.
+
+@ We permit command-line options in typical \UNIX\ style so that a variety of
+graphs can be studied: The user can say `\.{-t}\<title>',
+`\.{-n}\<number>', `\.{-x}\<number>', `\.{-f}\<number>',
+`\.{-l}\<number>', `\.{-i}\<number>', `\.{-o}\<number>', and/or
+`\.{-s}\<number>' to change the default values of the parameters in
+the graph generated by |book(t,n,x,f,l,i,o,s)|.
+
+When the bicomponents are listed, each character in the book is identified by
+a two-letter code, as found in the associated data file.
+An explanation of these codes will appear first if the \.{-v} or \.{-V} option
+is specified. The \.{-V} option prints a fuller explanation than~\.{-v}; it
+also shows each character's weighted number of appearances.
+
+@^UNIX dependencies@>
+
+@p
+#include "gb_graph.h" /* the GraphBase data structures */
+#include "gb_books.h" /* the |book| routine */
+#include "gb_io.h" /* the |imap_chr| routine */
+@#
+@<Global variables@>;
+@<Subroutines@>;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{@+Graph *g; /* the graph we will work on */
+ register Vertex *v; /* the current vertex of interest */
+ char *t="anna"; /* the book to use */
+ unsigned n=0; /* the desired number of vertices (0 means infinity) */
+ unsigned x=0; /* the number of major characters to exclude */
+ unsigned f=0; /* the first chapter to include */
+ unsigned l=0; /* the last chapter to include (0 means infinity) */
+ long i=1; /* the weight for appearances in selected chapters */
+ long o=1; /* the weight for appearances in unselected chapters */
+ long s=0; /* the random number seed */
+ @<Scan the command line options@>;
+ g=book(t,n,x,f,l,i,o,s);
+ if (g==NULL) {
+ fprintf(stderr,"Sorry, can't create the graph! (error code %d)\n",
+ panic_code);
+ return -1;
+ }
+ printf("Biconnectivity analysis of %s\n\n",g->id);
+ if (verbose) @<Print the cast of selected characters@>;
+ @<Perform the Hopcroft-Tarjan algorithm on |g|@>;
+}
+
+@ @<Scan the command line options@>=
+while (--argc) {
+@^UNIX dependencies@>
+ if (strncmp(argv[argc],"-t",2)==0) t=argv[argc]+2;
+ else if (sscanf(argv[argc],"-n%u",&n)==1) ;
+ else if (sscanf(argv[argc],"-x%u",&x)==1) ;
+ else if (sscanf(argv[argc],"-f%u",&f)==1) ;
+ else if (sscanf(argv[argc],"-l%u",&l)==1) ;
+ else if (sscanf(argv[argc],"-i%ld",&i)==1) ;
+ else if (sscanf(argv[argc],"-o%ld",&o)==1) ;
+ else if (sscanf(argv[argc],"-s%ld",&s)==1) ;
+ else if (strcmp(argv[argc],"-v")==0) verbose=1;
+ else if (strcmp(argv[argc],"-V")==0) verbose=2;
+ else {
+ fprintf(stderr,"Usage: %s [-ttitle][-xN][-fN][-lN][-iN][-oN][-sN][-v]\n",
+ argv[0]);
+ return -2;
+ }
+}
+
+@ @f Vertex int /* |gb_graph| defines these data types */
+@f Arc int
+@f Graph int
+
+@<Subroutines@>=
+char code_name[3][3];
+char *vertex_name(v,i) /* return (as a string) the name of vertex |v| */
+ Vertex *v;
+ int i; /* |i| should be 0, 1, or 2 to avoid clash in |code_name| array */
+{
+ code_name[i][0]=imap_chr(v->short_code/36);
+ code_name[i][1]=imap_chr(v->short_code%36);
+ return code_name[i];
+}
+
+@ @<Print the cast of selected characters@>=
+{
+ for (v=g->vertices;v<g->vertices+g->n;v++) {
+ if (verbose==1) printf("%s=%s\n",vertex_name(v,0),v->name);
+ else printf("%s=%s,%s [weight %d]\n",vertex_name(v,0),v->name,v->desc,@|
+ i*v->in_count+o*v->out_count);
+ }
+ printf("\n");
+}
+
+@*The algorithm.
+The Hopcroft-Tarjan algorithm is inherently recursive. We will
+implement the recursion explicitly via linked lists, instead of using
+\Cee's runtime stack, because some computer systems bog down in the
+presence of deeply nested recursion.
+
+Each vertex goes through three stages during the algorithm. First it is
+`unseen'; then it is `active'; finally it becomes `settled', when it
+has been assigned to a bicomponent.
+
+The data structures that represent the current state of the algorithm
+are implemented by using five of the utility fields in each vertex:
+|rank|, |parent|, |untagged|, |link|, and |min|. We will describe each of
+these in turn.
+
+@ First is the integer |rank| field, which is zero when a vertex is unseen.
+As soon as the vertex is first examined, it becomes active and its |rank|
+becomes and remains nonzero. Indeed, the |k|th vertex to become active
+will receive rank~|k|.
+
+It's convenient to think of the Hopcroft-Tarjan algorithm as a simple adventure
+game, in which we want to explore all rooms of a cave. Passageways between
+the rooms allow two-way travel. When we come
+into a room for the first time, we assign a new number to that room;
+this is its rank. Later on we may happen to come into the same room
+again, and we will notice that it has nonzero rank; then we'll be able
+to make a quick exit, saying ``we've already been here.'' (The extra
+complexities of computer games, like dragons that might need to be
+vanquished, do not arise.)
+
+@d rank z.i /* the |rank| of a vertex is stored in utility field |z| */
+
+@<Glob...@>=
+int nn; /* the number of vertices that have been seen */
+
+@ The active vertices will always form an oriented tree, whose arcs are
+a subset of the arcs in the original graph. A tree arc from |u| to~|v|
+will be represented by |v->parent==u|. Every active vertex has a
+parent, which is usually another active vertex; the only exception is
+the root of the tree, whose |parent| is a dummy vertex called |dummy|.
+The dummy vertex has rank zero.
+
+In the cave analogy, the `parent' of room |v| is the room we were in
+immediately before entering |v| the first time. By following parent
+pointers, we will be able to leave the cave whenever we want.
+
+@d parent y.v /* the |parent| of a vertex is stored in utility field |y| */
+
+@<Glob...@>=
+Vertex dummy; /* imaginary parent of the root vertex */
+
+@ All edges in the original undirected graph are explored systematically during
+a depth-first search. Whenever we look at an edge, we `tag' it so that
+we won't need to explore it again. In a cave, for example, we might
+mark each passageway between rooms once we've tried to go through it.
+
+In a GraphBase graph, undirected edges are represented as a pair of directed
+arcs. Each of these arcs will be examined and eventually tagged.
+
+The algorithm doesn't actually place a tag on its |Arc| records; instead,
+each vertex |v| has a pointer |v->untagged| that leads to all
+hitherto-unexplored arcs from~|v|. The arcs of the list that appear
+between |v->arcs| and |v->untagged| are the ones already examined.
+
+@d untagged x.a /* the |untagged| field points to an |Arc| record, or |NULL| */
+
+@ The algorithm maintains a special stack, the |active_stack|, which contains
+all the currently active vertices. Each vertex has a |link| field that points
+to the vertex next lower on its stack, or to |NULL| if the vertex is
+at the bottom. The vertices on |active_stack| always appear in increasing
+order of rank from bottom to top.
+
+@d link w.v /* the |link| field of a vertex occupies utility field |w| */
+
+@<Glob...@>=
+Vertex * active_stack; /* the top of the stack of active vertices */
+
+@ Finally there's a |min| field, which is the tricky part that makes
+everything work. If vertex~|v| is unseen or settled, its |min| field is
+irrelevant. Otherwise |v->min| points to the active vertex~|u|
+of smallest rank having the property that
+there is a directed path from |v| to |u| consisting of
+zero or more `mature' tree arcs followed by a single non-tree arc.
+
+What is a tree arc, you ask. And what is a mature arc? Good questions. At the
+moment when arcs of the graph are tagged, we classify them either as tree
+arcs (if they correspond to a new |parent| link in the tree of active
+nodes) or non-tree arcs (otherwise). The tree arcs therefore correspond to
+passageways that have led us to new territory. A tree arc becomes mature
+when it is no longer on the path from the root to the current vertex being
+explored. We also say that a vertex becomes mature when it is
+no longer on that path. All arcs from a mature vertex have been tagged.
+
+We said before that every vertex is initially unseen, then active, and
+finally settled. With our new definitions, we see further that every arc starts
+out untagged, then it becomes either a non-tree arc or a tree arc. In the
+latter case it begins as an immature tree arc and eventually matures.
+
+The dummy vertex is considered to be active, and we assume that
+there is a non-tree arc from the root vertex back to |dummy|. Thus,
+there is a non-tree arc from |v| to |v->parent| for all~|v|, and |v->min|
+will always point to a vertex whose rank is less than or equal to
+|v->parent->rank|. It will turn out that |v->min| is always an ancestor
+of~|v|.
+
+Just believe these definitions, for now. All will become clear soon.
+
+@d min v.v /* the |min| field of a vertex occupies utility field |v| */
+
+@ Depth-first search explores a graph by systematically visiting all
+vertices and seeing what they can lead to. In the Hopcroft-Tarjan algorithm, as
+we have said, the active vertices form an oriented tree. One of these
+vertices is called the current vertex.
+
+If the current vertex still has an arc that hasn't been tagged, we
+tag one such arc and there are two cases: Either the arc leads to
+an unseen vertex, or it doesn't. If it does, the arc becomes a tree
+arc; the previously unseen vertex becomes active, and it becomes the
+new current vertex. On the other hand if the arc leads to a vertex
+that has already been seen, the arc becomes a non-tree arc and the
+current vertex doesn't change.
+
+Finally there will come a time when the current vertex~|v| has no
+untagged arcs. At this point, the
+algorithm might decide that |v| and all its descendants
+form a bicomponent, together with |v->parent|.
+ Indeed, this condition turns out to be true if and only if
+|v->min==v->parent|; a proof appears below. If so, |v| and all its descendants
+become settled, and they leave the tree. If not, the tree arc from
+|v|'s parent~|u| to~|v| becomes mature, so the value of |v->min| is
+used to update the value of |u->min|. In both cases |v| becomes mature,
+and the new current vertex will be the parent of~|v|. Notice that only the
+value of |u->min| needs to be updated, when the arc from |u| to~|v|
+matures; all other values |w->min| stay the same, because a newly
+mature arc has no mature predecessors.
+
+In the cave analogy, a room |v| and its descendants will become a
+bicomponent together with the room~|u| from which we entered~|v|
+when there's no outlet from the subcave starting at~|v|
+without coming back through |u| itself. Once such a bicomponent
+is identified, we close it off and don't explore that subcave any further.
+
+If |v| is the root of the tree, it always has |v->min==dummy|, so it
+will always define a new bicomponent at the moment it matures. Then
+the depth-first search will terminate, since |v|~has no real parent.
+But the Hopcroft-Tarjan algorithm will press on, trying to find a
+vertex~|u| that is still unseen. If such a vertex exists, a
+new depth-first search will begin with |u| as the root. This process
+keeps on going until at last all vertices are happily settled.
+
+The beauty of this algorithm is that it all works very efficiently
+when we organize it as follows:
+
+@<Perform the Hopcroft-Tarjan algorithm on |g|@>=
+@<Make all vertices unseen and all arcs untagged@>;
+for (vv=g->vertices; vv<g->vertices+g->n; vv++)
+ if (vv->rank==0) /* |vv| is still unseen */
+ @<Perform a depth-first search with |vv| as the root, finding the
+ bicomponents of all unseen vertices reachable from~|vv|@>;
+
+@ @<Glob...@>=
+Vertex *vv; /* sweeps over all vertices, making sure none is left unseen */
+
+@ It's easy to get the data structures started, according to the
+conventions stipulated above.
+
+@<Make all vertices unseen...@>=
+for (v=g->vertices; v<g->vertices+g->n; v++) {
+ v->rank=0;
+ v->untagged=v->arcs;
+}
+nn=0;
+active_stack=NULL;
+dummy.rank=0;
+
+@ The task of starting a depth-first search isn't too bad either. Throughout
+this part of the algorithm, variable~|v| will point to the current vertex.
+
+@<Perform a depth-first search with |vv| as the root...@>=
+{
+ v=vv;
+ v->parent=&dummy;
+ @<Make vertex |v| active@>;
+ do @<Explore one step from the current vertex~|v|, possibly moving
+ to another current vertex and calling~it~|v|@>@;
+ while (v!=&dummy);
+}
+
+@ @<Make vertex |v| active@>=
+v->rank=++nn;
+v->link=active_stack;
+active_stack=v;
+v->min=v->parent;
+
+@ Now things get interesting. But we're just doing what any well-organized
+spelunker would do when calmly exploring a cave.
+There are three main cases,
+depending on whether the current vertex stays where it is, moves
+to a new child, or backtracks to a parent.
+
+@<Explore one step from the current vertex~|v|, possibly moving
+ to another current vertex and calling~it~|v|@>=
+{@+register Vertex *u; /* a vertex adjacent to |v| */
+ register Arc *a=v->untagged; /* |v|'s first remaining untagged arc, if any */
+ if (a) {
+ u=a->tip;
+ v->untagged = a->next; /* tag the arc from |v| to |u| */
+ if (u->rank) { /* we've seen |u| already */
+ if (u->rank < v->min->rank)
+ v->min=u; /* non-tree arc, just update |v->min| */
+ } else { /* |u| is presently unseen */
+ u->parent = v; /* the arc from |v| to |u| is a new tree arc */
+ v = u; /* |u| will now be the current vertex */
+ @<Make vertex |v| active@>;
+ }
+ } else { /* all arcs from |v| are tagged, so |v| matures */
+ u=v->parent; /* prepare to backtrack in the tree */
+ if (v->min==u) @<Remove |v| and all its successors on the active stack
+ from the tree, and report them as a bicomponent of the graph
+ together with~|u|@>@;
+ else /* the arc from |u| to |v| has just matured,
+ making |v->min| visible from |u| */@,
+ if (v->min->rank < u->min->rank)
+ u->min=v->min;
+ v=u; /* the former parent of |v| is the new current vertex |v| */
+ }
+}
+
+@ The elements of the active stack are always in order
+by rank, and all children of a vertex~|v| in the tree have rank higher
+than~|v|. The Hopcroft-Tarjan algorithm relies on a converse property: {\sl All
+active nodes whose rank exceeds that of the current vertex~|v|
+are descendants of~|v|.} (This holds because the algorithm has constructed
+the tree by assigning ranks in preorder, ``the order of succession to the
+throne''. First come |v|'s firstborn and descendants, then the nextborn,
+and so on.) Therefore the descendants of the current vertex always appear
+consecutively at the top of the stack.
+
+Suppose |v| is a mature, active vertex with |v->min==v->parent|, and
+let |u=v->parent|. We want to prove that |v| and its descendants,
+together with~|u| and all edges between these vertices, form a
+biconnected graph. Call this subgraph~|H|. The parent links
+define a subtree of~|H|, rooted at~|u|, and |v| is the only vertex
+having |u| as a parent (because all other vertices are descendants
+of~|v|). If |x| is any vertex of~|H| different from |u| and |v|,
+there is a path from |x| to |x->min| that does not touch~|x->parent|,
+and |x->min| is a proper ancestor of |x->parent|. This property
+is sufficient to establish the biconnectedness of~|H|. (A proof appears
+at the conclusion of this program.) Moreover, we cannot add any
+more vertices to~|H| without losing biconnectivity; if |w|~is another
+vertex, |w| has either been output already as a non-articulation point
+of a previous biconnected component, or we can prove that
+there is no path from |w| to~|v| that avoids the vertex~|u|.
+
+Therefore we are justified in settling |v| and its active descendants now.
+Removing them from the tree of active vertices does not remove any
+vertex from which there is a path to a vertex of rank less than
+|u->rank|; hence it does not affect the validity of the |w->min| value
+for any vertex~|w| that remains active.
+
+A slight technicality arises with respect to whether or not
+the parent of~|v|, vertex~|u|, is part of the present bicomponent.
+When |u| is the dummy vertex, we have already printed the final bicomponent
+of a connected component of the original graph, unless |v| was
+an isolated vertex. Otherwise |u| is an
+articulation point that will occur in subsequent bicomponents,
+unless this is the final bicomponent of a connected component.
+(This aspect of the algorithm is probably its most subtle point;
+consideration of an example or two should clarify everything.)
+
+We print out enough information for a reader to verify the
+biconnectedness of the claimed component easily.
+
+@<Remove |v| and all its successors on the active stack...@>=
+if (u==&dummy) { /* |active_stack| contains just |v| */
+ if (artic_pt)
+ printf(" and %s (this ends a connected component of the graph)\n",
+ vertex_name(artic_pt,0));
+ else printf("Isolated vertex %s\n",vertex_name(v,0));
+ active_stack=artic_pt=NULL;
+} else {@+register Vertex *t; /* runs through the vertices of the
+ new bicomponent */
+ if (artic_pt)
+ printf(" and articulation point %s\n",vertex_name(artic_pt,0));
+ t=active_stack;
+ active_stack=v->link;
+ printf("Bicomponent %s", vertex_name(v,0));
+ if (t==v) putchar('\n'); /* single vertex */
+ else {
+ printf(" also includes:\n");
+ while (t!=v) {
+ printf(" %s (from %s; ..to %s)\n",
+ vertex_name(t,0), vertex_name(t->parent,1),vertex_name(t->min,2));
+ t=t->link;
+ }
+ }
+ artic_pt=u; /* the printout will be finished later */
+}
+
+@ Like all global variables, |artic_pt| is initially zero (|NULL|).
+
+@<Glob...@>=
+Vertex *artic_pt; /* articulation point to be printed if the current
+ bicomponent isn't the last in its connected component */
+
+@*Proofs.
+The program is done but we still should prove that it works.
+First we want to clarify the informal definition by verifying that
+the cycle relation between edges, as stated in the introduction, is indeed an
+equivalence relation.
+
+\def\dash{\mathrel-\joinrel\joinrel\mathrel-}
+Suppose $u\dash v$ and $w\dash x$ are edges of a simple cycle~$C$, while
+$w\dash x$ and $y\dash z$ are edges of a simple cycle~$D$. We want to show
+that there is a simple cycle containing the edges $u\dash v$ and $x\dash y$.
+There are vertices $a,b\in C$ such that $a\dash^\ast y\dash z\dash^\ast b$
+is a subpath of~$D$ containing no other vertices of $C$ besides $a$ and~$b$.
+Join this subpath to the subpath in $C$ that runs from $b$ to~$a$ through
+the edge $u\dash v$.
+
+Therefore the stated relation between edges is transitive, and it is
+an equivalence relation.
+A graph is biconnected if it contains a single vertex, or if each of
+its vertices is adjacent to at least one other vertex and any two edges are
+equivalent.
+
+@ Next we prove the well known fact that a graph is biconnected if and
+only if it is connected and, for any three distinct vertices $x$,
+$y$,~$z$, it contains a path from $x$ to~$y$ that does not touch~$z$.
+Call the latter condition property~P.
+
+Suppose $G$ is biconnected, and let $x,y$ be distinct vertices of~$G$.
+Then there exist edges $u\dash x$ and $v\dash y$, which are either
+identical (hence $x$ and~$y$ are adjacent) or part of a simple cycle
+(hence there are two paths from $x$ to~$y$, having no other vertices in
+common). Thus $G$ has property~P.
+
+Suppose, conversely, that $G$ has property~P, and let $u\dash v,
+w\dash x$ be distinct edges of~$G$. We want to show that these edges
+belong to some simple cycle. The proof is by induction on
+$k=\min\bigl(d(u,w),d(u,x),\allowbreak d(v,w),d(v,x)\bigr)$, where $d$~denotes
+distance. If $k=0$, property~P gives the result directly. If $k>0$,
+we can assume by symmetry that $k=d(u,w)$; so there's a vertex $y$
+with $u\dash y$ and $d(y,w)=k-1$. And we have $u\dash v$ equivalent to
+$u\dash y$ by property~P, $u\dash y$ equivalent to $w\dash x$ by induction,
+hence $u\dash v$ is equivalent to $w\dash x$ by transitivity.
+
+@ Finally, we prove that $G$ satisfies property~P if it has the
+following properties: (1)~There are two distinguished vertices $u$
+and~$v$. (2)~Some of the edges of~$G$ form a subtree rooted at~$u$,
+and $v$ is the only vertex whose parent in this tree is~$u$.
+(3)~Every vertex~$x$ other than $u$ or $v$ has a path to its
+grandparent that does not go through its parent.
+
+If property P doesn't hold, there are distinct vertices $x,y,z$ such
+that every path from $x$ to~$y$ goes through~$z$. In particular, $z$ must be
+between $x$ and~$y$ in the unique path~$\pi$ that joins them in the subtree.
+It follows that $z\ne u$ is the parent of some node $z'$ in that path; hence
+$z'\ne u$ and $z'\ne v$. But we can
+avoid $z$ by going from $z'$ to the grandparent of $z'$, which is
+also part of path~$\pi$ unless $z$ is also the parent of another node
+$z''$ in~$\pi$. In the latter case, however,
+we can avoid $z$ by going from $z'$ to the grandparent of $z'$ and from there
+to $z''$, since $z'$ and $z''$ have the same grandparent.
+
+@* Index. We close with a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/cities.texmap b/support/graphbase/cities.texmap
new file mode 100644
index 0000000000..710b6f8c36
--- /dev/null
+++ b/support/graphbase/cities.texmap
@@ -0,0 +1,160 @@
+% Plain TeX code to generate a map of the 128 cities in miles.dat
+
+% Parameters to the \\ macro are:
+% #1: city name to be typeset
+% #2,#3: (x,y) coordinates for lower left corner of label box
+% #4,#5: (x,y) coordinates for the dot
+% (#4,#5)=(12318-lng,1.5(lat-2672)), where (lat,lng) are the coords in miles.dat
+
+% Parameters to \| are similar, but the state code is separated out
+% and put on a second line, #3 ems from the right edge of the main line
+% e.g. City Name, ST .5(cityx,cityy,dotx,doty)
+% puts "ST" on the second line, .5em from the right
+
+\newdimen\unit \unit=.0012in
+\setbox0=\hbox{\fivesy\char15}
+\newbox\dotbox \setbox\dotbox=\hbox{\kern-.5\wd0\fivesy\char15} \wd\dotbox=0pt
+\newdimen\fudge \setbox0=\hbox{\fiverm p} \fudge=-\dp0
+ \advance\fudge-.5\ht\dotbox \advance\fudge.5\dp\dotbox
+\newdimen\vertpos
+\def\\#1 (#2,#3,#4,#5){\vertpos=#5\unit \advance\vertpos\fudge
+ \setbox0=\hbox{\kern#4\unit \raise\vertpos\copy\dotbox}\wd0=0pt \box0
+ \setbox0=\hbox{\kern#2\unit \raise#3\unit\hbox{\fiverm#1}}\wd0=0pt \box0}
+\def\|#1, #2 #3(#4,#5,#6,#7){\vertpos=#7\unit \advance\vertpos\fudge
+ \setbox0=\hbox{\kern#6\unit \raise\vertpos\copy\dotbox}\wd0=0pt \box0
+ \setbox0=\hbox{\kern#4\unit \raise#5\unit
+ \hbox{\fiverm#1,\llap{\lower55\unit\hbox{#2\kern#3em}}}}\wd0=0pt \box0}
+
+\vglue 2in
+\noindent
+\\Ravenna, OH (3707,2103,4188,2166)
+\\Reading, PA (4735,2050,4719,2041)
+\\Red Bluff, CA (-415,2034,88,2019)
+\\Regina, SA (1535,3575,1847,3555)
+\\Reno, NV (306,1940,331,1920)
+\\Rhinelander, WI (3222,2860,3370,2838)
+\\Richfield, UT (877,1737,1103,1807)
+\|Richmond, IN .5(3620,1901,3823,1966)
+\\Richmond, VA (4585,1572,4567,1623)
+\\Roanoke, VA (4136,1514,4318,1582)
+\\Rochester, MN (2696,2613,3066,2595)
+\\Rochester, NY (4032,2445,4551,2466)
+\\Rockford, IL (2953,2277,3402,2332)
+\\Rock Springs, WY (1014,2161,1389,2230)
+\\Rocky Mount, NC (4548,1323,4532,1383)
+\\Roswell, NM (1410,938,1859,1002)
+\\Rutland, VT (5044,2504,5015,2533)
+\\Sacramento, CA (168,1796,163,1780)
+\\Saginaw, MI (3533,2432,3918,2506)
+\\Saint Augustine, FL (3996,402,4180,475)
+\\Saint Cloud, MN (2349,2837,2895,2827)
+\\Saint Johnsbury, VT (4991,2677,5110,2655)
+\\Saint Joseph, MI (3659,2319,3664,2307)
+\\Saint Joseph, MO (2203,1964,2828,1957)
+\|Saint Louis, MO .5(3105,1715,3293,1785)
+\\Saint Paul, MN (2776,2750,3002,2734)
+\\Salem, OR (-362,2665,9,2733)
+\\Salida, CO (1404,1791,1712,1771)
+\\Salina, KS (2162,1793,2551,1818)
+\\Salinas, CA (-261,1426,147,1492)
+\\Salisbury, MD (4771,1690,4752,1747)
+\\Salt Lake City, UT (620,2036,1124,2106)
+\\San Angelo, TX (1699,683,2268,711)
+\\San Antonio, TX (1855,377,2462,405)
+\\San Bernardino, CA (605,1090,581,1108)
+\\San Diego, CA (340,827,597,898)
+\\Sandusky, OH (3537,2158,4041,2209)
+\\San Francisco, CA (-580,1605,70,1659)
+\\San Jos\'e, CA (147,1541,124,1593)
+\\Santa Ana, CA (-18,1004,525,1056)
+\\Santa Barbara, CA (-272,1175,342,1155)
+\\Santa Fe, NM (1224,1284,1717,1344)
+\\Santa Rosa, CA (-531,1729,40,1758)
+\\Sarasota, FL (3604,29,4059,93)
+\\Sault Sainte Marie, MI (3894,2969,3877,2965)
+\\Savannah, GA (4223,804,4203,804)
+\\Schenectady, NY (4942,2380,4917,2415)
+\\Scottsbluff, NB (1514,2292,1946,2272)
+\|Scranton, PA 1(4619,2245,4745,2203)
+\\Seattle, WA (-343,3143,79,3132)
+\\Sedalia, MO (2599,1720,2989,1798)
+\\Selma, AL (3630,786,3610,855)
+\\Seminole, OK (2416,1206,2644,1276)
+\\Sheridan, WY (1204,2733,1616,2712)
+\\Sherman, TX (2180,969,2651,1038)
+\\Shreveport, LA (2845,887,2937,868)
+\\Sioux City, IA (2185,2296,2673,2365)
+\\Sioux Falls, SD (2102,2535,2639,2523)
+\\South Bend, IN (3118,2210,3687,2244)
+\\Spokane, WA (579,3153,571,3142)
+\\Springfield, IL (2896,1977,3347,1962)
+\\Springfield, MA (5070,2256,5053,2307)
+\\Springfield, MO (2986,1507,2983,1575)
+\\Springfield, OH (3430,1990,3931,1980)
+\\Staunton, VA (4151,1644,4405,1714)
+\\Sterling, CO (1767,2105,1990,2085)
+\\Steubenville, OH (3646,2045,4250,2046)
+\\Stevens Point, WI (3288,2600,3355,2670)
+\\Stockton, CA (204,1658,183,1686)
+\\Stroudsburg, PA (4818,2111,4793,2140)
+\\Sumter, SC (4292,1007,4277,1080)
+\\Swainsboro, GA (4087,894,4078,882)
+\\Syracuse, NY (4300,2374,4697,2449)
+\\Tacoma, WA (-380,3019,69,3078)
+\\Tallahassee, FL (3334,502,3884,559)
+\\Tampa, FL (4070,202,4067,184)
+\\Terre Haute, IN (3008,1855,3571,1912)
+\\Texarkana, TX (2923,994,2907,1006)
+\\Toledo, OH (3743,2257,3958,2239)
+\\Topeka, KS (2380,1869,2745,1849)
+\\Toronto, ON (4065,2561,4374,2539)
+\\Traverse City, MI (3775,2682,3749,2706)
+\\Trenton, NJ (4859,1976,4835,2026)
+\\Trinidad, CO (1740,1501,1861,1567)
+\\Tucson, AZ (1018,755,1215,825)
+\\Tulsa, OK (2562,1436,2721,1416)
+\\Tupelo, MS (3037,1144,3441,1131)
+\\Tuscaloosa, AL (3560,986,3555,973)
+\\Twin Falls, ID (361,2393,865,2376)
+\\Tyler, TX (2417,816,2782,844)
+\|Uniontown, PA 1(4295,1986,4339,1977)
+\\Utica, NY (4807,2438,4789,2458)
+\\Valdosta, GA (3995,555,3984,616)
+\\Valley City, ND (2037,3050,2511,3030)
+\\Vancouver, BC (-257,3403,0,3382)
+\\Vicksburg, MS (2963,771,3224,844)
+\\Victoria, TX (2518,242,2611,313)
+\\Vincennes, IN (3575,1737,3559,1794)
+\\Waco, TX (2494,652,2598,724)
+\\Walla Walla, WA (370,2830,479,2902)
+\|Warren, PA .5(4285,2295,4398,2269)
+\\Washington, DC (4633,1807,4609,1825)
+\\Waterbury, CT (5027,2173,5007,2224)
+\\Waterloo, IA (2698,2383,3078,2367)
+\\Watertown, NY (4731,2571,4720,2589)
+\\Watertown, SD (2056,2701,2601,2727)
+\\Waukegan, IL (3180,2361,3529,2346)
+\\Wausau, WI (3363,2741,3348,2736)
+\\Waycross, GA (4087,675,4077,675)
+\\Weed, CA (-252,2225,73,2205)
+\\Wenatchee, WA (291,3040,280,3105)
+\\West Palm Beach, FL (4190,-70,4307,0)
+\|Wheeling, WV 1(3975,1935,4240,2002)
+\\Wichita, KS (2286,1575,2578,1645)
+\\Wichita Falls, TX (1909,1098,2463,1077)
+\|Williamson, WV .5(3650,1616,4084,1644)
+\|Williamsport, PA .5(4168,2192,4612,2179)
+\\Williston, ND (1471,3232,1950,3214)
+\\Wilmington, DE (4776,1899,4757,1954)
+\\Wilmington, NC (4521,1143,4520,1128)
+\|Winchester, VA 0(4135,1805,4496,1870)
+\\Winnipeg, MB (2347,3495,2597,3474)
+\\Winston-Salem, NC (3586,1354,4287,1407)
+\\Wisconsin Dells, WI (2769,2469,3335,2536)
+\\Worcester, MA (5140,2320,5132,2332)
+\\Yakima, WA (-11,2912,261,2982)
+\\Yankton, SD (2110,2410,2573,2424)
+\|Youngstown, OH 1(4262,2092,4247,2157)
+
+\nopagenumbers\bye
+
diff --git a/support/graphbase/david.dat b/support/graphbase/david.dat
new file mode 100644
index 0000000000..0fd32c9061
--- /dev/null
+++ b/support/graphbase/david.dat
@@ -0,0 +1,157 @@
+* File "david.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* David Copperfield, by Charles Dickens
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 152,151276216)
+AD Adams, head boy in DS's school
+AS Annie Strong, beautiful young wife of DS
+AW Agnes Wickfield, daughter of WW
+BA Mr. Barkis, willin' carrier
+BC Beauty Crewler, sister of ST
+BM Baby Murdstone, baby boy of CC and ED
+BT Betsey Trotwood, DC's paternal great-aunt
+CC Clara Copperfield, mother of DC
+CD Mr. Chillip, doctor at DC's birth
+CH Captain Hopkins, debtor with sonorous voice
+CK Mr. Creakle, proprietor of Salem House school
+CL Clicket (the Orfling), servant of WM
+CM Jack Maldon, ne'er-do-well cousin of AS
+CP Clara Peggotty, nurse to DC
+CR Mrs. Crupp, landlady to DC
+CS Miss Clarissa Spenlow, aunt of DO
+DB Richard Babley (Mr. Dick), weak-minded prot\'eg\'e of BT
+DC David Copperfield, our hero
+DL Mr. Dolloby, buyer of used clothing
+DM Miss Emma Micawber, daughter of WM and EM
+DO Dora Spenlow, daughter of FS
+DP Dan Peggotty, brother of CP
+DS Dr. Strong, schoolmaster at Dover
+DW Miss Mowcher, dwarf hairdresser
+ED Edward Murdstone, second husband of CC
+EM Mrs. Emma Micawber, sanguine wife of WM
+FG Mr. Grainger, friend of JS
+FM Mr. Markham, friend of JS
+FS Mr. Francis Spenlow, attorney
+GP Mr. Gulpidge, something to do with the law business
+GR Gregory, foreman of wine packers at Murdstone and Grinby
+GU Mrs. Gulpidge, dinner guest of FS
+HA Mrs. Henry Spiker, `Hamlet's Aunt'
+HC Rev. Horace Crewler, father of ST
+HP Ham Peggotty, nephew to CP and DP
+HS Mr. Henry Spiker, solicitor
+JK Mr. Jorkins, `hard-hearted' partner of FS
+JM Jane Murdstone, sister of ED
+JR Joram, partner of OM
+JS James Steerforth, schoolmate of DC
+JT Janet, maid to BT
+JU Julia Mills, bosom friend of DO
+KI Miss Kitt, creature in pink
+LA Miss Larkins, DC's older woman crush
+LC Mr. Chestle, `elderly' gentleman who marries LA
+LE Emily Peggotty (Little Em'ly), niece of DP
+LF Mr. Larkins, father of LA
+LM Littimer, valet to JS
+LS Miss Lavinia Spenlow, aunt of DO
+MC Mrs. Creakle, wife of CK
+ME Martha Endell, `fallen woman'
+MF Mrs. Fibbotson, old housemate of MM
+MG Mrs. Gummidge (Old Mawther), widow of DP's partner
+MH Mrs. Crewler, wife of HC
+MJ Master Wilkins Micawber Jr., son of WM and EM
+ML Charley Mell, teacher at Salem House
+MM Mrs. Mell, mother of ML
+MO Minnie Omer, daughter and seamstress to OM
+MP Mealy Potatoes, laborer at Murdstone and Grinby
+MS Mrs. Steerforth, mother of JS
+MW Mick Walker, laborer at Murdstone and Grinby
+OC Miss Creakle, daughter of CK
+OM Mr. Omer, haberdasher and funeral furnisher
+OS Mrs. Markleham (The Old Soldier), mother of AS
+PA Mary Anne Paragon, first servant of DC and DO
+PN Mr. Passnidge, friend of ED
+QU Mr. Quinion, manager of Murdstone and Grinby
+RD Rosa Dartle, companion to MS
+RW Red Whisker, rival for DO
+SA Miss Shepherd, adorable little girl
+SC Sarah Crewler, crippled sister of ST
+SH Mr. Sharp, headmaster at Salem House
+ST Sophy Crewler, fianc\'ee of TT
+TI Mr. Tiffey, clerk to FS
+TP Tipp, carman at Murdstone and Grinby
+TR Mr. Trotwood, husband left by BT
+TT Tommy Traddles, student at Salem House
+TU Mr. Tungay, one-legged guard at Salem House
+TW Micawber Twins, children of WM and EM
+UH Uriah Heep, articled to lawyer WW
+UM Mrs. Heep, 'umble mother of UH
+WA Mrs. Waterbrook, wife of WB
+WB Mr. Waterbrook, agent for WW
+WI William 1, friendly and hungry waiter
+WL William 2, coachman
+WM Wilkins Micawber, debtor who waits
+WW Mr. Wickfield, attorney at Dover
+
+1:CC,BT;BT,CP;HP,CP;BT,CD;HP,BT;CC,DC
+2:CC,DC,CP;DC,CP;DC,CP,ED;CP,CC;DC,ED;DC,ED,QU,PN;BA,DC,CP
+3:CP,DC;CP,HP,DC;CP,HP,DC,LE,MG,DP;LE,DC;MG,CP;DC,CC,ED;BA,DC,CP
+4:CC,CP,DC,ED;JM,DC,CC,ED;CC,ED,JM;DC,CC,JM,ED;DC,ED;CP,DC;JM,DC;BA,DC
+5:BA,DC,CP;BA,DC;DC,WI;DC,ML,MM,MF;TU,ML,DC
+6:DC,ML,TU;DC,TU,CK,MC,OC;TT,DC;JS,DC
+7:TU,CK;CK,DC;TT,JS,DC;DC,JS;MM,JS,TT,DC,CK,TU;TU,DC;DP,HP,DC,JS
+8:BA,DC;DC,CC,BM,CP;DC,CC,CP;DC,ED,JM;DC,JM,CC,BM;DC,ED,JM,CC;DC,CC,BM
+9:DC,SH;CK,MC,DC;OM,MO,DC,JR;DC,CP,CC,BM;ED,CD,DC,JM;MG,ED,CD,DC,JR,MO
+10:JM,CP,DC;DC,HP,DP,CP,BA;BA,CP,DP,MG,LE,DC,HP;DP,HP,LE,DC,MG;QU,DC,ED,JM
+11:DC,MW,MP;QU,DC,WM;DC,WM,TW,MJ,DM,EM,CL;GR,TP,DC;EM,DC;CH,DC;DC,CP,WM
+12:DC,EM,WM;WM,QU,TP,DC;DC,WM,EM,MJ,DM,CL;CP,DC;DC,MP
+13:DC,DL;DC,JT,BT,DB
+14:BT,JT,JM,ED,DC;BT,DC,JM,ED;BT,DC,JM,ED,DB;DB,DC,BT
+15:DC,DB,BT,JT;DC,BT,UH;DC,BT,WW;DC,BT,WW,AW
+16:WW,DC,DS,AS;AD,DC;CM,WW,DC,AW,UH;JM,DC,AS,DS,OS,WW,AW
+17:DC,CP;BT,DB,TR;DS,DC,DB;UH,DC,UM,WM;DC,WM,EM
+18:DC,SA;DC,AW;AD,DC;DC,LA;DC,LF;LC,DC
+19:DC,BT,DB;DC,AW;DC,AW,DS,AS,OS,WW;WL,DC;JS,DC
+20:DC,JS;MS,JS,DC,RD;MS,DC
+21:DC,MS,JS,RD,LM;DC,MO,OM;DC,CP,BA;DC,CP,JS;DC,JS,HP,LE,DP,MG
+22:DC,JS,MG;DC,JS,HP,LE;ME,LE,HP;DC,JS,LM;DC,JS,DW;DC,HP,LE,CP,ME
+23:DC,JS,LM;DC,BT,JT;BT,TR;DC,BT,FS;DC,FS;DC,BT,CR;DC,BT,TI
+24:DC,MS,RD;DC,JS;DC,CR;DC,JS,FG,FM;DC,AW
+25:DC,AW;DC,AW,WA;DC,WB,WA,HS,HA,UH,AW,TT,GP,GU;DC,UH
+26:DC,AW,UH;DC,FS;DC,DO,JM;DC,CR;DC,TI
+27:DC,TT;DC,TT,WM;DC,TT,WM,EM;DC,WM
+28:DC,CR;DC,TT,WM,EM;DC,TT,WM,EM,LM;DC,JS
+29:DC,FS;DC,RD,MS,JS;DC,RD;DC,RD,JS;DC,JS,MS;DC,JS
+30:DC,OM;DC,OM,MO,JR;DC,DP,CP,LE,HP;DC,CP,DP,BA
+31:DC,CP;DC,CP,MG,DP;DC,CP,MG,DP,HP;DC,HP;LE,LM,JS
+32:DC,HP,DP,MG;DC,MO;DC,DW;DC,HP,DP,MG,CP;DC,DP,RD,MS
+33:DC,CP,FS,ED;JM,ED;DC,DO,JU,FS,RW,KI;TI,DC,CP
+34:DC,AW;CR,DC;CP,TT;DC,TT;DC,CP,BT,DB,CR;DC,CP,BT,DB
+35:DC,DB,BT,CP;DC,FS;DC,JK;DC,TI;WW,UH,AW,UM;DC,AW,BT,WW,UH
+36:DC,DS;DC,DS,AS,CM;DC,DB,TT;DC,TT,DM,MJ,EM,WM
+37:BT,CR;BT,CP,DC;DC,DO;DC,DO,JU;DC,JU
+38:DC,TT,DB,BT;DC,FS,JM;DC,JU;DC,TI;DC,TI,JK;JU,DO;DO,LS,CS
+39:DC,BT;DC,JT;DC,WM;DC,AW,WW,UH,UM
+40:DC,BT,DB;DC,BT;DC,ME;DC,DP;DC,DP,ME;LE,MG
+41:DC,LS,CS;DC,BT,DB,TT;TT,HC,MH,BC,SC,ST;TT,DC,LS,CS;DC,DO;BT,LS,CS,DO
+42:DC,AW,LS,CS,DO;DC,WW,UH,DS;DC,DS,OS,AS;DB,DS;DB,AS;DC,BT;WM,EM
+43:DC,TT;DC,DO,BT,LS,CS;DC,AW,DO,BT,CP,LS,CS,TT,ST;DC,DO,LS;DC,DO
+44:DC,DO;DC,DO,PA;DC,BT;DC,DO,TT
+45:DC,DS,OS;DS,OS,AS;DC,BT,AS,OS;DC,BT,OS,DS,AS,DB;DC,BT,DB
+46:DC,RD;DC,RD,LM;LM,LE;DC,RD,MS;DC,DP;DC,DP,ME
+47:DC,DP,ME;BT,TR;DC,BT
+48:DC,DO;DC,DO,TT;DC,DO,BT
+49:DC,WM;DC,TT;TT,EM;DC,TT,WM;DC,TT,WM,BT,DB
+50:DC,DP;DP,ME;DC,ME;RD,LE,DC;DP,LE,DC
+51:DC,DP,BT;DC,DO;DC,OM;DC,DP,CP,MG;DC,HP;DC,DP,MG
+52:DC,BT,DO;DC,TT,BT,DB,WM,UH;DC,TT,BT,DB,WM,UH,AW,UM;DC,BT,WM,EM,DM,TW,MJ
+53:DC,DO,BT;DC,DO;DC,BT,DO,AW;DC,AW
+54:DC,AW,BT,WM,EM;DC,TT,BT,AW;DC,BT;DC,BT,TR;DC,BT,WM
+55:DC,CP,DP;DC,BT;DC,LE;DC,HP,JS
+56:DC,RD,MS
+57:DC,WM,EM,TW,MJ,DM,TT,AW,BT,CP,DP;DC,CP,DP;DP,ME,DC;DC,CP,MG;LE,AW;DC,LE
+58:DC,AW
+59:DC,TT,ST;DC,TT;DC,CD;DC,BT,CP,DB;ED,JM
+60:DC,BT;DC,AW;DC,AW,WW
+61:DC,TT,ST;DC,TT;DC,CK,TT;DC,CK,TT,UH,LM;LM,DW
+62:DC,BT;DC,AW;DC,BT,AW,DB,CP;DC,AW,TT,ST,DS,AS
+63:DC,AW,DP;DP,LE,ME,MG,WM,EM,MJ,DM,ML;DC,AW,DP,BT,CP
+64:DC,AW,BT,CP,DB;RD,MS;JU,CM;DS,AS,OS;DC,TT,ST;TT,HC,MC,BC;DC,AW
+* End of file "david.dat"
diff --git a/support/graphbase/econ.dat b/support/graphbase/econ.dat
new file mode 100644
index 0000000000..367699aa8a
--- /dev/null
+++ b/support/graphbase/econ.dat
@@ -0,0 +1,891 @@
+* File "econ.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* Input/Output structure of the US economy, 1985
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 886,303998716)
+Industry:
+Goods:
+Natural resources:
+Organic resources:
+Living resources:
+Agriculture:
+Livestock and livestock products:1
+Agriculture, excluding livestock:2
+Forestry and fishery products:3
+Fossil fuels:
+Coal mining:7
+Petroleum and natural gas production:8
+Inorganic resources:
+Mining of metals:
+Mining of ferrous metals:5
+Mining of nonferrous metals:6
+Mining of minerals:
+Quarrying of stone and clay:9
+Mining of chemicals:10
+Manufacturing:
+Organic products:
+Products from agriculture:
+Food and tobacco products:
+Food, liquor, and candy:14
+Cigarettes, cigars, tobacco:15
+Inedible products from agriculture:
+Textiles and leather:
+Textile manufacturing:
+Yard goods:
+Spinning and weaving:16
+Specialized textile products:17
+Fabricated textiles:
+Apparel:18
+Household textiles:19
+Leather manufacturing:
+Leather tanning and finishing:33
+Leather products:34
+Wood and paper:
+Wood manufacturing:
+Lumber and basic wood products:
+Lumber and wood, except containers:20
+Wood containers:21
+Furniture:
+Household furniture:22
+Office furniture and fixtures:23
+Paper manufacturing:
+Paper products:
+Paper products, except containers:24
+Paperboard containers and boxes:25
+Printing and publishing:26
+Organic chemical products:
+Rubber and plastics:
+Rubber products:32
+Plastics and synthetic materials:28
+Petrochemicals:
+Petroleum refining and byproducts:31
+Paints and allied products:30
+Inorganic products:
+General inorganic products:
+Metal products:
+Primary metal manufacturing:
+Primary iron and steel manufacturing:37
+Primary nonferrous metals manufacturing:38
+Metal equipment:
+Tools and parts:
+Screw machine products and stampings:41
+Metal products, not screws or stampings:42
+Metal fixtures:
+Architectural metalwork:40
+Metal containers:39
+Mineral and chemical products:
+Inorganic chemical products:
+Drugs and toiletries:29
+Fertilizers, glues, explosives, etc.:27
+Mineral products:
+Stone and clay products:36
+Glass and glass products:35
+Specialized manufactured goods:
+Specialized static equipment:
+Precision instruments:
+Scientific and controlling instruments:62
+Optical and photographic equipment:63
+Sundries (jewelry, games, etc.):64
+Specialized dynamic equipment:
+Vehicles and ordnance:
+Vehicles:
+Aircraft and parts:60
+Land and water vehicles:
+Motor vehicles and equipment:59
+Ships, trains, cycles, motor homes:61
+Ordnance and accessories:13
+Machinery and equipment:
+Electrical machinery and parts:
+Electrical parts:
+Electrical components:
+Electronic components and accessories:57
+Batteries and other electric supplies:58
+Electric lighting and wiring equipment:55
+Electrical equipment:
+Electrical apparatus:
+Radio, TV, and communication equipment:56
+Electrical appliances:
+Household appliances:54
+Office, computing, and accounting machines:51
+Industrial machinery:
+Electrical machines for service industries:52
+Electrical apparatus for manufacturing:53
+Non-electrical machinery and parts:
+Machine components:
+General industrial machinery equipment:49
+Engines and components:
+Engine parts:50
+Engines and turbines:43
+Non-electrical machinery:
+Outdoor machinery:
+Farm and garden machinery:44
+Construction and mining machinery:45
+Machinery for manufacturing:
+Materials handling machinery and equipment:46
+Industrial robots:
+Metalworking machinery and equipment:47
+Special industry machinery and equipment:48
+Services:
+Indirect services:
+Infrastructure:
+Construction:
+New construction:11
+Repair and maintenance construction:12
+Facilities:
+Transportation and communication:
+Transportation and warehousing:65
+Communications:
+Communications, except radio and TV:66
+Radio and television broadcasting:67
+Utilities:
+Private utilities:68
+Public utilities:
+Federal government enterprises:78
+Local government enterprises:79
+Economic services:
+Wholesale and retail trade:69
+Financial services:
+Banking and insurance:70
+Real estate and rental:71
+Direct services:
+Commercial services:
+Business support services:73
+Agricultural support services:4
+Personal services:
+Health, education, and social services:77
+Non-institutional personal service:
+Personal support services:
+Hotels, beauty care, etc.:72
+Automobile repair and services:75
+Recreational services:
+Eating and drinking places:74
+Amusements:76
+
+8490,2182,42,467,,,,,,
+,,,59639,,84,58,3,4,7
+,,1,15,3,4,79,7,107,
+,23,,,,,,,5,2
+7,1,,,,,,3,,
+,2,,1,,,,,,
+,,,5,2,,,1,,
+,3,19,545,,73,120,5,,
+
+16775,2871,66,460,,,,3,,
+,,,22546,3354,774,18,18,29,7
+,,1,9,1,2,143,54,119,2
+2,10,,,,3,,,6,1
+3,1,,,,,,2,,
+,1,,,,,,,,
+,1,,25,7,,,392,88,2
+28,39,42,1202,,1114,187,1731,1,
+
+,,281,26,,,,,,
+,,,1465,,1,1,343,2,4601
+5,3,4,44,1,,47,3,21,29
+1,8,,,1,1,,,,10
+,7,,,,1,1,1,,
+,,,,,1,,,2,
+1,2,,7,,,,5,5,
+,,,1112,,,23,22,,
+
+3106,4127,1232,304,,1,11,1,1,2
+1025,1972,1,223,,2,,1,,110
+,1,,4,1,1,235,13,5,1
+5,1,,,1,3,1,1,,1
+,2,1,,,,,,,
+1,,2,,1,3,2,,2,2
+1,,2,1,14,2,,36,1631,9
+3140,111,23,3,,169,258,2,8,
+
+,,,,184,1,,,,
+,,2,1,,,,,,1
+,,,1,1,1,135,6,2,9
+2,,,,,6,2452,17,,7
+6,65,,1,1,1,5,1,3,1
+1,,1,,4,,1,8,9,
+,,1,,,,,3,,
+,,,,,,,,,
+
+,,,,22,240,,,,
+,,,2,,,,,,
+,,,5,,1,504,26,8,20
+9,4,,,4,8,72,1720,1,26
+1,14,,,,,5,1,3,
+,,2,,1,1,3,36,7,1
+,7,2,2,,,,,,
+,,,,,,,,,1
+
+17,4,,,11,13,4458,8,16,2
+,,12,154,9,37,7,7,4,11
+1,6,1,332,6,6,346,136,26,1
+31,46,1,1,2,354,2477,36,,10
+13,75,1,4,6,2,8,1,6,3
+3,4,5,6,8,8,6,5,66,8
+2,3,11,5,148,,,11672,59,2
+110,,2,79,14,9,32,1234,304,1
+
+,,,,,,,5725,50,2
+,,,13,,7,8,,3,1
+,,,19,3,3,10216,1144,117,158
+99602,263,,1,4,62,29,3,41,1
+1,6,,1,1,,6,4,7,1
+,1,,,,,6,2,,
+,5,14,4,220,,,33012,,
+,,,,,,,,17,3
+
+2,236,3,6,15,3,,,189,8
+1917,1728,,19,,,2,,1,3
+,,,234,1,2,316,20,33,38
+401,43,,,281,1742,148,22,,8
+1,14,,,,,3,1,2,
+2,,1,,3,3,3,1,5,1
+,3,2,35,,,,,,
+,,2,,,1,2,,,
+
+,1,,,,,,2,1,75
+,,,26,,,,,,
+,,,45,,2,1632,80,26,8
+41,12,2,,6,97,48,3,,1
+,4,,,,,1,3,1,
+,14,,,,,4,1,1,
+,3,7,2,2,,,8,,
+1,,,,,,,,4,
+
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+
+207,497,355,123,19,9,146,4313,31,15
+594,211,68,867,14,113,34,102,29,177
+3,53,50,370,90,120,464,176,112,42
+758,244,4,12,65,316,614,179,46,276
+163,179,49,23,49,24,43,34,63,33
+406,41,97,47,37,139,196,34,209,148
+44,60,52,71,4790,5685,3,14571,2747,410
+24266,576,722,554,522,720,1298,584,3439,12
+
+,,18,,,,,,,
+23,1,1538,,,,,,,
+,,,,,,,,,
+,1,,,,59,20,,,13
+4,2,3,,,,2,6,,1
+,,4,,,104,2,,10,108
+21,1,1,1,2,,,1,5,2
+2,,120,,,,3,,,33
+
+11321,,104,255,,1,,7,1,
+10,3,1,50209,4,2,10,13,9,6
+,29,5,402,7,23,581,86,887,218
+47,43,453,19,1,26,6,5,5,8
+8,8,1,1,2,2,3,5,4,3
+11,4,5,3,1,8,12,3,5,8
+4,96,7,36,149,,1,379,583,15
+10,163,178,39923,3,568,4151,1630,1,1
+
+,,,,,,,,,
+,,,,3607,,,,,
+,,,1,,,,,,
+,,,,,,,,5,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+
+,15,,,,1,42,,1,4
+,,4,1,1,10645,2270,11372,4394,19
+,932,32,807,2,49,25,755,13,2
+3,957,,210,8,205,2,33,,5
+3,16,1,1,,1,5,13,4,1
+9,2,4,42,22,7,11,1,31,116
+12,370,7,394,4,,,3,1,
+1,212,39,1,,51,64,14,,4
+
+36,82,54,34,,,,,,
+1892,470,3,19,,234,769,147,1066,62
+,200,220,411,1,62,13,22,21,1
+25,938,,191,2,3,2,4,,4
+3,11,2,1,1,1,5,3,109,28
+5,2,7,2,2,4,6,5,315,3
+241,262,16,54,61,,,4,69,
+1,24,42,28,19,24,24,5,1,3
+
+,,,,,1,16,14,3,1
+38,11,15,17,2,39,105,9259,161,15
+,44,10,20,2,6,4,8,2,
+2,21,,20,6,8,12,4,1,6
+4,14,4,1,1,1,3,2,7,2
+6,2,5,2,2,37,42,1,20,15
+17,39,3,29,129,68,,21,118,
+10,526,74,,67,125,578,3,6,2
+
+,57,15,57,,,,,,
+87,72,2,73,,8,25,827,443,1
+,49,4,8,,2,36,4,4,2
+1,14,,1,2,1,8,5,,4
+54,7,6,2,3,2,5,1,4,2
+2,4,5,3,3,1,1,9,3364,108
+93,4,1,87,139,,,41,73,135
+8,636,25,97,,65,613,158,2,1
+
+11,12,,,5,22,112,,2,2
+20859,2899,31,39,3,5,16,1,30,14617
+177,1862,904,3542,11,26,113,25,15,1
+40,301,,42,139,211,96,118,16,120
+75,211,5,26,16,13,20,32,50,7
+24,57,38,74,37,51,23,5,218,41
+1138,59,8,494,39,,,128,986,
+7,128,30,25,,109,76,,,6
+
+4,173,2,15,,,,,,
+,,20,53,3,,,,,3
+3,8,4,2,,,,,,
+,5,,1,56,,7,14,,28
+20,3,,1,2,4,6,2,6,1
+,21,10,16,,21,1,,6,7
+,1,,5,,,,,21,
+,,,,,,,,,1
+
+,,,,,,,,,
+105,34,3,,,,,,,
+,32,2,,,,,,,
+,,,,,,,1,,1
+,1,,,,,,,,
+5,,3,,1,416,38,,1,16
+92,7,1,,,,,,,
+,2,,,,2,,,,6
+
+,,,,,,,,,
+783,187,1,,,,,,,1
+,,119,,,,,,,
+,1,,,,,3,1,,1
+4,1,1,,1,4,1,,1,
+1,1,1,34,1,,,2,528,28
+102,1,,,,,,,,
+,,,,,2,,,,
+
+159,66,2,14,,1,10,5,41,4
+958,500,10,3488,240,59,125,213,64,65
+,40,31,12052,8290,10266,837,426,432,21
+147,1073,,47,31,565,12,36,20,52
+112,75,23,4,4,12,15,14,70,8
+276,22,189,58,12,116,225,10,157,21
+17,318,578,435,139,73,1,135,4028,847
+133,252,7556,425,48,33,1911,95,15,19
+
+3,119,2,102,,,,3,4,
+9,4,39,6972,111,258,90,253,144,132
+34,164,179,1062,780,178,437,311,1051,83
+444,1040,10,81,510,174,60,91,41,190
+188,451,39,36,7,7,81,18,87,106
+252,145,130,246,227,201,211,102,143,18
+17,232,153,406,62,22,,18,1339,2
+1,80,216,979,1,1,157,35,,12
+
+19,30,1,10,1,1,10,20,8,2
+13,2,56,1863,195,22,19,83,37,35
+2,33,23,126,35,6089,193,31,198,65
+25,77,2,18,30,42,34,39,194,55
+40,71,13,10,17,14,32,26,34,29
+147,26,62,21,22,385,117,19,79,126
+35,103,40,77,551,336,3,313,3311,4261
+783,467,8369,223,33,124,8226,444,34,14
+
+189,6790,317,1732,63,126,499,592,118,69
+748,488,77,2403,27,807,580,112,106,919
+1,50,96,2225,504,1356,21439,12274,4730,2675
+4126,3656,116,56,726,910,1623,885,12,83
+168,915,6,10,16,8,135,194,45,12
+84,102,176,75,125,165,1070,427,388,73
+67,247,1527,435,223,18,1,1059,54,13
+361,215,1535,88,15,73,5200,11,177,26
+
+,,,,,,,1,3,
+,,42,81,1,5371,2944,1722,361,52
+4,88,31,1529,194,39,923,1563,179,632
+48,13586,,88,6,291,15,689,25,19
+70,162,2,4,3,6,41,18,32,6
+116,94,97,230,179,318,267,110,252,61
+166,236,167,654,,,,,,
+,,39,,,,,,,11
+
+197,,,3,,,,6,1,1
+94,45,2,1404,14,78,28,175,6,1
+,,,123,,2,483,162,3470,30
+625,31,35,18,,37,1,1,7,16
+14,16,,,,,1,1,2,2
+1,,,,,1,1,2,7,
+1,11,2,4,9,88,,32,193,10
+18,843,396,164,,6,8626,53,9,
+
+,,4,,,,,13,1,
+2897,2304,7,2,,3,5,,2,294
+,166,130,23,41,27,164,75,67,137
+10,59,,,25,76,28,44,253,157
+116,313,9,28,22,9,32,2,13,7
+82,59,70,140,42,52,10,26,651,80
+179,33,3,138,38,62,,2,,
+1,1,115,,642,1,22,2,,3
+
+1000,6006,344,652,66,76,729,395,234,47
+7670,3934,108,1474,56,271,117,282,50,654
+7,96,74,1862,254,335,2729,731,562,228
+10211,929,17,13,205,743,739,510,41,223
+89,253,83,21,43,59,124,84,199,69
+408,116,190,29,60,185,299,72,333,350
+135,196,156,190,17282,262,1,16722,9508,973
+967,693,2590,462,1635,332,3286,633,677,26
+
+375,490,11,90,37,52,242,28,68,8
+1332,1068,188,4014,424,431,525,331,527,410
+1,956,672,2053,61,510,907,888,2006,52
+260,4529,,465,83,236,117,396,28,416
+284,1311,82,299,294,122,151,218,306,42
+2099,462,535,878,469,2926,2642,471,7589,387
+396,1176,1315,934,1336,158,,176,1983,108
+505,661,1172,1687,193,159,3596,43,23,95
+
+,,,,,,,,,
+,,,,,3,1,260,162,2
+,61,5,2,,5,,,,
+,7,74,1188,,,,,,
+,2,,,,,1,,,
+,,,,,,,,,
+,1,,60,,,,,,
+,,6,,,,,1,,
+
+55,,,4,,,,2,,
+3,1,,5,,7,,7,2,9
+,,,1,1,2,7,1,1,1
+5,11,,474,5,,3,,,
+,1,,,,,,,,1
+2,,,,,2,1,,7,2
+,5,1,53,9,1,,9,147,19
+6,68,16,4,,23,40,30,1,
+
+8,,,3,,,,9,1,
+288,214,7,3940,,133,35,3,7,65
+,89,24,9,2,2,69,28,564,10
+49,572,,1,1118,38,9,23,1,414
+38,64,4,2,2,3,8,24,8,2
+39,19,33,103,453,101,522,21,1606,14
+184,141,223,23,20,4,,4,59,17
+5,198,58,219,383,1,317,2,1,6
+
+,149,2,19,3,24,132,17,40,1
+20842,5742,33,89,2,10,9,9,6,318
+2,73,52,142,13,21,165,47,27,86
+214,237,4,4,133,4489,450,167,7,93
+44,178,94,19,84,23,224,62,152,209
+144,108,178,99,54,103,442,32,502,117
+331,94,79,102,91,28,,94,122,5
+43,226,55,219,772,5,69,2,39,10
+
+8,10,,,47,84,126,466,43,15
+4855,1146,572,15,1,3,5,4,15,68
+3,300,1281,46,138,96,337,25,21,47
+44,625,,4,21,217,9272,475,2729,7095
+6600,4631,1234,868,1973,777,1446,833,2098,918
+473,1239,1360,1146,695,437,450,333,9978,1327
+1538,469,81,514,148,1,,38,15,2
+,3,45,,,,13,2,,105
+
+,,,,3,10,69,1,16,3
+3725,1033,457,8,,1,30,2,8,29
+,111,196,118,71,72,982,55,35,63
+17,169,,2,50,241,1100,14133,1548,3689
+1115,2276,461,109,97,153,402,295,660,442
+1115,1088,1454,582,729,1681,1896,1179,2604,2174
+505,672,429,906,90,110,,35,,
+,6,62,20,,6,,8,,85
+
+,,7,,,,,1,,
+,,,8858,1,,1,,1,
+,,,4,3,10,667,111,793,464
+402,8,,,,4,4,2,405,1
+16,12,,,,,1,1,1,
+,1,,,,,1,1,1,
+,15,3,2,,,,7,181,
+,,70,,,,,,,
+
+9,14,,,,,,46,21,5
+22247,7495,9,1,,,,,1,126
+,1,2,1,1,,7,1,13,
+2,68,,,1,13,5,5,,713
+4,24,157,4,246,99,94,127,163,3
+43,138,92,5,3,501,81,23,37,99
+1233,51,21,6,,,,4,28,
+177,,,,,,7,4,1,18
+
+36,,,1,10,17,257,,15,7
+144,62,124,636,,1,2,3,5,410
+1,87,207,14,3,6,37,4,177,18
+2,216,,17,29,22,212,138,8,1069
+1037,588,287,195,104,85,138,87,297,94
+1265,450,429,332,366,686,976,244,12408,601
+223,514,216,122,83,131,,101,2,
+2,27,106,387,2961,17,201,62,3,39
+
+140,239,31,42,43,41,179,499,69,7
+6757,3358,212,951,90,8,7,36,8,1148
+4,813,530,509,107,123,296,65,373,50
+324,422,,56,17,409,560,458,137,1374
+548,1717,189,116,198,139,184,245,319,238
+969,463,313,391,286,1004,1214,496,3671,554
+394,473,232,334,619,55,,240,477,23
+14,153,404,95,2016,27,249,17,4,48
+
+,,18,51,28,28,221,216,57,20
+,,57,,,,,,1,2
+,1,3,1,3,,14,,,
+10,25,,,,7,33,3,,28
+15,77,1443,871,566,116,14,109,155,53
+5,69,149,5,3,8,3,5,1617,17
+974,8,,5,274,215,,1501,1,
+6,,138,1,78,,,11,15,34
+
+385,882,19,75,,,,,,
+,,,30,,,,,,2
+,,,,1,,1,,,
+,,,,,,3,,,2
+1,3,2,356,11,1,1,1,1,
+,,,,,,,,1,1
+3,,,,19,,,77,19,
+90,,309,,2,4,,,39,
+
+,,,,48,61,805,113,140,22
+432,50,,,,,,,,5
+,,,,,,9,,,
+6,1,,,,134,3,,,3
+,9,11,2,566,11,1,1,7,1
+,,2,,,1,,,18,
+46,2,,,,,,7,,
+2,,261,,,,1,2,,5
+
+,,,,18,13,119,,45,4
+1221,475,2,3,1,32,,3,1,17
+,,1,,,,2,2,,
+,6,,,,5,12,12,,2
+1,1,,1,2,345,2,10,4,1
+1,,1,,,,,,23,
+4,1,,,8,,,10,134,
+2,,229,,,,,3,,3
+
+,,,3,2,3,5,35,7,
+57,19,124,46,3,15,8,14,7,113
+1,14,48,34,78,15,33,13,18,2
+10,206,1,7,51,33,370,499,50,220
+394,322,188,67,124,67,937,163,308,285
+316,173,188,62,102,246,252,109,482,618
+113,135,30,37,83,2,,37,73,
+3,,183,,13,1,,5,6,23
+
+,,,,,,,1,,
+,,1,156,,166,129,85,16,43
+1,10,1,295,101,322,595,53,10,2
+11,185,,3,72,6,56,23,,3
+3,20,,1,1,2,4,380,5,
+5,2,1,,,1,3,1,2,
+5,3,4,18,,,,,21,
+1,,341,92,,,,,,7
+
+21,28,9,11,40,30,442,340,72,12
+1367,221,184,123,21,1,2,6,3,46
+,13,76,155,2,9,349,180,141,6
+201,77,,1,14,98,700,430,7,384
+65,144,357,469,1082,556,383,567,2087,230
+113,614,139,101,15,377,54,113,1170,478
+637,58,82,65,526,92,,188,25,25
+19,,773,1,43,,,15,3,46
+
+57,89,2,9,5,16,119,203,33,5
+206,76,156,165,3,52,26,46,17,127
+3,29,51,96,42,33,80,37,31,11
+36,290,2,14,65,88,349,225,38,252
+1071,329,451,207,122,149,504,397,474,1382
+265,311,175,58,56,373,236,79,1860,759
+303,189,61,71,272,25,,223,424,
+33,40,181,297,780,6,20,24,81,34
+
+,,,1,,,,,,
+,,10,8,1,2,1,2,3,1
+,1,11,10,,31,12,2,5,
+2,16,,,1,2,12,2,,10
+12,27,3,1,3,5,7,5,19,4
+9408,3,46,6,7,335,375,12,7,31
+4,67,31,6,10,,,6,177,31
+14,788,546,10,2,10,35,9,,72
+
+,,,,,,,,,
+4047,1852,2,61,,,,,1,21
+,,2,1,,,86,4,3,1
+2,2,,,,1,6,6,1,96
+15,9,3,2,2,2,3,8,11,1
+3,992,5,262,3,13,1,7,1932,3
+117,4,,24,11,,,11,387,
+2,38,38,295,735,29,24,16,4,1
+
+12,13,,1,6,13,118,334,28,7
+2365,870,140,2,,,1,,2,30
+,2,47,7,1,5,56,2,10,1
+15,23,,,28,18,474,199,2,331
+66,206,146,80,186,244,356,480,780,73
+2382,1267,2076,705,250,692,351,221,368,135
+204,410,85,89,267,,,525,12,1
+53,21,269,,152,4,,1,162,53
+
+,,,,,,,1,,
+1052,544,1,,,,,43,,
+,,,,,,,,,
+,,,,9,,,,,2
+3,,1,,,,,,1,
+,3,1,140,,,,,2,1
+203,,,,24,,,30,36,53
+55,633,78,1,1,,28,9,14,
+
+6,6,1,6,,2,36,31,3,1
+5440,1911,12,25,,5,2,6,2,25
+,4,7,9,2,7,10,3,6,1
+14,106,,1,18,47,17,25,1,20
+45,15,5,32,4,3,34,4,9,4
+258,154,247,262,389,725,212,137,1163,11
+262,93,44,51,94,25,,268,104,42
+92,39,243,99,308,38,327,32,28,14
+
+,,,,,,1,5,,
+1446,464,1497,3,,,,1,,1
+,2,3,2,1,6,1,1,1,
+,8,,,1,1,5,7,,19
+12,16,20,1,4,3,6,11,9,2
+42,5,31,1,7,3314,86,3,798,2469
+201,24,9,11,76,2091,2,13,95,32
+1,35,71,3,82,6,81,11,2,84
+
+,,,,,,,,,
+,,528,,,14,3,1,3,2
+,8,9,18,,17,36,7,18,1
+,82,,1,3,9,12,58,,30
+25,74,20,1,8,7,30,69,93,15
+6515,8,953,12,329,15400,9168,743,465,1548
+23,1009,1678,127,74,727,28,16,18,96
+19,915,2002,,,,214,2,6,300
+
+94,448,7,49,,4,11,12,6,1
+308,96,12,12,,1,,4,1,15
+,,2,6,1,7,4,,6,1
+2,16,,,1,3,12,22,,8
+24,14,207,87,7,10,8,2,6,94
+42,5,23,4,312,42,19,680,3356,168
+79,26,21,10,84,15,,31,173,27
+90,12,147,15,609,4,554,14,10,6
+
+59,71,6,73,38,5,8,8,46,2
+315,137,52,18,1,2,,13,9,54
+,2,32,25,4,12,15,2,7,15
+136,39,,,1,88,101,58,2,75
+373,85,156,189,244,26,59,20,37,44
+32,58,74,35,39,99,9,132,48021,57
+739,34,4,13,438,251,,123,568,48
+39,19,196,28,10344,37,99,72,33,10
+
+,,,9,,,,,,
+,,2244,,1,,,,,
+,,4,,,9,,,,
+1,20,,,,2,9,2,,33
+22,29,74,3,14,10,14,21,29,52
+55,14,77,,12,209,31,,55,10609
+111,33,2,12,1991,,,31,,
+1,,2,,,,,,,78
+
+,,563,14,1,3,,,,
+4,,2,,,,,,1,3
+,,1,,,,,,,
+,,,,,,4,,,3
+1,1,3,1,2,,1,,2,
+,,4,,,,1,,47,1
+952,,,10,1412,12,,108,3,70
+15,7,397,1,15,256,15,22,35,1
+
+,,3,1,,2,16,41,2,
+1158,506,17,58,3,10,2,10,4,15
+1,8,6,37,5,7,99,28,57,2
+36,78,,3,26,13,94,40,2,78
+16,27,6,3,4,4,27,7,54,7
+62,255,43,386,7,135,27,13,360,458
+65,447,34,11,54,6,,173,121,7
+4,35,72,,18,,3687,5,3,9
+
+,,1,8,,,1,4,1,
+19,7,60,17,1,4,5,8,1,8
+,2,2,22,6,618,22,5,14,1
+7,21,,,6,14,11,4,3,11
+8,18,9,2,5,4,9,9,13,10
+56,9,26,3,16,199,66,9,25,290
+13,28,848,18,51,24,18,75,327,248
+91,566,2373,7,3,181,1201,21,7,12
+
+9,14,,7,3,1,6,7,5,1
+590,196,9,20,1,8,2,867,40,12
+,22,2,8,3,110,14,3,25,6
+2,32,,77,1,25,8,6,1,25
+5,18,1,1,8,5,5,3,5,3
+52,38,17,83,3,25,18,2,46,13
+34,30,6,1011,107,54,,91,742,326
+91,902,679,198,19,110,689,111,17,3
+
+1315,975,105,486,58,58,275,369,107,26
+6625,2280,388,6714,126,300,316,504,160,1073
+13,317,270,2273,768,1533,4136,1025,1127,400
+7634,1821,30,96,450,2781,1844,1593,293,751
+531,752,173,145,204,87,252,191,350,276
+1277,329,487,222,274,964,1218,407,1650,1238
+358,378,538,629,31372,555,16,4809,14477,2836
+774,461,6962,2493,2183,773,4995,3892,216,72
+
+207,312,11,15,2,4,26,94,13,2
+1401,693,118,659,12,160,30,510,54,84
+2,87,64,170,53,696,237,68,195,27
+234,213,2,33,43,126,71,91,12,173
+180,198,37,21,83,30,65,80,155,77
+427,77,132,40,45,463,324,43,106,334
+87,172,158,188,1914,1999,10,779,10089,5704
+1142,1176,7161,826,910,440,4101,250,44,21
+
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,,,,8
+,,,,,,,,,
+,,,,,,,,,
+,,,,,,12,,,
+3,,531,,,,,,,
+
+797,2774,80,372,408,296,840,1710,560,360
+1609,613,447,5913,88,1205,419,715,228,1274
+13,237,276,4204,374,792,7755,1849,841,145
+5131,2441,34,69,1278,2597,4220,2828,239,651
+658,1194,174,136,235,101,365,207,415,321
+928,295,517,311,252,962,1359,330,1767,986
+334,441,340,396,4173,1383,17,51703,20996,4133
+7732,4586,4196,4927,1588,1466,8982,759,3442,54
+
+2513,4120,392,1253,106,122,994,616,227,47
+26087,9600,475,17260,199,1371,624,2240,738,2509
+35,830,626,4088,440,2443,3873,1461,2114,496
+2718,2547,86,222,558,1221,2701,2948,477,1960
+1239,1787,578,711,1042,447,657,706,1127,406
+3086,1253,1600,864,843,3421,3198,800,7188,1384
+1377,1231,896,1525,5404,471,7,3136,10189,1044
+1609,1560,4898,8768,11095,513,6175,560,221,151
+
+1478,1518,76,260,19,53,271,560,102,102
+2501,633,120,1889,145,212,81,550,159,397
+12,318,296,363,66,650,938,178,551,80
+1337,498,7,129,122,380,317,379,76,297
+284,421,88,38,87,44,137,128,178,272
+962,92,364,139,202,516,710,251,683,1058
+147,216,382,324,3831,1353,16,2096,10827,65279
+14742,2034,4833,3799,520,646,3105,115,65,33
+
+1676,10760,139,1030,45,70,904,9422,228,40
+1012,396,183,1472,59,130,72,587,194,268
+6,179,176,408,137,1317,883,357,1173,85
+857,806,4,62,207,382,273,260,90,380
+206,359,58,62,71,68,169,108,210,223
+867,114,357,68,114,3645,664,195,345,459
+524,344,247,492,3650,2457,87,2100,36419,8924
+49610,4210,14526,6373,1963,2822,38336,1212,151,76
+
+132,154,16,42,3,7,34,70,49,8
+475,123,61,830,12,54,26,202,72,91
+3,59,48,261,30,453,236,92,182,44
+75,158,15,37,35,85,115,103,33,245
+73,123,26,12,25,17,45,36,66,59
+1199,63,145,53,89,559,537,106,136,872
+50,85,124,88,600,263,12,417,3351,1754
+212,1279,3770,969,220,474,2582,130,37,24
+
+374,2040,154,637,87,107,1084,1449,329,92
+46412,3386,1067,12160,1268,1448,418,1806,463,1036
+26,842,925,2144,380,4572,4129,1539,9796,499
+3114,2360,28,337,452,1305,1200,1125,224,1297
+1060,1524,323,203,446,240,573,417,838,1223
+3585,637,938,878,541,4241,2842,549,4116,3290
+680,1330,1552,1529,10966,4755,80,3737,82453,30351
+13701,5919,39370,8619,3355,5151,25392,1425,325,173
+
+14,20,43,120,4,10,41,425,27,13
+190,61,190,712,24,137,43,245,66,155
+5,87,76,185,75,1262,526,178,637,82
+342,406,3,43,62,206,122,155,56,218
+102,212,45,28,61,39,113,74,205,116
+779,92,185,71,92,650,673,99,211,1167
+89,249,297,163,2202,384,20,517,11535,2594
+1466,556,5472,278,197,552,3557,148,111,32
+
+249,297,46,276,37,64,210,239,50,22
+950,178,32,695,39,65,30,142,36,245
+3,100,95,218,75,288,141,132,110,33
+137,177,2,18,68,181,60,120,24,125
+135,130,46,10,20,33,72,26,73,88
+148,25,58,26,30,113,256,56,4928,146
+56,262,96,80,4511,259,1,545,11956,1009
+424,687,3752,317,429,682,2597,388,33,12
+
+,,,352,,,2,8,3,1
+2,1,1,7,2,,,4,,1
+,18,8,5,1,16,12,2,10,1
+3,6,,,2,1,1,3,1,11
+1,3,2,,1,2,2,,8,1
+4,,2,,1,14,39,31,28,32
+27,33,22,11,82,6,343,26,1565,5
+3,31,4806,1706,,6802,822,50,,1
+
+596,44,19,44,5,9,47,58,10,3
+10,5,14,155,11,48,4,44,66,80
+3,43,25,62,5,149,134,52,274,16
+118,173,1,4,11,39,14,37,12,42
+68,43,7,4,5,4,25,8,32,34
+60,23,17,17,12,115,125,9,207,124
+13,81,121,88,445,152,5,317,886,1294
+253,680,1936,366,59,323,6960,30,17,5
+
+10,15,8,81,3,8,15,23,8,7
+236,72,23,447,50,60,35,292,45,50
+2,45,50,100,33,1183,113,30,144,33
+113,95,3,58,29,61,72,52,5,73
+39,77,16,18,21,18,22,36,55,28
+117,15,58,58,28,369,131,16,224,239
+33,80,52,110,333,426,2,829,3763,7195
+1425,286,3667,291,55,104,2381,618,39,11
+
+,,4,33,1,3,5,11,11,2
+136,40,9,308,5,22,12,15,1,11
+,5,3,82,8,20,49,13,30,
+51,20,6,1,6,15,19,17,5,12
+10,24,3,2,4,2,7,3,7,5
+29,6,8,5,5,20,28,8,44,16
+4,12,9,10,212,107,2,57,515,80
+109,121,146,153,84,24,278,31,3,1
+
+1,7,4,5,13,75,39,513,14,12
+1,,14,4353,5,74,278,69,98,20
+,26,7,1071,23,45,895,134,560,70
+826,959,1,1,183,115,1184,2807,10,114
+45,162,76,72,114,23,140,67,65,16
+270,12,163,55,54,473,142,86,1360,81
+14,135,93,905,7080,2598,1,341,1649,2544
+34,96,1139,126,142,129,65,856,1,21
+
+20358,41531,3706,10213,1118,860,12999,94659,4147,920
+156635,67036,11870,74833,14205,8379,3231,19409,4403,17496
+180,5740,7022,24423,8988,33375,29925,9466,23680,3645
+34479,26857,776,2432,6524,17896,26394,13890,4852,16649
+14164,21872,7167,4945,9244,3139,12495,7637,11631,10223
+17064,7738,17112,5474,7580,24778,9758,7457,57221,34493
+12227,14622,9679,10959,132337,79652,966,147758,475550,165728
+517420,61039,322773,84779,48837,25330,256578,16653,5065,455017
+* End of file "econ.dat"
diff --git a/support/graphbase/econ_order.w b/support/graphbase/econ_order.w
new file mode 100644
index 0000000000..b581e0bcdf
--- /dev/null
+++ b/support/graphbase/econ_order.w
@@ -0,0 +1,289 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{ECON\_\thinspace ORDER}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+
+\prerequisite{GB\_\thinspace ECON}
+@* Near-triangular ordering.
+This demonstration program takes a matrix
+constructed by the |gb_econ| module and permutes the economic sectors
+so that the first sectors of the ordering tend to be producers of
+primary materials for other industries, while the last sectors
+tend to be final-product
+industries that deliver their output mostly to end users.
+
+More precisely, suppose the rows of the matrix represent the outputs
+of a sector and the columns represent the inputs. This program attempts
+to find a permutation of rows and columns that minimizes the sum of
+the elements below the main diagonal. (If this sum were zero, the
+matrix would be upper triangular; each supplier of a sector would precede
+it in the ordering, while each customer of that sector would follow it.)
+
+The general problem of finding a minimizing permutation is NP-complete;
+it includes, as a very special case, the {\sc FEEDBACK ARC SET} problem
+discussed in Karp's classic paper [{\sl Complexity of Computer
+Computations} (Plenum Press, 1972), 85--103].
+Here we use a simple heuristic downhill method
+to find a permutation that is locally optimum, in the sense that
+the below-diagonal sum does not decrease if any individual
+sector is moved to another position while preserving the relative order
+of the other sectors. We start with a random permutation and repeatedly
+improve it, choosing the improvement that gives the least positive
+gain at each step. One of the main motives for the present implementation
+was to get further experience with this method of cautious descent, which
+was proposed by A. M. Gleason in {\sl AMS Proceedings of Symposia in Applied
+Mathematics\/ \bf10} (1958), 175--178. (See the comments below.)
+
+@ As explained in |gb_econ|, the subroutine call |econ(n,2,0,s)|
+constructs a graph whose |n<=79| vertices represent sectors of the
+U.S. economy, and whose arcs $u\to v$ are assigned numbers corresponding to the
+flow of products from sector~|u| to sector~|v|. When |n<79|, the
+|n| sectors are obtained from a basic set of 79 sectors by
+combining related commodities; if |s=0|, the combination is done in
+a way that tends to equalize the row sums, while if |s>0| the combination
+is done by choosing a random subtree of a given 79-leaf tree (where the
+``randomness'' is fully determined by the value of~|s|).
+
+This program uses two random number seeds, one for |econ| and one
+for choosing the random initial permutation. The former is called~|s|
+and the latter is called~|t|. A further parameter, |r|, governs the
+number of repetitions to be made, trying different starting permutations
+on the same matrix. When |r>1|, new solutions are displayed only when
+they improve on the previous best.
+
+By default, |n=79|, |r=1|, and |s=t=0|. The user can change these
+default parameters by specifying options
+on the command line, at least in a \UNIX\ implementation, thereby
+obtaining a variety of special effects; the relevant
+command-line options are \.{-n}\<number>, \.{-r}\<number>,
+\.{-s}\<number>, and/or \.{-t}\<number>. Additional options
+\.{-v} (verbose), \.{-V} (extreme verbosity), and \.{-g}
+(greedy or steepest descent instead of cautious descent) are also provided.
+@^UNIX dependencies@>
+
+Here is the overall layout of this \Cee\ program:
+
+@p
+#include "gb_graph.h" /* the GraphBase data structures */
+#include "gb_flip.h" /* the random number generator */
+#include "gb_econ.h" /* the |econ| routine */
+@#
+@<Global variables@>@;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{@+unsigned n=79; /* the desired number of sectors */
+ long s=0; /* random |seed| for |econ| */
+ long t=0; /* random |seed| for initial permutation */
+ unsigned r=1; /* the number of repetitions */
+ long greedy=0; /* should we use steepest descent? */
+ register int j,k; /* all-purpose indices */
+ @<Scan the command line options@>;
+ g=econ(n,2,0,s);
+ if (g==NULL) {
+ fprintf(stderr,"Sorry, can't create the matrix! (error code %d)\n",
+ panic_code);
+ return -1;
+ }
+ printf("Ordering the sectors of %s, using seed %ld:\n",g->id,t);
+ printf(" (%s descent method)\n",greedy?"Steepest":"Cautious");
+ @<Put the graph data into matrix form@>;
+ @<Print an obvious lower bound@>;
+ gb_init_rand(t);
+ while (r--)
+ @<Find a locally optimum permutation and report the below-diagonal sum@>;
+}
+
+@ Besides the matrix $M$ of input/output coefficients, we will find it
+convenient to use the matrix $\Delta$, where $\Delta_{jk}=M_{jk}-M_{kj}$.
+
+@d INF 0x7fffffff /* infinity (or darn near) */
+@f Vertex int /* |gb_graph| defines these data types */
+@f Arc int
+@f Graph int
+
+@<Global...@>=
+Graph *g; /* the graph we will work on */
+long mat[79][79]; /* the corresponding matrix */
+long del[79][79]; /* skew-symmetric differences */
+long best_score=INF; /* the smallest below-diagonal sum we've seen so far */
+
+@ @<Scan the command line options@>=
+while (--argc) {
+@^UNIX dependencies@>
+ if (sscanf(argv[argc],"-n%u",&n)==1) ;
+ else if (sscanf(argv[argc],"-r%u",&r)==1) ;
+ else if (sscanf(argv[argc],"-s%ld",&s)==1) ;
+ else if (sscanf(argv[argc],"-t%ld",&t)==1) ;
+ else if (strcmp(argv[argc],"-v")==0) verbose=1;
+ else if (strcmp(argv[argc],"-V")==0) verbose=2;
+ else if (strcmp(argv[argc],"-g")==0) greedy=1;
+ else {
+ fprintf(stderr,"Usage: %s [-nN][-rN][-sN][-tN][-g][-v][-V]\n",argv[0]);
+ return -2;
+ }
+}
+
+@ @<Put the graph data into matrix form@>=
+{@+register Vertex *v;
+ register Arc *a;
+ n=g->n;
+ for (v=g->vertices;v<g->vertices+n;v++)
+ for (a=v->arcs;a;a=a->next)
+ mat[v-g->vertices][a->tip-g->vertices]=a->flow;
+ for (j=0;j<n;j++)
+ for (k=0;k<n;k++)
+ del[j][k]=mat[j][k]-mat[k][j];
+}
+
+@ The optimum permutation is a function only of the $\Delta$ matrix, because
+we can subtract any constant from both $M_{jk}$ and $M_{kj}$ without changing
+the basic problem. More sophisticated lower bounds than the trivial one
+computed here can be obtained by considering groups of three vertices
+instead of two.
+
+@<Print an obvious lower bound@>=
+{@+register long s=0;
+ for (j=1;j<n;j++)
+ for (k=0;k<j;k++)
+ if (mat[j][k]<=mat[k][j]) s+=mat[j][k];
+ else s+=mat[k][j];
+ printf("(The amount of feed-forward must be at least %d.)\n",s);
+}
+
+@* Descent.
+At each stage in our search, |mapping| will be the current permutation;
+in other words, the sector in row and column~|k| will be
+|g->vertices+mapping[k]|. The current below-diagonal sum will be
+the value of |score|. We will not actually have to permute anything
+inside of |mat|.
+
+@d sec_name(k) (g->vertices+mapping[k])->name
+
+@<Glob...@>=
+int mapping[79]; /* current permutation */
+long score; /* current sum of elements above main diagonal */
+long steps; /* the number of iterations so far */
+
+@ @<Find a locally optimum perm...@>=
+{
+ @<Initialize |mapping| to a random permutation@>;
+ while(1) {
+ @<Figure out the next move to make; |break| if at local optimum@>;
+ if (verbose) printf("%8d after step %d\n",score,steps);
+ else if (steps%1000==0 && steps>0) {
+ putchar('.');
+ fflush(stdout); /* progress report */
+ }
+ @<Take the next step@>;
+ }
+ printf("\n%s is %d, found after %d step%s.\n",@|
+ best_score==INF?"Local minimum feed-forward":"Another local minimum",@|
+ score,steps,steps==1?"":"s");
+ if (verbose || score<best_score) {
+ printf("The corresponding economic order is:\n");
+ for (k=0;k<n;k++) printf(" %s\n",sec_name(k));
+ if (score<best_score) best_score=score;
+ }
+}
+
+@ @<Initialize |mapping| to a random permutation@>=
+steps=score=0;
+for (k=0; k<n; k++) {
+ j=gb_unif_rand(k+1);
+ mapping[k]=mapping[j];
+ mapping[j]=k;
+}
+for (j=1; j<n; j++) for (k=0;k<j;k++) score+=mat[mapping[j]][mapping[k]];
+if (verbose>1) {
+ printf("\nInitial permutation:\n");
+ for (k=0;k<n;k++) printf(" %s\n",sec_name(k));
+}
+
+@ If we move, say, |mapping[5]| to |mapping[3]| and shift the previous
+entries |mapping[3]| and |mapping[4]| right one, the score decreases by
+|del[mapping[5]][mapping[3]]+del[mapping[5]][mapping[4]]|.
+
+Similarly, if we move |mapping[5]| to |mapping[7]| and shift the previous
+entries |mapping[6]| and |mapping[7]| left one, the score decreases by
+|del[mapping[6]][mapping[5]]+del[mapping[7]][mapping[5]]|.
+
+The number of possible moves is $(n-1)^2$. Our job is to find the
+one that makes the score decrease, but by as little as possible (or, if
+|greedy!=0|, to make the score decrease as much as possible).
+
+@<Figure out the next move to make; |break| if at local optimum@>=
+best_d=greedy? 0: INF;
+best_k=-1;
+for (k=0;k<n;k++) {@+register int d=0;
+ for (j=k-1;j>=0;j--) {
+ d+=del[mapping[k]][mapping[j]];
+ @<Record the move from |k| to |j|, if |d| is better than |best_d|@>;
+ }
+ d=0;
+ for (j=k+1;j<n;j++) {
+ d+=del[mapping[j]][mapping[k]];
+ @<Record the move...@>;
+ }
+ }
+if (best_k<0) break;
+
+@ @<Record the move...@>=
+if (d>0 && (greedy? d>best_d: d<best_d)) {
+ best_k=k;
+ best_j=j;
+ best_d=d;
+}
+
+@ @<Glob...@>=
+long best_d; /* best improvement seen so far on this step */
+int best_k,best_j; /* moving |best_k| to |best_j| improves by |best_d| */
+
+@ @<Take the next step@>=
+if (verbose>1)
+ printf("Now move %s to the %s, past\n",sec_name(best_k),
+ best_j<best_k? "left": "right");
+j=best_k;
+k=mapping[j];
+do@+{
+ if (best_j<best_k) mapping[j]=mapping[--j];
+ else mapping[j]=mapping[++j];
+ if (verbose>1) printf(" %s (%d)\n",sec_name(j),@|
+ best_j<best_k?del[mapping[j],mapping[best_k]]:
+ del[mapping[best_k],mapping[j]]);
+}@+while(j!=best_j);
+mapping[j]=k;
+score-=best_d;
+steps++;
+
+@* Comments.
+How well does cautious descent work? In this application, it
+is definitely too cautious. For example, after lots of computation with the
+default settings, it comes up
+with a pretty good value (457342), but only after taking 39418 steps!
+Then (if |r>1|) it tries again and stops with 461584 after 47634 steps.
+The greedy algorithm with the same starting permutations obtains the
+local minimum 457408 after only 93 steps, then 460411 after 83 steps.
+The greedy algorithm tends to find solutions that are a bit inferior,
+but it is so much faster that it allows us to run many
+more experiments. After 20 trials with the default settings it finds
+a permutation with only 456315 below the diagonal,
+and after about 250 more it reduces this upper bound to 456295.
+
+The method of stratified greed, which is illustrated in the |football|
+module, should do better; and it would be interesting to compare it
+to other methods like simulated annealing and genetic breeding.
+Comparisons should be made by seeing which method can come up with
+the best upper bound after calculating for a given number of mems
+(see |miles_span|). The upper bound obtained in any run is a random
+variable, so several independent trials of each method should be made.
+
+Question: Suppose we divide the vertices into two subsets and prescribe
+a fixed permutation on each subset. Is it NP-complete to find the
+optimum way to merge these two permutations---i.e., to find a
+permutation, extending the given ones, that has the smallest
+below-diagonal sum?
+
+@* Index. We close with a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/football.w b/support/graphbase/football.w
new file mode 100644
index 0000000000..0a40d539e4
--- /dev/null
+++ b/support/graphbase/football.w
@@ -0,0 +1,620 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{FOOTBALL}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GAMES}
+@* Introduction. This demonstration program uses graphs
+constructed by the |gb_games| module to produce
+an interactive program called \.{football}, which finds preposterously
+long chains of scores to ``prove'' that one given team might outrank another
+by a huge margin.
+
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+The program will prompt you for a starting team. If you simply type \<return>,
+it exits; otherwise you should enter a team name (e.g., `\.{Stanford}')
+before typing \<return>.
+
+Then the program will prompt you for another team. If you simply type
+\<return> at this point, it will go back and ask for a new starting team;
+otherwise you should specify another name (e.g., `\.{Harvard}').
+
+Then the program will find and display a chain from the starting team
+to the other one. For example, you might see
+$$\vbox{\halign{\tt#\hfil\cr
+ Sep 06: Stanford Cardinal 17, Colorado Buffaloes 21 (-4)\cr
+ Nov 17: Colorado Buffaloes 64, Kansas State Wildcats 3 (+57)\cr
+ Sep 29: Kansas State Wildcats 38, New Mexico Lobos 6 (+89)\cr
+ Sep 22: New Mexico Lobos 32, Texas Tech Red Raiders 34 (+87)\cr
+ Nov 17: Texas Tech Red Raiders 62, Southern Methodist Mustangs 7 (+142)\cr
+ Sep 08: Southern Methodist Mustangs 44, Vanderbilt Commodores 7 (+179)\cr
+\omit\qquad\vdots\cr
+ Nov 10: Cornell Big Red 41, Columbia Lions 0 (+2148)\cr
+ Sep 15: Columbia Lions 6, Harvard Crimson 9 (+2145)\cr}}$$
+This chain isn't necessarily optimal, it's just this
+particular program's best guess; algorithms that
+find better chains should be fun to invent.
+
+Actually this program has two variants. If you invoke it by saying simply
+`\.{football}', you get chains found by a simple ``greedy algorithm.''
+But if you invoke it by saying `\.{football} \<number>' (assuming \UNIX\
+command-line conventions), the program works harder. Higher values of
+\<number> do more calculation and tend to find better chains. For
+example, the simple greedy algorithm favors Stanford over Harvard by
+only 781; \.{football}~\.{10} raises this to 1939; the
+example above corresponds to \.{football}~\.{1000}.
+
+@ We use the data types \&{Area}, \&{Vertex}, \&{Arc}, and \&{Graph}
+defined in |gb_graph|.
+
+@f Area int
+@f Vertex int
+@f Arc int
+@f Graph int
+
+@ Here is the general layout of this program, as seen by the \Cee\ compiler:
+@^UNIX dependencies@>
+
+@p
+#include "gb_graph.h" /* the standard GraphBase data structures */
+#include "gb_games.h" /* the routine that sets up the graph of scores */
+#include "gb_flip.h" /* random number generator */
+@#
+@<Type declarations@>@;
+@<Global variables@>@;
+@<Subroutines@>@;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{
+ @<Scan the command line options@>;
+ @<Set up the graph@>;
+ while(1) {
+ @<Prompt for starting team and goal team; |break| if none given@>;
+ @<Find a chain from |start| to |goal|, and print it@>;
+ }
+}
+
+@ Let's deal with \UNIX-dependent stuff first. The rest of this program
+should work without change on any operating system.
+@^UNIX dependencies@>
+
+@<Scan the command line options@>=
+if (argc==3 && strcmp(argv[2],"-v")==0) verbose=argc=2; /* secret option */
+if (argc==1) width=0;
+else if (argc==2 && sscanf(argv[1],"%d",&width)==1) {
+ if (width<0) width=-width; /* a \UNIX\ user might have used a hyphen */
+} else {
+ fprintf(stderr,"Usage: %s [searchwidth]\n",argv[0]);
+ return -2;
+}
+
+@ @<Glob...@>=
+int width; /* number of cases examined per stratum */
+Graph *g; /* the graph containing score information */
+Vertex *u,*v; /* vertices of current interest */
+Arc *a; /* arc of current interest */
+Vertex *start,*goal; /* teams specified by the user */
+int mm; /* counter used only in |verbose| mode */
+
+@ An arc from |u| to |v| in the graph generated by |games| has a |len| field
+equal to the number of points scored by |u| against |v|.
+For our purposes we want also a |del| field, which gives the difference
+between the number of points scored by |u| and the number of points
+scored by~|v| in that game.
+
+@d del a.i /* |del| info appears in utility field |a| of an |Arc| record */
+
+@<Set up the graph@>=
+g=games(0,0,0,0,0,0,0,0);
+ /* this default graph has the data for the entire 1990 season */
+if (g==NULL) {
+ fprintf(stderr,"Sorry, can't create the graph! (error code %d)\n",
+ panic_code);
+ return -1;
+}
+for (v=g->vertices;v<g->vertices+g->n;v++)
+ for (a=v->arcs;a;a=a->next)
+ if (a->tip>v) { /* arc |a+1| is the mate of arc |a| iff |a->tip>v| */
+ a->del=a->len-(a+1)->len;
+ (a+1)->del=-a->del;
+ }
+
+@* Terminal interaction. While we're getting trivialities out of the way,
+we might as well take care of the simple dialog that transpires
+between this program and the user.
+
+@<Prompt for...@>=
+putchar('\n'); /* make a blank line for visual punctuation */
+restart: /* if we avoid this label, the |break| command will be broken */
+if ((start=prompt_for_team("Starting"))==NULL) break;
+if ((goal=prompt_for_team(" Other"))==NULL) goto restart;
+if (start==goal) {
+ printf(" (Um, please give me the names of two DISTINCT teams.)\n");
+ goto restart;
+}
+
+@ The user must spell team names exactly as they appear in the file
+\.{games.dat}. Thus, for example, `\.{Berkeley}' and `\.{Cal}' don't
+work; it has to be `\.{California}'. Similarly, a person must type
+`\.{Pennsylvania}' instead of `\.{Penn}', `\.{Nevada-Las} \.{Vegas}'
+instead of `\.{UNLV}'. A backslash is necessary in `\.{Texas} \.{A\\\&M}'.
+
+@<Sub...@>=
+Vertex *prompt_for_team(s)
+ char *s; /* string used in prompt message */
+{@+register char *q; /* current position in |buffer| */
+ register Vertex *v; /* current vertex being examined in sequential search */
+ char buffer[30]; /* a line of input */
+ while (1) {
+ printf("%s team: ",s);
+ fflush(stdout); /* make sure the user sees the prompt */
+ fgets(buffer,30,stdin);
+ if (buffer[0]=='\n') return NULL; /* the user just hit \<return> */
+ buffer[29]='\n';
+ for (q=buffer;*q!='\n';q++) ; /* scan to end of input */
+ *q='\0';
+ for (v=g->vertices;v<g->vertices+g->n;v++)
+ if (strcmp(buffer,v->name)==0) return v; /* aha, we found it */
+ printf(" (Sorry, I don't know any team by that name.)\n");
+ printf(" (One team I do know is %s...)\n",
+ (g->vertices+gb_unif_rand(g->n))->name);
+ }
+}
+
+@*Greed. The main task of this program is to find the longest possible
+simple path from |start| to |goal|, using |del| as the length of each
+arc in the path. This is an NP-complete problem, and the number of
+possibilities is pretty huge, so the present program is content to
+use heuristics that are reasonably easy to compute. (Researchers are hereby
+challenged to come up with better heuristics. Does simulated annealing
+give good results? How about genetic algorithms?)
+
+Perhaps the first approach that comes to mind is a simple ``greedy'' approach
+in which each step takes the largest possible |del| that doesn't prevent
+us from eventually getting to |goal|. So that's the method we will
+implement first.
+
+@ @<Find a chain from |start| to |goal|, and print it@>=
+@<Initialize the allocation of auxiliary memory@>;
+if (width==0) @<Use a simple-minded
+ greedy algorithm to find a chain from |start| to |goal|@>@;
+else @<Use a stratified heuristic to find a chain from |start| to |goal|@>;
+@<Print the solution corresponding to |cur_node|@>;
+@<Recycle the auxiliary memory used@>;
+
+@ We might as well use data structures that are more general than we need,
+in anticipation of a more complex heuristic that will be implemented later.
+The set of all possible solutions can be viewed as a backtrack tree
+in which the branches from each node are the games that can possibly
+follow that node. We will examine a small part of that gigantic tree.
+
+@<Type declarations@>=
+typedef struct node_struct {
+ Arc *a; /* game from the current team to the next team */
+ int len; /* accumulated length from |start| to here */
+ struct node_struct *prev; /* node that gave us the current team */
+ struct node_struct *next;
+ /* list pointer to node in same stratum (see below) */
+} node;
+
+@ @<Glob...@>=
+Area node_storage; /* working storage for heuristic calculations */
+node *next_node; /* where the next node is slated to go */
+node *bad_node; /* end of current allocation block */
+node *cur_node; /* current node of particular interest */
+
+@ @<Initialize the allocation of auxiliary memory@>=
+next_node=bad_node=NULL;
+
+@ @<Subroutines@>=
+node *new_node(x,d)
+ node *x; /* an old node that the new node will call |prev| */
+ int d; /* incremental change to |len| */
+{
+ if (next_node==bad_node) {
+ next_node=gb_alloc_type(1000,@[node@],node_storage);
+ if (next_node==NULL) return NULL; /* we're out of space */
+ bad_node=next_node+1000;
+ }
+ next_node->prev=x;
+ next_node->len=(x?x->len:0)+d;
+ return next_node++;
+}
+
+@ @<Recycle the auxiliary memory used@>=
+gb_free(node_storage);
+
+@ When we're done, |cur_node->a->tip| will be the |goal| vertex, and
+we can get back to the |start| vertex by following |prev| links
+from |cur_node|. It looks better to print the answers from |start| to
+|goal|, so maybe we should have changed our algorithm to go the
+other way.
+
+But let's not worry over trifles. It's easy to change
+the order of a linked list. The secret is simply to think of the list
+as a stack, from which we pop all the elements off to another stack;
+the new stack has the elements in reverse order.
+
+@<Print the solution corresponding to |cur_node|@>=
+next_node=NULL; /* now we'll use |next_node| as top of temporary stack */
+do@+{@+register node*t;
+ t=cur_node;
+ cur_node=t->prev; /* pop */
+ t->prev=next_node;
+ next_node=t; /* push */
+}@+while (cur_node);
+for (v=start;v!=goal;v=u,next_node=next_node->prev) {
+ a=next_node->a;
+ u=a->tip;
+ @<Print the score of game |a| between |v| and |u|@>;
+ printf(" (%+d)\n",next_node->len);
+}
+
+@ @<Print the score of game |a| between |v| and |u|@>=
+{@+register int d=a->date; /* date of the game, 0 means Aug 26 */
+ if (d<=5) printf(" Aug %02d",d+26);
+ else if (d<=35) printf(" Sep %02d",d-5);
+ else if (d<=66) printf(" Oct %02d",d-35);
+ else if (d<=96) printf(" Nov %02d",d-66);
+ else if (d<=127) printf(" Dec %02d",d-96);
+ else printf(" Jan 01"); /* |d=128| */
+ printf(": %s %s %d, %s %s %d",v->name,v->nickname,a->len,
+ u->name,u->nickname,a->len-a->del);
+}
+
+@ We can't just move from |v| to any adjacent vertex; we can only
+go to a vertex from which |goal| can be reached without touching |v|
+or any other vertex already used on the path from |start|.
+
+Furthermore, if the locally best move from |v| is directly to |goal|,
+we don't want to make that move unless it's our last chance; we can
+probably do better by making the chain longer. Otherwise, for example,
+a chain between a team and its worst opponent would consist of
+only a single game.
+
+To keep track of untouchable vertices, we use a utility field
+called |blocked| in each vertex record. Another utility field,
+|valid|, will be set to a validation code in each vertex that
+still leads to the goal.
+
+@d blocked u.i
+@d valid v.v
+
+@<Use a simple-minded greedy algorithm to find a chain from |start| to |goal|@>=
+{
+ for (v=g->vertices;v<g->vertices+g->n;v++) v->blocked=0,v->valid=NULL;
+ cur_node=NULL;
+ for (v=start;v!=goal;v=cur_node->a->tip) {@+register int d=-10000;
+ register Arc *best_arc; /* arc that achieves |del=d| */
+ register Arc *last_arc; /* arc that goes directly to |goal| */
+ v->blocked=1;
+ cur_node=new_node(cur_node,0);
+ if (cur_node==NULL) {
+ fprintf(stderr,"Oops, there isn't enough memory!\n");@+return -2;
+ }
+ @<Set |u->valid=v| for all |u| to which |v| might now move@>;
+ for (a=v->arcs;a;a=a->next)
+ if (a->del>d && a->tip->valid==v)
+ if (a->tip==goal) last_arc=a;
+ else best_arc=a,d=a->del;
+ cur_node->a=(d==-10000?last_arc:best_arc);
+ /* use |last_arc| as a last resort */
+ cur_node->len+=cur_node->a->del;
+ }
+}
+
+@ A standard marking algorithm supplies the final missing link in
+our algorithm.
+
+@d link w.v
+
+@<Set |u->valid=v| for all |u| to which |v| might now move@>=
+u=goal; /* |u| will be the top of a stack of nodes to be explored */
+u->link=NULL;
+u->valid=v;
+do {
+ for (a=u->arcs,u=u->link;a;a=a->next)
+ if (a->tip->blocked==0 && a->tip->valid!=v) {
+ a->tip->valid=v; /* mark |a->tip| reachable from |goal| */
+ a->tip->link=u;
+ u=a->tip; /* push it on the stack, so that its successors
+ will be marked too */
+ }
+} while (u);
+
+@*Stratified greed.
+One approach to better chains is the following algorithm, motivated by
+similar ideas of Pang Chen [Ph.D. thesis, Stanford University, 1989]:
+Suppose the nodes of a (possibly huge) backtrack tree are classified into
+a (fairly small) number of strata, by a function $h$ with the property
+that $h({\rm child})<h({\rm parent})$. Suppose further that we wish to
+find a node $x$ that maximizes a given function~$f(x)$, where it is
+reasonable to believe that $f$(child) will be relatively large among
+nodes in a child's stratum only if $f$(parent) is relatively large in
+the parent's stratum. Then it makes sense to restrict backtracking to,
+say, the top $w$ nodes of each stratum, ranked by their $f$ values.
+
+The greedy algorithm already described is a special case of this general
+approach, with $w=1$ and with $h(x)=-($length of chain leading to~$x)$.
+The refined algorithm we are about the describe uses a general value of $w$
+and a somewhat more relevant stratification function: Given a node~$x$
+of the backtrack tree for longest paths, corresponding to a path from
+|start| to a certain vertex~$u=u(x)$, we will let $h(x)$ be the number of
+vertices that lie between |u| and |goal| (in the sense that the simple
+path from |start| to~|u| can be extended until it passes through such
+a vertex and then all the way to~|goal|).
+
+Here is the top level of the stratified greedy algorithm. We maintain
+a linked list of nodes for each stratum, i.e., for each possible value
+of~$h$. The number of nodes required is bounded by $w$ times the
+number of strata.
+
+@<Use a strat...@>=
+{
+ @<Make |list[0]| through |list[n-1]| empty@>;
+ cur_node=NULL; /* |NULL| represents the root of the backtrack tree */
+ m=g->n-1; /* the highest stratum not yet fully explored */
+ do@+{
+ @<Place each child~|x| of |cur_node| into |list[h(x)]|, retaining
+ at most |width| nodes of maximum |len| on each list@>;
+ while (list[m]==NULL) m--,mm=0;
+ cur_node=list[m];
+ list[m]=cur_node->next; /* remove a node from highest remaining stratum */
+ if (verbose) @<Print ``verbose'' info about |cur_node|@>;
+ }@+while (m>0); /* exactly one node should be in |list[0]| (see below) */
+}
+
+@ The calculation of $h(x)$ is somewhat delicate, and we will defer it
+for a moment. The list manipulation is, however, easy, so we can finish it
+quickly while it's fresh in our minds.
+
+@d MAX_N 120 /* the number of teams in \.{games.dat} */
+
+@<Glob...@>=
+node *list[MAX_N]; /* the best nodes known in given strata */
+int size[MAX_N]; /* the number of elements in a given |list| */
+int m,h; /* current lists of interest */
+node *x; /* a child of |cur_node| */
+
+@ @<Make |list[0]|...@>=
+for (m=0;m<g->n;m++) {
+ list[m]=NULL;
+ size[m]=0;
+}
+
+@ The lists are maintained in order by |len|, with the largest |len| value
+at the end so that we can easily delete the smallest.
+
+When |h=0|, we retain only one node instead of~|width| different nodes,
+because we are interested in only one solution.
+
+@<Place node~|x| into |list[h]|, retaining
+ at most |width| nodes of maximum |len|@>=
+if ((h>0 && size[h]==width) || (h==0 && size[0]>0)) {
+ if (x->len<=list[h]->len) goto done; /* drop node |x| */
+ list[h]=list[h]->next; /* drop one node from |list[h]| */
+} else size[h]++;
+{@+register node *p,*q; /* node in list and its predecessor */
+ for (p=list[h],q=NULL; p; q=p,p=p->next)
+ if (x->len<=p->len) break;
+ x->next=p;
+ if (q) q->next=x;
+ else list[h]=x;
+}
+done:;
+
+@ @<Print ``verbose'' info...@>=
+{
+ cur_node->next=(node*)((++mm<<8)+m); /* pack an ID for this node */
+ printf("[%d,%d]=[%d,%d]&%s (%+d)\n",m,mm,@|
+ cur_node->prev?((unsigned)cur_node->prev->next)&0xff:0,@|
+ cur_node->prev?((unsigned)cur_node->prev->next)>>8:0,@|
+ cur_node->a->tip->name, cur_node->len);
+}
+
+@ Incidentally, it is plausible to conjecture that the stratified algorithm
+always beats the simple greedy algorithm; but that conjecture is false.
+For example, the greedy algorithm is able to rank Harvard over Stanford
+by 1529, while the stratified algorithm achieves only 1527 when
+|width=1|. On the other hand, the greedy algorithm often fails
+miserably; when comparing two Ivy League teams, it doesn't find a
+way to break out of the Ivy and Patriot Leagues.
+
+@*Bicomponents revisited.
+How difficult is it to compute the function $h$? Given a connected graph~$G$
+with two distinguished vertices $u$ and~$v$, we wish to count the number
+of vertices that might appear on a simple path from $u$ to~$v$.
+(This is {\it not\/} the same as the number of vertices reachable from both
+$u$ and~$v$. For example, consider a ``claw'' graph with four vertices
+$\{u,v,w,x\}$ and with edges only from $x$ to the other three vertices;
+in this graph $w$ is reachable from $u$ and~$v$ but it is not on any simple
+path between them.)
+
+The best way to solve this problem is probably to compute the bicomponents
+of~$G$, or least to compute some of them. Another demo program,
+|book_components|, explains the relevant theory in some detail, and
+we will assume familiarity with that algorithm in the present
+discussion.
+
+Let us imagine extending $G$ to a slightly larger graph $G^+$ by
+adding a dummy vertex~$o$ that is adjacent only to $v$. Suppose we determine
+the bicomponents of $G^+$ by depth-first search starting at~$o$.
+These bicomponents form a tree rooted at the bicomponent that contains
+just $o$ and~$v$. The number of vertices on paths between $u$ and~$v$,
+not counting $v$ itself, is then the number of vertices in the bicomponent
+containing~$u$ and in any other bicomponents between that one and the root.
+
+Strictly speaking, each articulation point belongs
+to two or more bicomponents. But we will assign each articulation point
+to its bicomponent that is nearest the root of the tree; then the vertices
+of each bicomponent are precisely the vertices output in bursts by the
+depth-first procedure. The bicomponents we wish to enumerate are $B_1$, $B_2$,
+\dots,~$B_k$, where $B_1$ is the bicomponent containing~$u$ and
+$B_{j+1}$ is the bicomponent containing the articulation point associated
+with~$B_j$; we stop at~$B_k$ when its associated articulation point is~$v$.
+(Often $k=1$.)
+
+The ``children'' of a given graph~$G$ are obtained by removing vertex~$u$
+and by considering paths from $u'$ to~$v$, where $u'$ is a vertex
+formerly adjacent to~$u$; thus $u'$ is either in~$B_1$ or it is $B_1$'s
+associated articulation point. Removing $u$ will, in general, split
+$B_1$ into a tree of smaller bicomponents, but $B_2,\ldots,B_k$ will be
+unaffected. The implementation below does not take full advantage of this
+observation, because the amount of memory required to avoid recomputation
+would probably be prohibitive.
+
+@ The following program is copied almost verbatim from |book_components|.
+Instead of repeating the commentary that appears there, we will mention
+only the significant differences. One difference is that we start
+the depth-first search at a definite place, the |goal|.
+
+@<Place each child~|x| of |cur_node| into |list[h(x)]|, retaining
+ at most |width| nodes of maximum |len| on each list@>=
+@<Make all vertices unseen and all arcs untagged, except for vertices
+ that have already been used in steps leading up to |cur_node|@>;
+@<Perform a depth-first search with |goal| as the root, finding
+ bicomponents and determining the number of vertices accessible
+ between any given vertex and |goal|@>;
+for (a=(cur_node? cur_node->a->tip: start)->arcs; a; a=a->next)
+ if ((u=a->tip)->untagged==NULL) { /* |goal| is reachable from |u| */
+ x=new_node(cur_node,a->del);
+ if (x==NULL) {
+ fprintf(stderr,"Oops, there isn't enough memory!\n");@+return -3;
+ }
+ x->a=a;
+ @<Set |h| to the number of vertices on paths between |u| and |goal|@>;
+ @<Place node...@>;
+ }
+
+@ Setting the |rank| field of a vertex to infinity, before beginning
+a depth-first search, is tantamount to removing that vertex from
+the graph, because it tells the algorithm not to look further at
+such a vertex.
+
+@d rank z.i /* when was this vertex first seen? */
+@d parent u.v /* who told me about this vertex? */
+@d untagged x.a /* what is its first untagged arc? */
+@d min v.v /* how low in the tree can we jump from its mature descendants? */
+
+@<Make all vertices unseen and all arcs untagged, except for vertices
+ that have already been used in steps leading up to |cur_node|@>=
+for (v=g->vertices; v<g->vertices+g->n; v++) {
+ v->rank=0;
+ v->untagged=v->arcs;
+}
+for (x=cur_node;x;x=x->prev)
+ x->a->tip->rank=g->n; /* ``infinite'' rank (or close enough) */
+start->rank=g->n;
+nn=0;
+active_stack=settled_stack=NULL;
+
+@ @<Glob...@>=
+Vertex * active_stack; /* the top of the stack of active vertices */
+Vertex *settled_stack; /* the top of the stack of bicomponents found */
+int nn; /* the number of vertices that have been seen */
+Vertex dummy; /* imaginary parent of |goal|; its |rank| is zero */
+
+@ The |settled_stack| will contain a list of all bicomponents in
+the opposite order from which they are discovered. This is the order
+we need for computing the |h| function in each bicomponent later.
+
+@<Perform a depth-first search...@>=
+{
+ v=goal;
+ v->parent=&dummy;
+ @<Make vertex |v| active@>;
+ do @<Explore one step from the current vertex~|v|, possibly moving
+ to another current vertex and calling~it~|v|@>@;
+ while (v!=&dummy);
+ @<Use |settled_stack| to put the mutual reachability count for
+ each vertex |u| in |u->parent->rank|@>;
+}
+
+@ @<Make vertex |v| active@>=
+v->rank=++nn;
+v->link=active_stack;
+active_stack=v;
+v->min=v->parent;
+
+@ @<Explore one step from the current vertex~|v|, possibly moving
+ to another current vertex and calling~it~|v|@>=
+{@+register Vertex *u; /* a vertex adjacent to |v| */
+ register Arc *a=v->untagged; /* |v|'s first remaining untagged arc, if any */
+ if (a) {
+ u=a->tip;
+ v->untagged = a->next; /* tag the arc from |v| to |u| */
+ if (u->rank) { /* we've seen |u| already */
+ if (u->rank < v->min->rank)
+ v->min=u; /* non-tree arc, just update |v->min| */
+ } else { /* |u| is presently unseen */
+ u->parent = v; /* the arc from |v| to |u| is a new tree arc */
+ v = u; /* |u| will now be the current vertex */
+ @<Make vertex |v| active@>;
+ }
+ } else { /* all arcs from |v| are tagged, so |v| matures */
+ u=v->parent; /* prepare to backtrack in the tree */
+ if (v->min==u) @<Remove |v| and all its successors on the active stack
+ from the tree, and report them as a bicomponent of the graph
+ together with~|u|@>@;
+ else /* the arc from |u| to |v| has just matured,
+ making |v->min| visible from |u| */@,
+ if (v->min->rank < u->min->rank)
+ u->min=v->min;
+ v=u; /* the former parent of |v| is the new current vertex |v| */
+ }
+}
+
+@ When a bicomponent is found, we reset the |parent| field of each vertex
+so that, afterwards, two vertices will belong to the same bicomponent
+if and only if they have the same |parent|. (This trick was not used
+in |book_components|, but it does appear in the similar algorithm of
+|roget_components|.) The new parent, |v|, will represent that bicomponent
+in subsequent computation; we put it onto |settled_stack|.
+We also reset |v->rank| to be the bicomponent's size, plus a constant
+large enough to keep the algorithm from getting confused. (Vertex~|u|
+may still have untagged arcs leading into this bicomponent; we need to
+keep the ranks at least as big as the rank of |u->min|.) Notice that
+|v->min| is |u|, the articulation point associated with this bicomponent.
+Later the |rank| field will
+contain the sum of all counts between here and the root.
+
+We don't have to do anything when |v==goal|; the trivial root bicomponent
+always comes out last.
+
+@<Remove |v| and all its successors on the active stack...@>=
+{@+if (v!=goal) {@+register Vertex *t; /* runs through the vertices of the
+ new bicomponent */
+ int c=0; /* the number of vertices removed */
+ t=active_stack;
+ while (t!=v) {
+ c++;
+ t->parent=v;
+ t=t->link;
+ }
+ active_stack=v->link;
+ v->parent=v;
+ v->rank=c+g->n; /* the true component size is |c+1| */
+ v->link=settled_stack;
+ settled_stack=v;
+ }
+}
+
+@ So here's how we sum the ranks. When we get to this step, the |settled|
+stack contains all bicomponent representatives except |goal| itself.
+
+@<Use |settled_stack| to put the mutual reachability count for
+ each vertex |u| in |u->parent->rank|@>=
+while (settled_stack) {
+ v=settled_stack;
+ settled_stack=v->link;
+ v->rank+=v->min->parent->rank+1-g->n;
+} /* note that |goal->parent->rank=0| */
+
+@ And here's the last piece of the puzzle.
+
+@<Set |h| to the number of vertices on paths between |u| and |goal|@>=
+h=u->parent->rank;
+
+@* Index. Finally, here's a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/games.dat b/support/graphbase/games.dat
new file mode 100644
index 0000000000..7d92b087fa
--- /dev/null
+++ b/support/graphbase/games.dat
@@ -0,0 +1,792 @@
+* File "games.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* College football teams and scores, 1990
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 787,644169130)
+USAF Air Force(Falcons)Western Athletic;,;5,
+AKRON Akron(Zips)Independent;,;,
+BAMA Alabama(Crimson Tide)Southeastern;104,;13,1
+AZ Arizona(Wildcats)Pacific Ten;370,48;,
+AZ-ST Arizona State(Sun Devils)Pacific Ten;113,8;,
+ARK Arkansas(Razorbacks)Southwest;647,79;,
+ARMY Army(Cadets)Independent;,;,
+AUBN Auburn(Tigers)Southeastern;1385,619;288,39
+BALL Ball State(Cardinals)Mid-American;,;,
+BAYL Baylor(Bears)Southwest;,;,
+BOST Boston College(Eagles)Independent;,;,
+BOWLG Bowling Green(Falcons)Mid-American;,;,
+BYU Brigham Young(Cougars)Western Athletic;1171,430;246,41
+BROWN Brown(Bears)Ivy;,;,
+BUCK Bucknell(Bisons)Patriot;,;,
+CAL California(Golden Bears)Pacific Ten;,;37,
+CMICH Central Michigan(Chippewas)Mid-American;,;,
+CINCI Cincinnati(Bearcats)Independent;,;,
+CLEM Clemson(Tigers)Atlantic Coast;471,21;950,420
+COLG Colgate(Red Raiders)Patriot;,;,
+COLO Colorado(Buffaloes)Big Eight;1041,305;1475,846
+CO-ST Colorado State(Rams)Western Athletic;9,;67,
+COLUM Columbia(Lions)Ivy;,;,
+CORN Cornell(Big Red)Ivy;,;,
+DART Dartmouth(Big Green)Ivy;,;,
+DUKE Duke(Blue Devils)Atlantic Coast;,;,
+ECAR East Carolina(Pirates)Independent;,;,
+EMICH Eastern Michigan(Hurons)Mid-American;,;,
+FLA Florida(Gators)Southeastern;163,18;863,
+FL-ST Florida State(Seminoles)Independent;1367,647;1303,677
+FORD Fordham(Rams)Patriot;,;,
+FRES Fresno State(Bulldogs)Big West;51,12;,
+FULL Fullerton State(Titans)Big West;,;,
+GA Georgia(Bulldogs)Southeastern;7,;,
+GTECH Georgia Tech(Yellow Jackets)Atlantic Coast;37,7;1441,847
+HARV Harvard(Crimson)Ivy;,;,
+HI Hawaii(Rainbow Warriors)Western Athletic;,;2,
+HOLY Holy Cross(Crusaders)Patriot;,;,
+HOUST Houston(Cougars)Southwest;395,;940,
+ILL Illinois(Fighting Illini)Big Ten;365,25;146,6
+IND Indiana(Fightin' Hoosiers)Big Ten;,;,
+IOWA Iowa(Hawkeyes)Big Ten;,;371,57
+IA-ST Iowa State(Cyclones)Big Eight;,;,
+KAS Kansas(Jayhawks)Big Eight;,;,
+KS-ST Kansas State(Wildcats)Big Eight;,;,
+KENTS Kent State(Golden Flashes)Mid-American;,;,
+KY Kentucky(Wildcats)Southeastern;,;,
+LAFAY Lafayette(Leopards)Patriot;,;,
+LHIGH Lehigh(Engineers)Patriot;,;,
+LBSU Long Beach State(Forty-Niners)Big West;,;,
+LSU Louisiana State(Fighting Tigers)Southeastern;25,;,
+LTECH Louisiana Tech(Bulldogs)Independent;,;,
+LOUVL Louisville(Cardinals)Independent;5,;775,245
+MD Maryland(Terps)Atlantic Coast;42,2;,
+MEMPH Memphis State(Tigers)Independent;,;,
+MIFL Miami, Florida(Hurricanes)Independent;1013,290;1388,763
+MIOH Miami, Ohio(Redskins)Mid-American;,;,
+MICH Michigan(Wolverines)Big Ten;1230,462;1025,426
+MI-ST Michigan State(Spartans)Big Ten;382,15;610,120
+MINN Minnesota(Golden Gophers)Big Ten;,;,
+MISS Mississippi(Rebels)Southeastern;3,;253,7
+MS-ST Mississippi State(Bulldogs)Southeastern;,;,
+MO Missouri(Tigers)Big Eight;,;,
+NAVY Navy(Midshipmen)Independent;,;,
+NEB Nebraska(Cornhuskers)Big Eight;1047,421;185,41
+UNLV Nevada-Las Vegas(Rebels)Big West;,;,
+NMEX New Mexico(Lobos)Western Athletic;,;,
+NM-ST New Mexico State(Aggies)Big West;,;,
+NCAR North Carolina(Tar Heels)Atlantic Coast;,;4,
+NC-ST North Carolina State(Wolfpack)Atlantic Coast;,;30,
+NIL Northern Illinois(Huskies)Independent;,;,
+NW Northwestern(Wildcats)Big Ten;,;,
+NDAME Notre Dame(Fighting Irish)Independent;1451,666;1179,548
+OSU Ohio State(Buckeyes)Big Ten;467,114;7,1
+OU Ohio University(Bobcats)Mid-American;,;,
+OK Oklahoma(Sooners)Big Eight;662,;452,
+OK-ST Oklahoma State(Cowboys)Big Eight;,;,
+OR Oregon(Ducks)Pacific Ten;36,2;6,1
+OR-ST Oregon State(Beavers)Pacific Ten;,;,
+PAC Pacific(Tigers)Big West;,;,
+PA-ST Penn State(Nittany Lions)Independent;25,;907,301
+PENN Pennsylvania(Red \& Blue)Ivy;,;,
+PITT Pittsburgh(Panthers)Independent;673,140;,
+PRIN Princeton(Tigers)Ivy;,;,
+PURD Purdue(Boilermakers)Big Ten;1,;,
+RICE Rice(Owls)Southwest;,;,
+RUTG Rutgers(Scarlet Knights)Independent;1,;,
+SDSU San Diego State(Aztecs)Western Athletic;,;,
+SJSU San Jose State(Spartans)Big West;,;138,16
+SCAR South Carolina(Fighting Gamecocks)Independent;40,2;,
+USC Southern California(Trojans)Pacific Ten;1126,479;266,9
+SMU Southern Methodist(Mustangs)Southwest;,;,
+SMISS Southern Mississippi(Golden Eagles)Independent;31,2;48,1
+SWLA Southwestern Louisiana(Ragin' Cajuns)Independent;,;,
+STAN Stanford(Cardinal)Pacific Ten;4,;,
+SYR Syracuse(Orangemen)Independent;2,;121,12
+TEMP Temple(Owls)Independent;,;,
+TENN Tennessee(Volunteers)Southeastern;1108,441;993,449
+TEX Texas(Longhorns)Southwest;214,25;887,268
+TA&M Texas A\&M(Aggies)Southwest;802,188;627,204
+TCU Texas Christian(Horned Frogs)Southwest;,;,
+UTEP Texas-El Paso(Miners)Western Athletic;,;,
+TTECH Texas Tech(Red Raiders)Southwest;,;,
+TOL Toledo(Rockets)Mid-American;,;,
+TUL Tulane(Green Wave)Independent;,;,
+TULSA Tulsa(Golden Hurricane)Independent;,;,
+UCLA UCLA(Bruins)Pacific Ten;38,;6,
+UTAH Utah(Utes)Western Athletic;,;,
+UT-ST Utah State(Aggies)Big West;,;,
+VAND Vanderbilt(Commodores)Southeastern;,;,
+VA Virginia(Cavaliers)Atlantic Coast;1005,272;188,65
+VTECH Virginia Tech(Gobblers)Independent;,;5,5
+WAKEF Wake Forest(Demon Deacons)Atlantic Coast;,;,
+WASH Washington(Huskies)Pacific Ten;345,20;1246,664
+WA-ST Washington State(Cougars)Pacific Ten;,;,
+WVA West Virginia(Mountaineers)Independent;10,;,
+WMICH Western Michigan(Broncos)Mid-American;,;,
+WIS Wisconsin(Badgers)Big Ten;,;,
+WYO Wyoming(Cowboys)Western Athletic;16,;7,
+YALE Yale(Bulldogs)Ivy;,;,
+>A26
+COLO31,TENN31
+>A31
+USC34,SYR16
+>S1
+CO-ST35@USAF33
+LBSU0@CLEM59
+LTECH17@ECAR27
+EMICH10@FRES41
+TA&M28@HI13
+VA59@KAS10
+CMICH17@KY20
+VTECH13@MD20
+BAYL0@NEB13
+NMEX29@NM-ST12
+MIOH0@NCAR34
+TULSA3@OK-ST10
+OU3@PITT35
+WAKEF17@RICE33
+LOUVL10@SJSU10
+DUKE10@SCAR21
+PAC7@TENN55
+WA-ST21@TCU3
+BYU30@UTEP10
+SWLA48@TUL6
+UTAH19@UT-ST0
+KENTS24@WVA35
+TEMP23@WYO38
+>S2
+BOWLG34@CINCI20
+>S6
+STAN17@COLO21
+>S8
+HI3@USAF27
+SMISS27@BAMA24
+ILL16@AZ28
+BAYL13@AZ-ST28
+FULL17@AUBN38
+MIFL21@BYU28
+CINCI34@CMICH0
+WMICH27@EMICH24
+OK-ST7@FLA50
+ECAR24@FL-ST45
+NMEX17@FRES24
+NC-ST13@GTECH21
+UNLV9@HOUST37
+OR-ST12@KAS38
+AKRON10@KENTS38
+FORD3@LHIGH35
+GA13@LSU18
+TOL14@MIOH20
+UTAH35@MINN29
+MEMPH21@MISS23
+TENN40@MS-ST7
+TCU20@MO19
+NIL14@NEB60
+TTECH10@OSU17
+SDSU21@OR42
+TEX17@PA-ST13
+BOST6@PITT29
+TUL21@RICE10
+KY8@RUTG24
+NCAR5@SCAR27
+VAND7@SMU44
+TEMP9@SYR19
+NM-ST27@UTEP24
+OK34@UCLA14
+LBSU13@UT-ST27
+CLEM7@VA20
+BOWLG21@VTECH7
+SJSU17@WASH17
+WYO34@WA-ST13
+MD14@WVA10
+CAL28@WIS12
+>S13
+HOUST51@TTECH35
+>S15
+CMICH14@AKRON14
+FLA17@BAMA13
+CO-ST20@AZ-ST31
+TULSA3@ARK28
+HOLY7@ARMY24
+OSU31@BOST10
+WA-ST36@BYU50
+YALE27@BROWN21
+MIFL52@CAL24
+HARV9@COLUM6
+PRIN14@CORN17
+PENN16@DART6
+VTECH24@ECAR23
+OU18@EMICH45
+SMISS17@GA18
+COLO22@ILL23
+CINCI10@IOWA63
+NM-ST7@KS-ST52
+IND45@KY24
+BUCK24@LAFAY14
+MIOH7@LSU35
+KAS16@LOUVL28
+CLEM18@MD17
+IA-ST16@MINN20
+AUBN24@MISS10
+FULL13@MS-ST27
+UT-ST10@MO45
+AZ25@NMEX10
+WAKEF15@NC-ST20
+DUKE27@NW24
+MICH24@NDAME28
+PITT28@OK52
+UNLV19@OR-ST20
+SJSU28@PAC14
+WASH20@PURD14
+COLG17@RUTG28
+LBSU20@SDSU38
+PA-ST14@USC19
+MI-ST23@SYR23
+UTEP0@TENN56
+SWLA14@TA&M63
+NIL14@TOL23
+SMU7@TUL43
+STAN31@UCLA32
+FRES31@UTAH7
+NAVY14@VA56
+LTECH21@WMICH27
+BALL7@WIS24
+>S22
+FULL17@AKRON48
+OR17@AZ22
+MISS21@ARK17
+TOL28@BALL16
+SDSU34@BYU62
+COLUM16@BUCK41
+BOWLG0@CMICH17
+MIOH16@CINCI12
+CORN24@COLG59
+UTEP20@CO-ST38
+LHIGH14@DART33
+VA59@DUKE0
+NM-ST3@FRES42
+BAMA16@GA17
+MO7@IND58
+IA-ST35@IOWA45
+PAC7@LBSU28
+NC-ST12@MD13
+UCLA15@MICH38
+NDAME20@MI-ST19
+SMISS10@MS-ST13
+MINN0@NEB56
+SJSU47@UNLV13
+TTECH34@NMEX32
+KY13@NCAR16
+KS-ST35@NIL42
+TULSA10@OK52
+RUTG0@PA-ST28
+HOLY17@PENN3
+FORD14@PRIN23
+NW14@RICE31
+ECAR20@SWLA10
+OR-ST3@STAN37
+PITT20@SYR20
+COLO29@TEX22
+OK-ST21@TCU31
+FL-ST31@TUL13
+HI19@UTAH7
+LSU21@VAND24
+SCAR35@VTECH24
+USC0@WASH31
+CAL31@WA-ST41
+LOUVL9@WVA7
+KENTS10@WMICH37
+TEMP24@WIS18
+USAF12@WYO24
+LAFAY17@YALE18
+>S29
+VAND28@BAMA59
+CAL20@AZ25
+CO-ST52@ARK31
+TENN26@AUBN26
+BOWLG6@BALL16
+FORD35@BROWN28
+MIOH7@CMICH31
+DUKE7@CLEM26
+PRIN13@COLG39
+WASH14@COLO20
+BUCK42@CORN21
+MS-ST21@FLA34
+VTECH28@FL-ST39
+FULL3@FRES38
+ECAR15@GA19
+SCAR6@GTECH27
+HARV14@HOLY35
+RICE22@HOUST24
+EMICH6@IND37
+WMICH20@IA-ST34
+NMEX6@KS-ST38
+CINCI27@KENTS24
+PENN13@LAFAY20
+COLUM9@LHIGH42
+TA&M8@LSU17
+SWLA10@LTECH24
+IOWA21@MIFL48
+MD17@MICH45
+TUL21@MISS31
+AZ-ST9@MO30
+BOST28@NAVY17
+OR-ST7@NEB31
+NC-ST12@NCAR9
+NIL7@NW24
+PURD11@NDAME37
+USC35@OSU26
+TOL27@OU20
+KAS17@OK31
+BYU16@OR32
+UNLV37@PAC28
+WVA38@PITT24
+MI-ST34@RUTG10
+USAF18@SDSU48
+TCU42@SMU21
+LOUVL13@SMISS25
+SJSU29@STAN23
+BAYL21@TTECH15
+MEMPH22@TULSA10
+WYO28@UTAH10
+ARMY14@WAKEF52
+UCLA30@WA-ST20
+>O6
+NAVY7@USAF24
+WMICH24@AKRON20
+WASH42@AZ-ST14
+TCU54@ARK26
+DUKE17@ARMY16
+LTECH14@AUBN16
+HOUST31@BAYL15
+RUTG14@BOST19
+OU10@BOWLG10
+SJSU34@CAL35
+GA3@CLEM34
+UTAH13@CO-ST22
+LAFAY41@COLUM34
+SMISS16@ECAR7
+LSU8@FLA34
+CORN20@HARV17
+DART10@HOLY21
+KAS34@IA-ST34
+NEB45@KS-ST8
+CMICH42@KENTS0
+NM-ST27@LBSU31
+TULSA14@LOUVL38
+GTECH31@MD3
+TUL14@MEMPH21
+FL-ST22@MIFL31
+BALL10@MIOH24
+IOWA12@MI-ST7
+KY29@MISS35
+COLO33@MO31
+FULL10@UNLV29
+UTEP28@NMEX48
+FRES18@NIL73
+IND42@NW0
+STAN36@NDAME31
+ILL31@OSU20
+OK31@OK-ST17
+UT-ST7@OR52
+TEMP10@PA-ST48
+LHIGH22@PENN16
+BROWN23@PRIN27
+MINN19@PURD7
+TEX26@RICE10
+WA-ST17@USC30
+BAMA25@SWLA6
+TTECH24@TA&M28
+EMICH23@TOL37
+AZ28@UCLA21
+SYR49@VAND14
+WVA21@VTECH26
+NCAR31@WAKEF24
+MICH41@WIS3
+SDSU51@WYO52
+COLG30@YALE7
+>O13
+CAL31@AZ-ST24
+TTECH49@ARK44
+VAND6@AUBN56
+KENTS0@BALL31
+SMU17@BAYL52
+ARMY20@BOST41
+CO-ST9@BYU52
+HOLY55@BROWN0
+PRIN9@BUCK14
+WMICH13@CMICH20
+IA-ST12@COLO28
+YALE17@DART27
+UT-ST24@FRES24
+PAC67@FULL37
+MISS28@GA12
+CLEM19@GTECH21
+FORD13@HARV19
+TA&M31@HOUST36
+PURD0@ILL34
+OSU27@IND27
+WIS10@IOWA30
+OK-ST17@KS-ST23
+MS-ST15@KY17
+CORN38@LAFAY16
+MEMPH17@LOUVL19
+WAKEF13@MD41
+KAS0@MIFL34
+MI-ST28@MICH27
+NW25@MINN35
+AKRON13@NAVY17
+MO21@NEB69
+UNLV24@NM-ST20
+USAF27@NDAME57
+MIOH40@OU18
+TEX14,OK13
+AZ21@OR-ST35
+SYR21@PA-ST27
+COLUM6@PENN21
+RUTG21@PITT45
+LBSU29@SJSU46
+ECAR7@SCAR37
+USC37@STAN22
+FLA3@TENN45
+RICE28@TCU38
+HI10@UTEP12
+BOWLG13@TOL19
+SMISS14@TUL14
+LTECH35@TULSA21
+SDSU31@UCLA45
+NC-ST0@VA31
+OR17@WASH38
+CINCI20@WVA28
+NMEX22@WYO25
+>O20
+LAFAY0@ARMY56
+FL-ST17@AUBN20
+PA-ST40@BOST21
+EMICH15@BOWLG25
+PENN17@BROWN24
+UCLA31@CAL38
+TOL12@CMICH13
+NMEX7@CO-ST47
+DART11@CORN6
+MD23@DUKE20
+CINCI32@ECAR56
+AKRON0@FLA59
+COLG31@FORD7
+LBSU16@FRES28
+VAND28@GA39
+FULL21@HI45
+LHIGH22@HOLY34
+MI-ST13@ILL15
+COLO41@KAS10
+OU15@KENTS44
+KY20@LSU30
+IOWA24@MICH23
+IND0@MINN12
+KS-ST10@MO31
+OK-ST3@NEB31
+GTECH13@NCAR13
+CLEM24@NC-ST17
+WIS34@NW44
+MIFL20@NDAME29
+IA-ST33@OK31
+AZ-ST7@OR27
+WA-ST55@OR-ST24
+NM-ST24@PAC62
+LOUVL27@PITT20
+HARV23@PRIN20
+OSU42@PURD2
+TTECH21@RICE42
+UT-ST27@SJSU34
+AZ35@USC26
+HOUST44@SMU17
+MEMPH7@SMISS23
+WASH52@STAN16
+RUTG0@SYR42
+VTECH28@TEMP31
+BAMA9@TENN6
+ARK17@TEX49
+BAYL20@TA&M20
+MS-ST38@TUL17
+SWLA25@TULSA13
+UTEP23@UTAH37
+VA49@WAKEF14
+BALL13@WMICH14
+COLUM7@YALE31
+>O27
+UTAH21@USAF52
+PA-ST9@BAMA0
+WA-ST34@AZ42
+USC13@AZ-ST6
+SYR26@ARMY14
+MIOH10@BOWLG10
+NMEX31@BYU55
+COLG28@BUCK27
+OK23@COLO32
+PRIN15@COLUM17
+BROWN7@CORN34
+HARV0@DART17
+CMICH16@EMICH12
+LSU3@FL-ST42
+DUKE31@GTECH48
+PAC24@HI35
+LAFAY3@HOLY34
+ARK28@HOUST62
+MICH45@IND19
+NW14@IOWA56
+NEB45@IA-ST13
+KS-ST24@KAS27
+GA24@KY26
+FULL35@LBSU37
+SWLA6@MEMPH20
+PURD33@MI-ST55
+AUBN17@MS-ST16
+TULSA35@NM-ST10
+MD10@NCAR34
+SCAR29@NC-ST38
+MINN23@OSU52
+WMICH31@OU23
+MO28@OK-ST48
+STAN0@OR31
+YALE27@PENN10
+NDAME31@PITT22
+AKRON17@RUTG20
+ECAR27@TEMP30
+SMU3@TEX52
+RICE15@TA&M41
+BAYL27@TCU21
+WYO17@UTEP10
+MIFL45@TTECH10
+KENTS14@TOL28
+CINCI7@TUL49
+OR-ST17@UCLA26
+UNLV6@UT-ST31
+MISS14@VAND13
+SMISS16@VTECH20
+CLEM24@WAKEF6
+CAL7@WASH46
+BOST27@WVA14
+ILL21@WIS3
+>N3
+BYU54@USAF7
+NIL31@AKRON28
+OR-ST9@AZ-ST34
+RICE19@ARK11
+RUTG31@ARMY35
+SYR35@BOST6
+BALL13@CMICH3
+LOUVL41@CINCI16
+NCAR3@CLEM20
+WYO8@CO-ST31
+COLUM20@DART34
+WAKEF20@DUKE57
+AUBN7@FLA48
+LAFAY59@FORD14
+BROWN37@HARV52
+NMEX16@HI43
+BUCK14@HOLY43
+TCU35@HOUST56
+IOWA54@ILL28
+IA-ST14@KS-ST28
+BOWLG20@KENTS16
+COLG7@LHIGH52
+MISS19@LSU10
+ECAR24@MEMPH17
+PITT0@MIFL45
+EMICH14@MIOH34
+IND20@MI-ST45
+BAMA22@MS-ST0
+OK55@MO10
+NDAME52@NAVY31
+COLO27@NEB12
+FRES45@UNLV18
+NW7@OSU48
+KAS31@OK-ST30
+UCLA24@OR28
+PENN20@PRIN34
+MICH38@PURD13
+UTAH14@SDSU66
+FULL6@SJSU44
+FL-ST41@SCAR10
+CAL31@USC31
+TA&M38@SMU17
+SMISS14@SWLA13
+WA-ST13@STAN31
+TEMP20@TENN41
+TEX41@TTECH22
+NM-ST10@UT-ST55
+GTECH41@VA38
+NC-ST16@VTECH20
+AZ10@WASH54
+PA-ST31@WVA19
+TOL37@WMICH9
+MINN21@WIS3
+CORN41@YALE31
+>N10
+LSU3@BAMA24
+STAN23@AZ10
+USAF15@ARMY3
+SMISS13@AUBN12
+ARK3@BAYL34
+WMICH19@BOWLG13
+DART29@BROWN0
+OR3@CAL28
+LAFAY7@COLG36
+OK-ST22@COLO41
+TULSA13@CO-ST31
+CORN41@COLUM0
+NIL20@ECAR24
+BALL20@EMICH13
+GA7@FLA38
+CINCI21@FL-ST70
+HOLY48@FORD0
+PAC17@FRES48
+UT-ST45@FULL17
+VTECH3@GTECH6
+WIS7@IND20
+OSU27@IOWA26
+MO25@IA-ST27
+NEB41@KAS9
+VAND21@KY28
+BUCK30@LHIGH27
+AKRON15@LTECH36
+BOST10@LOUVL17
+MS-ST27@MEMPH23
+KENTS10@MIOH31
+ILL17@MICH22
+MI-ST28@MINN16
+UTAH29@NMEX27
+SJSU56@NM-ST20
+VA24@NCAR10
+DUKE0@NC-ST16
+PURD33@NW13
+CMICH52@OU7
+KS-ST7@OK34
+USC56@OR-ST7
+MD10@PA-ST24
+HARV20@PENN24
+TEMP28@PITT18
+SMU28@RICE30
+WVA28@RUTG3
+HI38@SDSU44
+TUL26@SYR24
+NDAME34@TENN29
+HOUST24@TEX45
+TTECH40@TCU28
+NAVY14@TOL10
+UCLA25@WASH22
+AZ-ST51@WA-ST26
+BYU45@WYO14
+PRIN7@YALE34
+>N17
+CINCI7@BAMA45
+TA&M20@ARK16
+GA10@AUBN33
+OU6@BALL23
+FORD7@BUCK44
+STAN27@CAL25
+SCAR15@CLEM24
+HOLY35@COLG6
+KS-ST3@COLO64
+BROWN17@COLUM0
+PENN15@CORN21
+NCAR24@DUKE22
+YALE34@HARV19
+WYO17@HI38
+ILL24@IND10
+PURD9@IOWA38
+OK-ST25@IA-ST17
+MO31@KAS21
+EMICH24@KENTS25
+FLA47@KY15
+LHIGH35@LAFAY14
+UNLV20@LBSU29
+CO-ST30@LTECH31
+FL-ST35,MEMPH3
+BOST12@MIFL42
+MINN18@MICH35
+LSU22@MS-ST34
+SDSU40@NMEX34
+FULL9@NM-ST43
+MI-ST29@NW22
+PA-ST24@NDAME21
+OR6@OR-ST3
+DART23@PRIN6
+BAYL17@RICE16
+FRES7@SJSU42
+NIL20@SWLA24
+RUTG22@TEMP29
+MISS13@TENN22
+TEX38@TCU10
+USAF14@UTEP13
+SMU7@TTECH62
+USC45@UCLA42
+BYU42@UTAH22
+PAC45@UT-ST51
+ARMY42@VAND38
+MD35@VA30
+GTECH42@WAKEF7
+WASH55@WA-ST10
+SYR31@WVA7
+MIOH17@WMICH31
+OSU35@WIS10
+>N22
+WVA10@SCAR29
+>N23
+NEB10@OK45
+>N24
+AZ-ST17@AZ21
+TEX23@BAYL13
+TEMP29@BOST10
+UT-ST10@BYU45
+CO-ST30@HI27
+NW23@ILL28
+TUL13@LSU16
+SYR7@MIFL33
+WIS9@MI-ST14
+IOWA24@MINN31
+MS-ST9@MISS21
+MICH16@OSU13
+PITT17@PA-ST22
+IND28@PURD14
+UTEP31@SDSU58
+NDAME10@USC6
+ARK42@SMU29
+KY28@TENN42
+TCU10@TA&M56
+WAKEF56@VAND28
+VA13@VTECH38
+>D1
+HOUST62,AZ-ST45
+BAMA16,AUBN7
+FLA30@FL-ST45
+GTECH40@GA23
+BYU28@HI59
+MIFL30@SDSU28
+TA&M27@TEX28
+TENN49@VAND20
+>D8
+NAVY20@ARMY30
+SJSU48,CMICH24
+>D15
+LTECH34,MD34
+>D25
+SYR28,AZ0
+>D27
+USAF23,OSU11
+>D28
+FL-ST24,PA-ST17
+NC-ST31,SMISS27
+>D29
+TA&M65,BYU14
+AUBN27,IND23
+CO-ST32,OR31
+>D31
+MI-ST17,USC16
+CAL17,WYO15
+>J1
+LOUVL34,BAMA7
+CLEM30,ILL0
+WASH46,IOWA34
+MICH35,MISS3
+GTECH45,NEB21
+COLO10,NDAME9
+MIFL46,TEX3
+TENN23,VA22
+* End of file "games.dat"
diff --git a/support/graphbase/gb_basic.w b/support/graphbase/gb_basic.w
new file mode 100644
index 0000000000..eff1ee68fd
--- /dev/null
+++ b/support/graphbase/gb_basic.w
@@ -0,0 +1,2415 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace BASIC}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GRAPH}
+@* Introduction. This GraphBase module contains six subroutines that generate
+standard graphs of various types, together with six routines that combine or
+transform existing graphs.
+
+Simple examples of the use of these routines can be found in the
+demonstration programs |queen| and |queen_wrap|.
+
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@<gb_basic.h@>=
+extern Graph *board(); /* moves on generalized chessboards */
+extern Graph *simplex(); /* generalized triangular configurations */
+extern Graph *subsets(); /* patterns of subset intersection */
+extern Graph *perms(); /* permutations of a multiset */
+extern Graph *parts(); /* partitions of an integer */
+extern Graph *binary(); /* binary trees */
+@#
+extern Graph *complement(); /* the complement of a graph */
+extern Graph *gunion(); /* the union of two graphs */
+extern Graph *intersection(); /* the intersection of two graphs */
+extern Graph *lines(); /* the line graph of a graph */
+extern Graph *product(); /* the product of two graphs */
+extern Graph *induced(); /* a graph induced from another */
+
+@ The \Cee\ file \.{gb\_basic.c} has the following overall shape:
+
+@p
+#include "gb_graph.h" /* we use the |gb_graph| data structures */
+@#
+@<Private variables@>@;
+@<Basic subroutines@>@;
+@<Applications of basic subroutines@>@;
+
+@ Several of the programs below allocate arrays that will be freed again
+before the routine is finished.
+
+@<Private variables@>=
+static Area working_storage;
+
+@ If a graph-generating subroutine encounters a problem, it returns |NULL|
+(that is, \.{NULL}), after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise the routine returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in |gb_graph|.)
+
+@d panic(c)
+ {@+panic_code=c;
+ gb_free(working_storage);
+ gb_alloc_trouble=0;
+ return NULL;
+ }
+
+@ The names of vertices are sometimes formed from the names of other
+vertices, or from potentially long sequences of numbers. We assemble
+them in the |buffer| array, which is sufficiently long that the
+vast majority of applications will be unconstrained by size limitations.
+The programs do always make sure that |BUF_SIZE| is not exceeded, but
+they assume that it is rather large.
+
+@d BUF_SIZE 4096
+
+@<Private v...@>=
+static char buffer[BUF_SIZE];
+
+@*Grids and game boards. The subroutine call
+`|board(n1,n2,n3,n4,piece,wrap,directed)|'
+constructs a graph based on the moves of generalized chesspieces on a
+generalized rectangular board. Each vertex of the graph corresponds to a
+position on the board. Each arc of the graph corresponds to a move from
+one position to another.
+
+The first parameters, |n1| through |n4|, specify the size of the board.
+If, for example, a two-dimensional board with $n_1$ rows and $n_2$ columns
+is desired, you set $|n1|=n_1$, $|n2|=n_2$, and $|n3|=0$; the resulting
+graph will have $n_1n_2$ vertices. If you want a three-dimensional
+board with $n_3$ layers, set $|n3|=n_3$ and $n_4=0$. If you want
+a four-dimensional board, put the number of 4th coordinates in~|n4|.
+If you want a $d$-dimensional board with $2^d$ positions, set |n1=2|
+and |n2=-d|.
+
+In general, the |board| subroutine determines the dimensions by scanning the
+sequence |(n1,n2,n3,n4,0)=@t$(n_1,n_2,n_3,n_4,0)$@>| from left to right
+until coming to the first nonpositive parameter $n_{k+1}$. If $k=0$
+(i.e., if |n1<=0|), the default size $8\times8$ will be used; this is
+an ordinary chessboard with 8~rows and 8~columns. Otherwise if $n_{k+1}=0$,
+the board will have $k$~dimensions $n_1$, \dots,~$n_k$. Otherwise
+we must have $n_{k+1}<0$; in this case the board will have $d=\vert n_{k+1}
+\vert$ dimensions, chosen as the first $d$ elements of the infinite
+periodic sequence $(n_1,\ldots,n_k,n_1,\ldots,n_k,n_1,\ldots\,)$.
+For example, the specification |(n1,n2,n3,n4)=(2,3,5,-7)| is about as
+tricky as you can get. It produces a seven-dimensional board with
+dimensions $(n_1,\ldots,n_7)=(2,3,5,2,3,5,2)$, hence a graph with
+$2\cdot3\cdot5\cdot2\cdot3\cdot5\cdot2=1800$ vertices.
+
+The |piece| parameter specifies the legal moves of a generalized chesspiece.
+If |piece>0|, a move from position~|u| to position~|v| is considered legal
+if and only if the Euclidean distance between points |u| and~|v| is
+equal to $\sqrt{\vphantom1\smash{|piece|}}$.
+For example, if |piece=1| and if we have a
+two-dimensional board, the legal moves from $(x,y)$ are to $(x,y\pm1)$ and
+$(x\pm1,y)$; these are the moves of a so-called wazir, the only moves that
+a king and a rook can both make. If |piece=2|, the legal moves from $(x,y)$
+are to $(x\pm1,y\pm1)$; these are the four moves that a king and a bishop
+can both make. (A piece that can make only these moves was called a ``fers''
+in ancient Muslim chess.) If |piece=5|, the legal moves are those of a
+knight, from $(x,y)$ to $(x\pm1,y\pm2)$ or to $(x\pm2,y\pm1)$. If |piece=3|,
+there are no legal moves on a two-dimensional board, but moves from
+$(x,y,z)$ to $(x\pm1,y\pm1,z\pm1)$ would be legal in three dimensions.
+If |piece=0|, it is changed to the default value |piece=1|.
+
+If the value of |piece| is negative, arbitrary multiples of the basic moves
+for $\vert|piece|\vert$ are permitted. For example, |piece=-1| defines the
+moves of a rook, from $(x,y)$ to $(x\pm a,y)$ or to $(x,y\pm a)$ for all
+$a>0$; |piece=-2| defines the moves of a bishop, from $(x,y)$ to
+$(x\pm a,y\pm a)$. The literature of ``fairy chess'' assigns standard names
+to the following |piece| values: $\rm wazir=1$, $\rm fers=2$, $\rm dabbaba=4$,
+$\rm knight=5$, $\rm alfil=8$, $\rm camel=10$, $\rm zebra=13$, $\rm giraffe
+=17$, $\rm fiveleaper=25$, $\hbox{root-50-leaper}=50$, etc.; $\rm rook=-1$,
+$\rm bishop=-2$, $\rm unicorn=-3$, $\rm dabbabarider=-4$, $\rm nightrider=-5$,
+$\rm alfilrider=-8$, $\rm camelrider=-10$, etc.
+
+To generate a board with the moves of a king, you can use the |gunion|
+subroutine below to take the union of boards with |piece=1| and
+|piece=2|. Similarly, you can get queen moves by taking the union of
+boards with |piece=-1| and |piece=-2|.
+
+If |piece>0|, all arcs of the graph will have length~1. If |piece<0|, the
+length of each arc will be the number of multiples of a basic move that
+produced the arc.
+
+@ If the |wrap| parameter is nonzero, it specifies a subset of coordinates
+in which values are computed modulo the corresponding size.
+For example, the coordinates $(x,y)$ for vertices on a two-dimensional
+board are restricted to the range $0\le x<n_1$, $0\le y<n_2$; when
+|wrap=0|, a move from $(x,y)$ to $(x+\delta_1,y+\delta_2)$ is
+therefore legal only if $0\le x+\delta_1<n_1$ and $0\le
+y+\delta_2<n_2$. But when |wrap=1|, the $x$~coordinates are allowed to
+``wrap around''; the move would then be made to $((x+\delta_1)\bmod
+n_1,y+\delta_2)$, provided that $0\le y+\delta_2<n_2$. Setting
+|wrap=1| effectively makes the board into a cylinder instead of a
+rectangle. Similarly, the $y$~coordinates are allowed to wrap around
+when |wrap=2|. Both $x$ and $y$ coordinates are treated modulo their
+corresponding sizes when |wrap=3|; the board is then effectively a
+torus. In general, coordinates $k_1$, $k_2$, \dots~ will wrap around
+when $|wrap|=2^{k_1-1}+2^{k_2-1}+\cdots\,$. Setting |wrap=-1| causes all
+coordinates to be computed modulo their size.
+
+The graph constructed by |board| will be undirected unless |directed!=0|.
+Directed |board| graphs will be acyclic when |wrap=0|, but they may
+have cycles when |wrap!=0|. Precise rules defining the directed arcs
+are given below.
+
+Several important special cases are worth noting: To get the complete graph
+on |n| vertices, you can say |board(n,0,0,0,-1,0,0)|. To get the
+transitive tournament on |n| vertices, i.e., the directed graph
+with arcs from |u| to |v| when |u<v|, you can say |board(n,0,0,0,-1,0,1)|.
+To get the empty graph on |n| vertices, you can say |board(n,0,0,0,2,0,0)|.
+To get a circuit (undirected) or a cycle (directed) of length~|n|,
+you can say |board(n,0,0,0,1,1,0)| and |board(n,0,0,0,1,1,1)|,
+respectively.
+
+@(gb_basic.h@>=
+#define complete(n) @[board(n,0,0,0,-1,0,0)@]
+#define transitive(n) @[board(n,0,0,0,-1,0,1)@]
+#define empty(n) @[board(n,0,0,0,2,0,0)@]
+#define circuit(n) @[board(n,0,0,0,1,1,0)@]
+#define cycle(n) @[board(n,0,0,0,1,1,1)@]
+
+
+@ @<Basic subroutines@>=
+Graph *board(n1,n2,n3,n4,piece,wrap,directed)
+ int n1,n2,n3,n4; /* size of board desired */
+ int piece; /* type of moves desired */
+ long wrap; /* mask for coordinate positions that wrap around */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ long n; /* total number of vertices */
+ int p; /* $\vert|piece|\vert$ */
+ int l; /* length of current arc */
+ @<Normalize the board-size parameters@>;
+ @<Set up a graph with |n| vertices@>;
+ @<Insert arcs or edges for all legal moves@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* alas, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ Most of the subroutines in |gb_basic| use the following local
+variables.
+
+@<Vanilla local variables@>=
+Graph *new_graph; /* the graph being constructed */
+register int i,j,k; /* all-purpose indices */
+register int d; /* the number of dimensions */
+register Vertex *v; /* the current vertex of interest */
+register long s; /* accumulator */
+
+@ Several arrays will facilitate the calculations that |board| needs to make:
+The number of distinct values in coordinate position~$k$ will be |nn[k]|;
+this coordinate position will wrap around if and only if |wr[k]!=0|.
+The current moves under consideration will be from $(x_1,\ldots,x_d)$
+to $(x_1+\delta_1,\ldots, x_k+\delta_k)$, where $\delta_k$ is stored
+in |del[k]|. An auxiliary array |sig| holds the sums
+$\sigma_k=\delta_1^2+\cdots+\delta_{k-1}^2$. Additional arrays |xx|
+and |yy| hold coordinates of vertices before and after a move is made.
+
+Some of these arrays are also used for other purposes by other programs
+besides |board|; we will meet those programs later.
+
+We limit the number of dimensions to 91 or less. This is hardly a limitation,
+since the number of vertices would be astronomical even if the dimensionality
+were only half this big. But some of our later programs will be able
+to make good use of 40 or 50 dimensions and perhaps more; the number 91
+is an upper limit imposed by the number of standard printable characters
+(see the convention for vertex names in the |perms| routine).
+
+@d MAX_D 91
+
+@<Private...@>=
+static int nn[MAX_D+1]; /* component sizes */
+static int wr[MAX_D+1]; /* does this component wrap around? */
+static int del[MAX_D+1]; /* displacements for the current move */
+static int sig[MAX_D+2]; /* partial sums of squares of displacements */
+static int xx[MAX_D+1], yy[MAX_D+1]; /* coordinate values */
+
+@ @<Normalize the board-size parameters@>=
+if (piece==0) piece=1;
+if (n1<=0) {@+n1=n2=8;@+n3=0;@+}
+nn[1]=n1;
+if (n2<=0) {@+k=2;@+d=-n2;@+n3=n4=0;@+}
+else {
+ nn[2]=n2;
+ if (n3<=0) {@+k=3;@+d=-n3;@+n4=0;@+}
+ else {
+ nn[3]=n3;
+ if (n4<=0) {@+k=4;@+d=-n4;@+}
+ else {@+nn[4]=n4;@+d=4;@+goto done;@+}
+ }
+}
+if (d==0) {@+d=k-1;@+goto done;@+}
+@<Compute component sizes periodically for |d| dimensions@>;
+done: /* now |nn[1]| through |nn[d]| are set up */
+
+@ At this point, |nn[1]| through |nn[k-1]| are the component sizes
+that should be replicated periodically. In unusual cases, the number
+of dimensions might not be as large as the number of specifications.
+
+@<Compute component sizes periodically...@>=
+if (d>MAX_D) panic(bad_specs); /* too many dimensions */
+for (j=1; k<=d; j++,k++) nn[k]=nn[j];
+
+@ We want to make the subroutine idiot-proof, so we use floating-point
+arithmetic to make sure that boards with more than a billion cells have
+not been specified.
+
+@d MAX_NNN 1000000000.0
+
+@<Set up a graph with |n| vertices@>=
+{@+float nnn; /* approximate size */
+ for (n=1,nnn=1.0,j=1; j<=d; j++) {
+ nnn *= (float)nn[j];
+ if (nnn>MAX_NNN) panic(very_bad_specs); /* way too big */
+ n *= nn[j]; /* this multiplication cannot cause integer overflow */
+ }
+ new_graph=gb_new_graph(n);
+ if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+ sprintf(new_graph->id,"board(%d,%d,%d,%d,%d,%ld,%d)",
+ n1,n2,n3,n4,piece,wrap,directed?1:0);
+ strcpy(new_graph->format,"ZZZIIIZZZZZZZZ");
+ @<Give names to the vertices@>;
+}
+
+@ The symbolic name of a board position like $(3,1)$ will be the string
+`\.{3.1}'. The first three coordinates are also stored as integers, in
+utility fields |x.i|, |y.i|, and |z.i|, because immediate access to
+those values will be helpful in certain applications. (The coordinates can,
+of course, always be recovered in a slower fashion from the vertex name,
+via |sscanf|.)
+
+The process of assigning coordinate values and names is equivalent to
+adding unity in a mixed-radix number system. Vertex $(x_1,\ldots,x_d)$
+will be in position $x_1n_2\ldots n_d+\cdots+x_{d-1}n_d+x_d$ relative
+to the first vertex of the new graph; therefore it is also possible to
+deduce the coordinates of a vertex from its address.
+
+@<Give names...@>=
+{@+register char *p; /* string pointer */
+ nn[0]=xx[0]=xx[1]=xx[2]=xx[3]=0;
+ for (k=4;k<=d;k++) xx[k]=0;
+ for (v=new_graph->vertices;;v++) {
+ p=buffer;
+ for (k=1;k<=d;k++) {
+ sprintf(p,".%d",xx[k]);
+ while (*p) p++;
+ }
+ v->name=gb_save_string(&buffer[1]); /* omit |buffer[0]|, which is |'.'| */
+ v->x.i=xx[1];@+v->y.i=xx[2];@+v->z.i=xx[3];
+ for (k=d;xx[k]+1==nn[k];k--) xx[k]=0;
+ if (k==0) break; /* a ``carry'' has occurred all the way to the left */
+ xx[k]++; /* increase coordinate |k| */
+ }
+}
+
+@ Now we come to a slightly tricky part of the routine, the move generator.
+Let $p=\vert|piece|\vert$. The outer loop of this procedure runs through all
+solutions of the equation $\delta_1^2+\cdots+\delta_d^2=p$, where the
+$\delta$'s are nonnegative integers. Within that loop, we attach signs
+to the $\delta$'s, but always leaving $\delta_k$ positive if $\delta_1=
+\cdots=\delta_{k-1}=0$. For every such vector~$\delta$, we generate moves
+from |v| to $v+\delta$ for every vertex |v|. When |directed=0|,
+we use |gb_new_edge| instead of |gb_new_arc|, so that the reverse arc
+from $v+\delta$ to~|v| is also generated.
+
+@<Insert arcs or edges for all legal moves@>=
+@<Initialize the |wr|, |sig|, and |del| tables@>;
+p=piece;
+if (p<0) p=-p;
+while (1) {
+ @<Advance to the next nonnegative |del| vector, or |break| if done@>;
+ while (1) {
+ @<Generate moves for the current |del| vector@>;
+ @<Advance to the next signed |del| vector, or restore |del|
+ to nonnegative values and |break|@>;
+ }
+}
+
+@ The \Cee\ language does not define |>>| unambiguously. If |w| is negative,
+the assignment `|w>>=1|' here should keep |w| negative.
+(However, this technicality doesn't matter except in highly unusual cases
+when there are more than 32 dimensions.)
+@^system dependencies@>
+
+@<Initialize the |wr|, |sig|, and |del| tables@>=
+{@+register long w=wrap;
+ for (k=1;k<=d;k++,w>>=1) {
+ wr[k]=w&1;
+ del[k]=sig[k]=0;
+ }
+ sig[0]=del[0]=sig[d+1]=0;
+}
+
+@ @<Advance to the next nonnegative |del|...@>=
+for (k=d;sig[k]+(del[k]+1)*(del[k]+1)>p;k--) del[k]=0;
+if (k==0) break;
+del[k]++;
+sig[k+1]=sig[k]+del[k]*del[k];
+for (k++;k<=d;k++) sig[k+1]=sig[k];
+if (sig[d+1]<p) continue;
+
+@ @<Advance to the next signed |del| vector, or restore |del|
+ to nonnegative values and |break|@>=
+for (k=d;del[k]<=0;k--) del[k]=-del[k];
+if (sig[k]==0) break; /* all but |del[k]| were negative or zero */
+del[k]=-del[k]; /* some entry preceding |del[k]| is positive */
+
+@ We use the mixed-radix addition technique again when generating moves.
+
+@<Generate moves for the current |del| vector@>=
+for (k=1;k<=d;k++) xx[k]=0;
+for (v=new_graph->vertices;;v++) {
+ @<Generate moves from |v| corresponding to |del|@>;
+ for (k=d;xx[k]+1==nn[k];k--) xx[k]=0;
+ if (k==0) break; /* a ``carry'' has occurred all the way to the left */
+ xx[k]++; /* increase coordinate |k| */
+}
+
+@ The legal moves when |piece| is negative are derived as follows, in
+the presence of possible wraparound: Starting at $(x_1,\ldots,x_d)$, we
+move to $(x_1+\delta_1,\ldots,x_d+\delta_d)$, $(x_1+2\delta_1,\ldots,
+x_d+2\delta_d)$,~\dots, until either coming to a position with a nonwrapped
+coordinate out of range or coming back to the original point.
+
+A subtle technicality should be noted: When coordinates are wrapped and
+|piece>0|, self-loops are possible---for example, in |board(1,0,0,0,1,1,1)|.
+But self-loops never arise when |piece<0|.
+
+@<Generate moves from |v|...@>=
+for (k=1;k<=d;k++) yy[k]=xx[k]+del[k];
+for (l=1;;l++) {
+ @<Correct for wraparound, or |goto no_more| if off the board@>;
+ if (piece<0) @<Go to |no_more| if |yy=xx|@>;
+ @<Record a legal move from |xx| to |yy|@>;
+ if (piece>0) goto no_more;
+ for (k=1;k<=d;k++) yy[k]+=del[k];
+}
+no_more:
+
+@ @<Go to |no_more|...@>=
+{
+ for (k=1;k<=d;k++) if (yy[k]!=xx[k]) goto unequal;
+ goto no_more;
+ unequal:;
+}
+
+@ @<Correct for wraparound, or |goto no_more| if off the board@>=
+for (k=1;k<=d;k++) {
+ if (yy[k]<0) {
+ if (!wr[k]) goto no_more;
+ do yy[k]+=nn[k];@+ while (yy[k]<0);
+ } else if (yy[k]>=nn[k]) {
+ if (!wr[k]) goto no_more;
+ do yy[k]-=nn[k];@+ while (yy[k]>=nn[k]);
+ }
+}
+
+@ @<Record a legal move from |xx| to |yy|@>=
+for (k=2,j=yy[1];k<=d;k++) j=nn[k]*j+yy[k];
+if (directed) gb_new_arc(v,new_graph->vertices+j,l);
+else gb_new_edge(v,new_graph->vertices+j,l);
+
+@* Generalized triangular boards. The subroutine call
+`|simplex(n,n0,n1,n2,n3,n4,directed)|' creates a graph based on
+generalized triangular or tetrahedral configurations. Such graphs are
+similar in spirit to the game boards created by |board|, but they
+pertain to nonrectangular grids like those in ``Chinese checkers.'' As
+with |board| in the case |piece=1|, the vertices represent board positions,
+and the arcs run from board positions to their nearest neighbors. Each arc has
+length~1.{\tolerance=1000\par}
+
+More formallly, the vertices can be defined as sequences of nonnegative
+integers $(x_0,x_1,\ldots,x_d)$ whose sum is~|n|, where two sequences
+are considered adjacent if and only if they differ by $\pm1$ in exactly
+two components---equivalently, if the Euclidean distance between them
+is~$\sqrt2$. When $d=2$, for example, the vertices can be visualized
+as a triangular array
+$$\vcenter{\halign{&\hbox to 2em{\hss$#$\hss}\cr
+&&&(0,0,3)\cr
+&&(0,1,2)&&(1,0,2)\cr
+&(0,2,1)&&(1,1,1)&&(2,0,1)\cr
+(0,3,0)&&(1,2,0)&&(2,1,0)&&(3,0,0)\cr}}$$
+containing $(n+1)(n+2)/2$ elements, illustrated here when $n=3$; each vertex of
+the array has up to 6 neighbors. When $d=3$ the vertices form a tetrahedral
+array, a stack of triangular layers, and they can have as many as 12
+neighbors. In general, a vertex in a $d$-simplicial array will have up to
+$d(d+1)$ neighbors.
+
+If the |directed| parameter is nonzero, arcs run only form vertices to neighbors
+that are lexicographically greater---for example, downward or to the right
+in the triangular array shown. The directed graph is therefore acyclic,
+and a vertex of a $d$-simplicial array has out-degree at most $d(d+1)/2$.
+
+@ The first parameter, |n|, specifies the sum of the coordinates
+$(x_0,x_1,\ldots,x_d)$. The following parameters |n0| through |n4| specify
+upper bounds on those coordinates, and they also specify the dimensionality~|d|.
+
+If, for example, |n0|, |n1|, and |n2| are positive while |n3=0|, the
+value of~|d| will be~2 and the coordinates will be constrained to
+satisfy $0\le x_0\le|n0|$, $0\le x_1\le|n1|$, $0\le x_2\le|n2|$. These
+upper bounds essentially lop off the corners of the triangular array.
+We obtain a hexagonal board with $6m$ boundary cells by asking for
+|simplex(3m,2m,2m,2m,0,0,0)|. We obtain the diamond-shaped board used
+in the game of Hex [Martin Gardner, {\sl The Scientific American
+Book of Mathematical Puzzles {\char`\&} Diversions\/} (Simon {\char`\&}
+Schuster, 1959), Chapter~8] by calling |simplex(20,10,20,10,0,0,0)|.
+
+In general, |simplex| determines |d| and upper bounds $(n_0,n_1,\ldots,n_d)$
+in the following way: Let the first nonpositive entry of the sequence
+|(n0,n1,n2,n3,n4,0)|$\null=(n_0,n_1,n_2,n_3,n_4,0)$ be~$n_k$. If $k>0$
+and $n_k=0$, the value of~$d$ will be $k-1$ and the coordinates will be
+bounded by the given numbers $(n_0,\ldots,n_d)$. If $k>0$ and $n_k<0$,
+the value of~$d$ will be $\vert n_k\vert$ and the coordinates will be
+bounded by the first $d+1$ elements of the infinite periodic sequence
+$(n_0,\ldots,n_{k-1},n_0,\ldots,n_{k-1},n_0,\ldots\,)$. If $k=0$ and
+$n_0<0$, the value of~$d$ will be $\vert n_0\vert$ and the coordinates
+will be unbounded; equivalently, we may set $n_0=\cdots=n_d=n$. In
+this case the number of vertices will be $n+d\choose d$. Finally,
+if $k=0$ and $n_0=0$, we have the default case of a triangular array
+with $3n$ boundary cells, exactly as if $n_0=-2$.
+
+For example, the specification |n0=3|, |n1=-5| will produce all vertices
+$(x_0,x_1,\ldots,x_5)$ such that $x_0+x_1+\cdots+x_5=n$ and $0\le x_j\le3$.
+The specification |n0=1|, |n1=-d| will essentially produce all $n$-element
+subsets of the $(d+1)$-element set $\{0,1,\ldots,d\}$, because we can
+regard an element~$k$ as being present in the set if $x_k=1$, absent
+if $x_k=0$. In that case two subsets are adjacent if and only if
+they have exactly $n-1$ elements in common.
+
+@ @<Basic subroutines@>=
+Graph *simplex(n,n0,n1,n2,n3,n4,directed)
+ unsigned n; /* the constant sum of all coordinates */
+ int n0,n1,n2,n3,n4; /* constraints on coordinates */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ @<Normalize the simplex parameters@>;
+ @<Create a graph with one vertex for each point@>;
+ @<Name the points and create the arcs or edges@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* darn, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Normalize the simplex parameters@>=
+if (n0==0) n0=-2;
+if (n0<0) {@+k=2;@+nn[0]=n;@+d=-n0;@+n1=n2=n3=n4=0;@+}
+else {
+ if (n0>n) n0=n;
+ nn[0]=n0;
+ if (n1<=0) {@+k=2;@+d=-n1;@+n2=n3=n4=0;@+}
+ else {
+ if (n1>n) n1=n;
+ nn[1]=n1;
+ if (n2<=0) {@+k=3;@+d=-n2;@+n3=n4=0;@+}
+ else {
+ if (n2>n) n2=n;
+ nn[2]=n2;
+ if (n3<=0) {@+k=4;@+d=-n3;@+n4=0;@+}
+ else {
+ if (n3>n) n3=n;
+ nn[3]=n3;
+ if (n4<=0) {@+k=5;@+d=-n4;@+}
+ else {@+if (n4>n) n4=n;
+ nn[4]=n4;@+d=4;@+goto done;@+}
+ }
+ }
+ }
+}
+if (d==0) {@+d=k-2;@+goto done;@+}
+nn[k-1]=nn[0];
+@<Compute component sizes periodically...@>;
+done: /* now |nn[0]| through |nn[d]| are set up */
+
+@ @<Create a graph with one vertex for each point@>=
+@<Determine the number of feasible $(x_0,\ldots,x_d)$, and allocate the graph@>;
+sprintf(new_graph->id,"simplex(%u,%d,%d,%d,%d,%d,%d)",
+ n,n0,n1,n2,n3,n4,directed?1:0);
+strcpy(new_graph->format,"VVZIIIZZZZZZZZ"); /* hash table will be used */
+
+@ We determine the number of vertices by determining the coefficient of~$z^n$
+in the power series
+$$(1+z+\cdots+z^{n_0})(1+z+\cdots+z^{n_1})\ldots(1+z+\cdots+z^{n_d}).$$
+
+@<Determine the number of feasible $(x_0,\ldots,x_d)$...@>=
+{@+long nverts; /* the number of vertices */
+ register long *coef=gb_alloc_type(n+1,@[long@],working_storage);
+ if (gb_alloc_trouble) panic(no_room+1); /* can't allocate |coef| array */
+ for (k=0;k<=nn[0];k++) coef[k]=1;
+ /* now |coef| represents the coefficients of $1+z+\cdots+z^{n_0}$ */
+ for (j=1;j<=d;j++)
+ @<Multiply the power series coefficients by $1+z+\cdots+z^{n_j}$@>;
+ nverts=coef[n];
+ gb_free(working_storage); /* recycle the |coef| array */
+ new_graph=gb_new_graph(nverts);
+ if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+}
+
+@ There's a neat way to multiply by $1+z+\cdots+z^{n_j}$: We multiply
+first by $1-z^{n_j+1}$, then sum the coefficients.
+
+We want to detect impossibly large specifications without risking
+integer overflow. It is easy to do this because multiplication is being
+done via addition.
+
+@<Multiply the power series coefficients by $1+z+\cdots+z^{n_j}$@>=
+{
+ for (k=n,i=n-nn[j]-1;i>=0;k--,i--) coef[k]-=coef[i];
+ s=1;
+ for (k=1;k<=n;k++) {
+ s+=coef[k];
+ if (s>1000000000) panic(very_bad_specs); /* way too big */
+ coef[k]=s;
+ }
+}
+
+@ As we generate the vertices, it proves convenient to precompute an
+array containing the numbers $y_j=n_j+\cdots+n_d$, representing the
+largest possible sum of $x_j+\cdots+x_d$. We also want to maintain
+the numbers $\sigma_j=n-(x_0+\cdots+x_{j-1})=x_j+\cdots+x_d$. The
+conditions
+$$0\le x_j\le n_j, \qquad \sigma_j-y_{j+1}\le x_j\le \sigma_j$$
+are ``necessary and sufficient,'' in the sense that we can find at least
+one way to complete a partial solution $(x_0,\ldots,x_k)$ to a full
+solution $(x_0,\ldots,x_d)$ if and only if the conditions hold for
+all $j\le k$.
+
+There is at least one solution if and only if $n\le y_0$.
+
+We enter the name string into a hash table, using the |hash_in|
+routine of |gb_graph|, because there is no simple way to compute the
+location of a vertex from its coordinates.
+
+@<Name the points and create the arcs or edges@>=
+v=new_graph->vertices;
+yy[d+1]=0;@+sig[0]=n;
+for (k=d;k>=0;k--) yy[k]=yy[k+1]+nn[k];
+if (yy[0]>=n) {
+ k=0;@+xx[0]=(yy[1]>=n? 0: n-yy[1]);
+ while (1) {
+ @<Complete the partial solution $(x_0,\ldots,x_k)$@>;
+ @<Assign a symbolic name for $(x_0,\ldots,x_d)$ to vertex~|v|@>;
+ hash_in(v); /* enter |v->name| into the hash table
+ (via utility fields |u,v|) */
+ @<Create arcs or edges from previous points to~|v|@>;
+ v++;
+ @<Advance to the next partial solution $(x_0,\ldots,x_k)$, where |k| is
+ as large as possible; |goto last| if there are no more solutions@>;
+ }
+}
+last:@+if (v!=new_graph->vertices+new_graph->n)
+ panic(impossible); /* can't happen */
+
+@ @<Complete the partial solution $(x_0,\ldots,x_k)$@>=
+for (s=sig[k]-xx[k],k++;k<=d;s-=xx[k],k++) {
+ sig[k]=s;
+ if (s<=yy[k+1]) xx[k]=0;
+ else xx[k]=s-yy[k+1];
+}
+if (s!=0) panic(impossible+1) /* can't happen */
+
+@ Here we seek the largest $k$ such that $x_k$ can be increased without
+violating the necessary and sufficient conditions stated earlier.
+
+@<Advance to the next partial solution $(x_0,\ldots,x_k)$...@>=
+for (k=d-1;;k--) {
+ if (xx[k]<sig[k] && xx[k]<nn[k]) break;
+ if (k==0) goto last;
+}
+xx[k]++;
+
+@ As in the |board| routine, we represent the sequence of coordinates
+$(2,0,1)$ by the string `\.{2.0.1}'.
+The string won't exceed |BUF_SIZE|, because the ratio |BUF_SIZE/MAX_D| is
+plenty big.
+
+The first three coordinate values, $(x_0,x_1,x_2)$, are placed into
+utility fields |x|, |y|, and |z|, so that they can be accessed immediately
+if an application needs them.
+
+@<Assign a symbolic name for $(x_0,\ldots,x_d)$ to vertex~|v|@>=
+{@+register char *p=buffer; /* string pointer */
+ for (k=0;k<=d;k++) {
+ sprintf(p,".%d",xx[k]);
+ while (*p) p++;
+ }
+ v->name=gb_save_string(&buffer[1]); /* omit |buffer[0]|, which is |'.'| */
+ v->x.i=xx[0];@+v->y.i=xx[1];@+v->z.i=xx[2];
+}
+
+@ Since we are generating the vertices in lexicographic order of their
+coordinates, it is easy to identify all adjacent vertices that
+precede the current setting of $(x_0,x_1,\ldots,x_d)$. We locate them
+via their symbolic names.
+
+@<Create arcs or edges from previous points to~|v|@>=
+for (j=0;j<d;j++)
+ if (xx[j]) {@+register Vertex *u; /* previous vertex adjacent to |v| */
+ xx[j]--;
+ for (k=j+1;k<=d;k++)
+ if (xx[k]<nn[k]) {@+register char *p=buffer; /* string pointer */
+ xx[k]++;
+ for (i=0;i<=d;i++) {
+ sprintf(p,".%d",xx[i]);
+ while (*p) p++;
+ }
+ u=hash_out(&buffer[1]);
+ if (u==NULL) panic(impossible+2); /* can't happen */
+ if (directed) gb_new_arc(u,v,1);
+ else gb_new_edge(u,v,1);
+ xx[k]--;
+ }
+ xx[j]++;
+ }
+
+@* Subset graphs. The subroutine call
+`|subsets(n,n0,n1,n2,n3,n4,size_bits,directed)|'
+creates a graph having the same vertices as
+|simplex(n,n0,n1,n2,n3,n4,directed)| but with a quite different notion
+of adjacency. In this we interpret a solution $(x_0,x_1,\ldots,x_d)$ to
+the conditions $x_0+x_1+\cdots+x_d=n$ and $0\le x_j\le n_j$ not as a
+position on a game board but as a submultiset of the multiset
+$\{n_0\cdot0,n_1\cdot 1,\ldots,n_d\cdot d\}$, having $x_j$ elements
+equal to~$j$. (If each $n_j=1$, the multiset is a set; this is an
+important special case.) Two vertices are adjacent if and only if
+their intersection has a cardinality that matches one of the bits in
+|size_bits|, which is an unsigned integer. Each arc has length~1.
+
+For example, suppose $n=3$ and |(n0,n1,n2,n3)=(2,2,2,0)|. Then the vertices
+are the 3-element submultisets of $\{0,0,1,1,2,2\}$, namely
+$$\{0,0,1\},\quad \{0,0,2\},\quad \{0,1,2\},\quad
+\{0,2,2\},\quad \{1,1,2\},\quad \{1,2,2\},$$
+which are represented by the respective vectors
+$$(2,1,0),\quad (2,0,1),\quad (1,1,1),\quad
+(1,0,2),\quad (0,2,1),\quad (0,1,2).$$
+The intersection of multisets represented by $(x_0,x_1,\ldots,x_d)$ and
+$(y_0,y_1,\ldots,y_d)$ is $$\bigl(\min(x_0,y_0),\min(x_1,y_1),\ldots,
+\min(x_d,y_d)\bigr);$$ each element occurs as often as it occurs
+in both multisets being intersected. If now |size_bits=3|, the
+multisets will be considered adjacent whenever their
+intersection contains exactly 0 or~1 elements, because $3=2^0+2^1$.
+The vertices adjacent to $\{0,0,1\}$ will, for example, be
+$\{0,2,2\}$ and $\{1,2,2\}$. In this case, every pair of submultisets
+has a nonempty intersection, so the same graph would be obtained
+if |size_bits=2|.
+
+If |directed| is nonzero, the graph will have directed arcs, from |u|
+to~|v| only if $u\le v$. Notice that the graph will have self-loops if
+and only if the binary representation of |size_bits| contains the term
+$2^n$, in which case there will be a loop from every vertex to itself.
+(In an undirected graph, such loops are represented by two arcs.)
+
+We define a macro |disjoint_subsets(n,k)| for the case
+of $n\choose k$ vertices, adjacent if and only if they represent
+disjoint $k$-subsets of an $n$-set.
+One important special case is the Petersen graph, whose vertices
+are the 2-element subsets of $\{0,1,2,3,4\}$, adjacent when they
+are disjoint. This graph is remarkable because it contains 10 vertices,
+each of degree~3, but it has no circuits of length less than~5.
+
+@(gb_basic.h@>=
+#define disjoint_subsets(n,k) @[subsets(k,1,1-n,0,0,0,1,0)@]
+#define petersen() @[disjoint_subsets(5,2)@]
+
+@ @<Basic subroutines@>=
+Graph *subsets(n,n0,n1,n2,n3,n4,size_bits,directed)
+ unsigned n; /* the number of elements in the multiset */
+ int n0,n1,n2,n3,n4; /* multiplicities of elements */
+ unsigned long size_bits; /* intersection sizes that trigger arcs */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ @<Normalize the simplex parameters@>;
+ @<Create a graph with one vertex for each subset@>;
+ @<Name the subsets and create the arcs or edges@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* rats, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Create a graph with one vertex for each subset@>=
+@<Determine the number of feasible $(x_0,\ldots,x_d)$, and allocate the graph@>;
+sprintf(new_graph->id,"subsets(%u,%d,%d,%d,%d,%d,0x%lx,%d)",
+ n,n0,n1,n2,n3,n4,size_bits,directed?1:0);
+strcpy(new_graph->format,"ZZZIIIZZZZZZZZ"); /* hash table will not be used */
+
+@ We generate the vertices with exactly the logic used in |simplex|.
+
+@<Name the subsets and create the arcs or edges@>=
+v=new_graph->vertices;
+yy[d+1]=0;@+sig[0]=n;
+for (k=d;k>=0;k--) yy[k]=yy[k+1]+nn[k];
+if (yy[0]>=n) {
+ k=0;@+xx[0]=(yy[1]>=n? 0: n-yy[1]);
+ while (1) {
+ @<Complete the partial solution $(x_0,\ldots,x_k)$@>;
+ @<Assign a symbolic name for $(x_0,\ldots,x_d)$ to vertex~|v|@>;
+ @<Create arcs or edges from previous subsets to~|v|@>;
+ v++;
+ @<Advance to the next partial solution $(x_0,\ldots,x_k)$, where |k| is
+ as large as possible; |goto last| if there are no more solutions@>;
+ }
+}
+last:@+if (v!=new_graph->vertices+new_graph->n)
+ panic(impossible); /* can't happen */
+
+@ The only difference is that we generate the arcs or edges by brute
+force, examining each pair of vertices to see if they are adjacent or not.
+
+The code here is character-set dependent: It assumes that `\..' and null
+have a character code less than `\.0', as in ASCII. It also assumes
+that characters occupy exactly eight bits.
+@^system dependencies@>
+
+@d UL_BITS 8*sizeof(unsigned long) /* the number of bits in |size_bits| */
+
+@<Create arcs or edges from previous subsets to~|v|@>=
+{@+register Vertex *u;
+ for (u=new_graph->vertices;u<=v;u++) {@+register char *p=u->name;
+ int ss=0; /* the number of elements common to |u| and |v| */
+ for (j=0;j<=d;j++,p++) {
+ for (s=(*p++)-'0';*p>='0';p++) s=10*s+*p-'0'; /* |sscanf(p,"%d",&s)| */
+@^character-set dependencies@>
+ if (xx[j]<s) ss+=xx[j];
+ else ss+=s;
+ }
+ if ((size_bits&(((unsigned long)1)<<ss))&& ss<UL_BITS) {
+ if (directed) gb_new_arc(u,v,1);
+ else gb_new_edge(u,v,1);
+ }
+ }
+}
+
+@* Permutation graphs. The subroutine call
+`|perms(n0,n1,n2,n3,n4,max_inv,directed)|'
+creates a graph whose vertices represent the permutations of a
+multiset, having at most |max_inv| inversions. Two permutations are adjacent
+in the graph if one is obtained from the other by interchanging two
+adjacent elements. Each arc has length~1.
+
+For example, the multiset $\{0,0,1,2\}$ has twelve permutations:
+$$\vcenter{\halign{#&&\quad#\cr
+0012,&0021,&0102,&0120,&0201,&0210,\cr
+1002,&1020,&1200,&2001,&2010,&2100.\cr}}$$
+The first of these, 0012, has two neighbors, 0021 and 0102.
+
+The number of inversions is the number of pairs of elements $xy$ such
+that $x>y$ and $x$ precedes $y$ from left to right, counting
+multiplicity. For example, 2010 has four inversions, corresponding to
+$xy\in\{20,21,20,10\}$. When two permutations are adjacent, one of
+them has exactly one more inversion than the other. It is not
+difficult to verify that the number of inversions of a permutation is
+equal to the distance in the graph from that permutation to the
+lexicographically first permutation.
+
+Parameters |n0| through |n4| specify the composition of the multiset,
+just as in the |subsets| routine.
+Roughly speaking, there are |n0| elements equal to~0, |n1| elements
+equal to~1, and so on. The multiset $\{0,0,1,2,3,3\}$ would, for example,
+be represented by |(n0,n1,n2,n3,n4)=(2,1,1,2,0)|.
+
+Of course, we sometimes want to have multisets with more than five distinct
+elements; when there are $d+1$ distinct elements, the multiset should have
+$n_k$ elements equal to~$k$ and $n=n_0+n_1+\cdots+n_d$ elements in all.
+The value of $d$ can be specified by making |n0=-d| (in which case
+each multiplicity $n_k$ is taken to be~1); or by making |n0>0| and |n1=-d|
+(in which case each multiplicity $n_k$ is taken to be equal to~|n0|); or
+|n0>0|, |n1>0|, |n2=-d| (in which case the multiplicities are alternately
+$(|n0|,|n1|,|n0|,|n1|,|n0|,\ldots\,)$); or |n0>0|, |n1>0|, |n2>0|, |n3=-d|,
+(in which case the multiplicities are the first~|d+1| elements of the
+periodic sequence $(|n0|,|n1|,|n2|,|n0|,|n1|,\ldots\,)$); or all
+but |n4| are positive, while |n4=-d| (in which case the multiplicities again
+are periodic).
+
+An example like |(n0,n1,n2,n3,n4)=(1,2,3,4,-8)| is about as tricky
+as you can get. It specifies the multiset $\{0,1,1,2,2,2,3,3,3,3,4,5,5,
+6,6,6,7,7,7,7,8\}$.
+
+If any of the multiplicity parameters is negative or zero, the
+remaining multiplicities are ignored. For example, if |n2<=0|, the
+subroutine does not look at |n3| or~|n4|.
+
+You probably don't want to try |perms(n0,0,0,0,0,max_inv,directed)|
+when |n0>0|, because a multiset with |n0| identical elements has only
+one permutation.
+
+The special case when you want all $n!$ permutations of an $n$-element set
+can be obtained by calling |all_perms(n,directed)|.
+
+@(gb_basic.h@>=
+#define all_perms(n,directed) @[perms(1-n,0,0,0,0,0,directed)@]
+
+@ If |max_inv=0|, all permutations will be considered, regardless of
+the number of inversions. In that case the total number of vertices in
+the graph will be the multinomial coefficient $${n\choose
+n_0,n_1,\ldots,n_d}\,,\qquad n=n_0+n_1+\cdots+n_d.$$ The maximum
+number of inversions in general is the number of inversions of the
+lexicographically last permutation, namely ${n\choose2}-{n_0\choose2}-
+{n_1\choose2}-\cdots-{n_d\choose2}=\sum_{0\le j<k\le d}n_jn_k$.
+
+If |directed| is nonzero, the graph will contain only arcs that are directed
+from permutations to their neighbors having exactly one more inversion.
+
+@ The program for |perms| is very similar in structure to the program
+for |simplex| already considered.
+
+@<Basic subroutines@>=
+Graph *perms(n0,n1,n2,n3,n4,max_inv,directed)
+ int n0,n1,n2,n3,n4; /* composition of the multiset */
+ unsigned long max_inv; /* maximum number of inversions */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register int n; /* total number of elements in multiset */
+ @<Normalize the permutation parameters@>;
+ @<Create a graph with one vertex for each permutation@>;
+ @<Name the permutations and create the arcs or edges@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* shucks, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Normalize the permutation parameters@>=
+if (n0==0) {@+n0=1;@+n1=0;@+} /* convert the empty set into $\{0\}$ */
+else if (n0<0) {@+n1=n0;@+n0=1;@+}
+n=BUF_SIZE; /* this allows us to borrow code from |simplex|, already written */
+@<Normalize the simplex parameters@>;
+@<Determine |n| and the maximum possible number of inversions@>;
+
+@ Here we want to set |max_inv| to the maximum possible number of
+inversions, if it is zero or if it exceeds that number.
+
+@<Determine |n| and the maximum possible number of inversions@>=
+{@+register long ss; /* max inversions known to be possible */
+ for (k=0,s=ss=0;k<=d;ss+=s*nn[k],s+=nn[k],k++)
+ if (nn[k]>=BUF_SIZE) panic(bad_specs);
+ /* too many elements in the multiset */
+ if (s>=BUF_SIZE) panic(bad_specs+1); /* too many elements in the multiset */
+ n=s;
+ if (max_inv==0 || max_inv>ss) max_inv=ss;
+}
+
+@ To determine the number of vertices, we sum the first |max_inv+1|
+coefficients of a power series in which the coefficient of~$z^j$
+is the number of permutations having $j$ inversions. It is known
+[{\sl Sorting and Searching}, exercise 5.1.2--16] that this power series
+is the ``$z$-multinomial coefficient''
+$${n\choose n_0,\ldots,n_d}_z={n!_z\over n_0!_z\ldots n_d!_z}\,,
+\qquad\hbox{where}\qquad m!_z=\prod_{k=1}^m{1-z^k\over 1-z}\,.$$
+
+@<Create a graph with one vertex for each permutation@>=
+{@+long nverts; /* the number of vertices */
+ register long *coef=gb_alloc_type(max_inv+1,@[long@],working_storage);
+ if (gb_alloc_trouble) panic(no_room+1); /* can't allocate |coef| array */
+ coef[0]=1;
+ for (j=1,s=nn[0];j<=d;s+=nn[j],j++)
+ @<Multiply the power series coefficients by
+ $\prod_{1\le k\le n_j}(1-z^{s+k})/(1-z^k)$@>;
+ for (k=1,nverts=1;k<=max_inv;k++) {
+ nverts+=coef[k];
+ if (nverts>1000000000) panic(very_bad_specs); /* way too big */
+ }
+ gb_free(working_storage); /* recycle the |coef| array */
+ new_graph=gb_new_graph(nverts);
+ if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+ sprintf(new_graph->id,"perms(%d,%d,%d,%d,%d,%lu,%d)",
+ n0,n1,n2,n3,n4,max_inv,directed?1:0);
+ strcpy(new_graph->format,"VVZZZZZZZZZZZZ"); /* hash table will be used */
+}
+
+@ After multiplication by $(1-z^{k+s})/(1-z^k)$, the coefficients of the
+power series will be nonnegative, because they are the coefficients of
+a $z$-multinomial coefficient.
+
+@<Multiply the power series coefficients by
+ $\prod_{1\le k\le n_j}(1-z^{s+k})/(1-z^k)$@>=
+for (k=1;k<=nn[j];k++) {@+register int ii;
+ for (i=max_inv,ii=i-k-s;ii>=0;ii--,i--) coef[i]-=coef[ii];
+ for (i=k,ii=0;i<=max_inv;i++,ii++) {
+ coef[i]+=coef[ii];
+ if (coef[i]>1000000000) panic(very_bad_specs+1); /* way too big */
+ }
+}
+
+@ As we generate the permutations, we maintain a table $(y_1,\ldots,y_n)$,
+where $y_k$ is the number of
+inversions whose first element is the $k$th element of the multiset.
+For example, if the multiset is $\{0,0,1,2\}$ and the current permutation is
+$(2,0,1,0)$, the inversion table is $(y_1,y_2,y_3,y_4)=(0,0,1,3)$. Clearly
+$0\le y_k<k$, and $y_k\le y_{k-1}$ when the $k$th element of the multiset
+is the same as the $(k-1)$st element. These conditions are necessary
+and sufficient to define a valid inversion table. We will generate
+permutations in lexicographic order of their inversion tables.
+
+For convenience, we set up another array~|z|, which holds the
+initial inversion-free permutation.
+
+@<Name the permutations and create the arcs or edges@>=
+{@+register int *xtab,*ytab,*ztab; /* permutations and their inversions */
+ int m=0; /* current number of inversions */
+ @<Initialize |xtab|, |ytab|, and |ztab|@>;
+ v=new_graph->vertices;
+ while (1) {
+ @<Assign a symbolic name for $(x_1,\ldots,x_n)$ to vertex~|v|@>;
+ @<Create arcs or edges from previous permutations to~|v|@>;
+ v++;
+ @<Advance to the next perm; |goto last| if there are no more solutions@>;
+ }
+ last:@+if (v!=new_graph->vertices+new_graph->n)
+ panic(impossible); /* can't happen */
+ gb_free(working_storage);
+}
+
+@ @<Initialize |xtab|, |ytab|, and |ztab|@>=
+xtab=gb_alloc_type(3*n+3,@[int@],working_storage);
+if (gb_alloc_trouble) { /* can't allocate |xtab| */
+ gb_recycle(new_graph);@+panic(no_room+2);@+}
+ytab=xtab+(n+1);
+ztab=ytab+(n+1);
+for (j=0,k=1,s=nn[0];;k++) {
+ xtab[k]=ztab[k]=j; /* |ytab[k]=0| */
+ if (k==s) {
+ if (++j>d) break;
+ else s+=nn[j];
+ }
+}
+
+@ Here is the heart of the permutation logic. We find the largest~$k$
+such that $y_k$ can legitimately be increased by~1. When we encounter
+a~$k$ for which $y_k$ cannot be increased, we set $y_k=0$ and adjust
+the $x$'s accordingly. If no $y_k$ can be increased, we are done.
+
+@<Advance to the next perm...@>=
+for (k=n;k;k--) {
+ if (m<max_inv && ytab[k]<k-1)
+ if (ytab[k]<ytab[k-1] || ztab[k]>ztab[k-1]) goto move;
+ if (ytab[k]) {
+ for (j=k-ytab[k];j<k;j++) xtab[j]=xtab[j+1];
+ m-=ytab[k];
+ ytab[k]=0;
+ xtab[k]=ztab[k];
+ }
+}
+goto last;
+move: j=k-ytab[k]; /* the current location of the $k$th element, $z_k$ */
+xtab[j]=xtab[j-1];@+xtab[j-1]=ztab[k];
+ytab[k]++;@+m++;
+
+@ A permutation is encoded as a sequence of nonblank characters,
+using an abbreviated copy of the |imap| code from |gb_io| and omitting
+the characters that need to be quoted within strings. If the
+number of distinct elements in the multiset is at most~62, only digits
+and letters will appear in the vertex name.
+
+@<Private variables@>=
+static char *short_imap="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+abcdefghijklmnopqrstuvwxyz_^~&@@,;.:?!%#$+-*/|<=>()[]{}`'";
+
+@ @<Assign a symbolic name for $(x_1,\ldots,x_n)...@>=
+{@+register char *p; register int *q;
+ for (p=&buffer[n-1],q=&xtab[n];q>xtab;p--,q--) *p=short_imap[*q];
+ v->name=gb_save_string(buffer);
+ hash_in(v); /* enter |v->name| into the hash table
+ (via utility fields |u,v|) */
+}
+
+@ Since we are generating the vertices in lexicographic order of their
+inversions, it is easy to identify all adjacent vertices that
+precede the current setting of $(x_1,\ldots,x_n)$. We locate them
+via their symbolic names.
+
+@<Create arcs or edges from previous permutations to~|v|@>=
+for (j=1;j<n;j++)
+ if (xtab[j]>xtab[j+1]) {@+register Vertex *u;
+ /* previous vertex adjacent to |v| */
+ buffer[j-1]=short_imap[xtab[j+1]];@+buffer[j]=short_imap[xtab[j]];
+ u=hash_out(buffer);
+ if (u==NULL) panic(impossible+2); /* can't happen */
+ if (directed) gb_new_arc(u,v,1);
+ else gb_new_edge(u,v,1);
+ buffer[j-1]=short_imap[xtab[j]];@+buffer[j]=short_imap[xtab[j+1]];
+ }
+
+@* Partition graphs. The subroutine call
+`|parts(n,max_parts,max_size,directed)|'
+creates a graph whose vertices represent the different ways to partition
+the integer~|n| into at most |max_parts| parts, where each part is at most
+|max_size|. Two partitions are adjacent in the graph if
+one can be obtained from the other by combining two parts.
+Each arc has length~1.
+
+For example, the partitions of~5 are
+$$5,\quad 4+1,\quad 3+2,\quad 3+1+1,\quad 2+2+1,\quad 2+1+1+1,\quad 1+1+1+1+1.$$
+Here 5 is adjacent to $4+1$ and to $3+2$; $4+1$ is adjacent also to
+$3+1+1$ and to $2+2+1$; $3+2$ is adjacent also to $3+1+1$ and to $2+2+1$; etc.
+If |max_size| is 3, the partitions 5 and $4+1$ would not be included in
+the graph. If |max_parts| is 3, the partitions $2+1+1+1$ and $1+1+1+1+1$
+would not be included.
+
+If |max_parts| or |max_size| are zero, they are reset to be equal to~|n|,
+so that they make no restriction on the partitions.
+
+If |directed| is nonzero, the graph will contain only directed arcs from
+partitions to their neighbors having exactly one more part.
+
+The special case when we want to generate all $p(n)$ partitions of the
+integer~$n$ can be obtained by calling |all_parts(n,directed)|.
+
+@(gb_basic.h@>=
+#define all_parts(n,directed) @[parts(n,0,0,directed)@]
+
+@ The program for |parts| is very similar in structure to the program
+for |perms| already considered.
+
+@<Basic subroutines@>=
+Graph *parts(n,max_parts,max_size,directed)
+ unsigned n; /* the number being partitioned */
+ unsigned max_parts; /* maximum number of parts */
+ unsigned max_size; /* maximum size of each part */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ if (max_parts==0 || max_parts>n) max_parts=n;
+ if (max_size==0 || max_size>n) max_size=n;
+ if (max_parts>MAX_D) panic(bad_specs); /* too many parts allowed */
+ @<Create a graph with one vertex for each partition@>;
+ @<Name the partitions and create the arcs or edges@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault);
+ /* doggone it, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ The number of vertices is the coefficient of $z^n$
+in the $z$-binomial coefficient ${m+p\choose m}_z$, where $m=|max_parts|$
+and $p=|max_size|$. This coefficient is calculated as in the |perms| routine.
+
+@<Create a graph with one vertex for each partition@>=
+{@+long nverts; /* the number of vertices */
+ register long *coef=gb_alloc_type(n+1,@[long@],working_storage);
+ if (gb_alloc_trouble) panic(no_room+1); /* can't allocate |coef| array */
+ coef[0]=1;
+ for (k=1;k<=max_parts;k++) {
+ for (j=n,i=n-k-max_size;i>=0;i--,j--) coef[j]-=coef[i];
+ for (j=k,i=0;j<=n;i++,j++) {
+ coef[j]+=coef[i];
+ if (coef[j]>1000000000) panic(very_bad_specs); /* way too big */
+ }
+ }
+ nverts=coef[n];
+ gb_free(working_storage); /* recycle the |coef| array */
+ new_graph=gb_new_graph(nverts);
+ if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+ sprintf(new_graph->id,"parts(%u,%u,%u,%d)",
+ n,max_parts,max_size,directed?1:0);
+ strcpy(new_graph->format,"VVZZZZZZZZZZZZ"); /* hash table will be used */
+}
+
+@ As we generate the partitions, we maintain
+the numbers $\sigma_j=n-(x_1+\cdots+x_{j-1})=x_j+x_{j+1}+\cdots\,$,
+somewhat as we did in the |simplex| routine. We set $x_0=|max_size|$,
+and $y_j=|max_parts|+1-j$; then the conditions
+$$\sigma_j/y_j\le x_j\le \sigma_j,\qquad x_j\le x_{j-1}$$
+characterize the legal values of~$x_j$, given $(x_1,\ldots,x_{j-1})$.
+
+@<Name the partitions and create the arcs or edges@>=
+v=new_graph->vertices;
+xx[0]=max_size;@+sig[1]=n;
+for (k=max_parts,s=1;k>0;k--,s++) yy[k]=s;
+if (max_size*max_parts>=n) {
+ k=1;@+xx[1]=(n-1)/max_parts+1; /* $\lceil n/|max_parts|\rceil$ */
+ while (1) {
+ @<Complete the partial solution $(x_1,\ldots,x_k)$@>;
+ @<Assign the name $x_1+\cdots+x_d$ to vertex~|v|@>;
+ @<Create arcs or edges from |v| to previous partitions@>;
+ v++;
+ @<Advance to the next partial solution $(x_1,\ldots,x_k)$, where |k| is
+ as large as possible; |goto last| if there are no more solutions@>;
+ }
+}
+last:@+if (v!=new_graph->vertices+new_graph->n)
+ panic(impossible); /* can't happen */
+
+@ @<Complete the partial solution $(x_1,\ldots,x_k)$@>=
+for (s=sig[k]-xx[k],k++;s;k++) {
+ sig[k]=s;
+ xx[k]=(s-1)/yy[k]+1;
+ s-=xx[k];
+}
+d=k-1; /* the smallest part is $x_d$ */
+
+@ Here we seek the largest $k$ such that $x_k$ can be increased without
+violating the necessary and sufficient conditions stated earlier.
+
+@<Advance to the next partial solution $(x_1,\ldots,x_k)$...@>=
+if (d==1) goto last;
+for (k=d-1;;k--) {
+ if (xx[k]<sig[k] && xx[k]<xx[k-1]) break;
+ if (k==1) goto last;
+}
+xx[k]++;
+
+@ @<Assign the name $x_1+...@>=
+{@+register char *p=buffer; /* string pointer */
+ for (k=1;k<=d;k++) {
+ sprintf(p,"+%d",xx[k]);
+ while (*p) p++;
+ }
+ v->name=gb_save_string(&buffer[1]); /* omit |buffer[0]|, which is |'+'| */
+ hash_in(v); /* enter |v->name| into the hash table
+ (via utility fields |u,v|) */
+}
+
+@ Since we are generating the partitions in lexicographic order of their
+parts, it is reasonably easy to identify all adjacent vertices that
+precede the current setting of $(x_1,\ldots,x_d)$, by splitting
+$x_j$ into two parts when $x_j\ne x_{j+1}$. We locate previous partitions
+via their symbolic names.
+
+@<Create arcs or edges from |v| to previous partitions@>=
+if (d<max_parts) {
+ xx[d+1]=0;
+ for (j=1;j<=d;j++) {
+ if (xx[j]!=xx[j+1]) {@+int a,b;
+ for (b=xx[j]/2,a=xx[j]-b;b;a++,b--)
+ @<Generate a subpartition $(n_1,\ldots,n_{d+1})$ by
+ splitting $x_j$ into $a+b$, and make that subpartition
+ adjacent to~|v|@>;
+ }
+ nn[j]=xx[j];
+ }
+}
+
+@ The values of $(x_1,\ldots,x_{j-1})$ have already been copied into
+$(n_1,\ldots,n_{j-1})$. Our job is to copy the smaller parts
+$(x_{j+1},\ldots,x_d)$ while
+inserting $a$ and $b$ in their proper places, knowing that $a\ge b$.
+
+@<Generate a subpartition $(n_1,\ldots,n_{d+1})$...@>=
+{@+register Vertex *u; /* previous vertex adjacent to |v| */
+ register char *p=buffer;
+ for (k=j+1;xx[k]>a;k++) nn[k-1]=xx[k];
+ nn[k-1]=a;
+ for (;xx[k]>b;k++) nn[k]=xx[k];
+ nn[k]=b;
+ for (;k<=d;k++) nn[k+1]=xx[k];
+ for (k=1;k<=d+1;k++) {
+ sprintf(p,"+%d",nn[k]);
+ while (*p) p++;
+ }
+ u=hash_out(&buffer[1]);
+ if (u==NULL) panic(impossible+2); /* can't happen */
+ if (directed) gb_new_arc(v,u,1);
+ else gb_new_edge(v,u,1);
+}
+
+@* Binary tree graphs. The subroutine call
+`|binary(n,max_height,directed)|'
+creates a graph whose vertices represent the binary trees with $n$ internal
+nodes and with all leaves at distance at most |max_height| from the root.
+Two binary trees are adjacent in the graph if
+one can be obtained from the other by a single application of the
+associative law for binary operations, i.e., by replacing some subtree
+of the form $(\alpha\cdot\beta)\cdot\gamma$ by the subtree $\alpha\cdot
+(\beta\cdot\gamma)$. (This transformation on binary trees is often
+called a ``rotation.'') If the |directed| parameter is nonzero, the
+directed arcs go from a tree containing $(\alpha\cdot\beta)\cdot\gamma$
+to a tree containing $\alpha\cdot(\beta\cdot\gamma)$ in its place; otherwise
+the graph is undirected. Each arc has length~1.
+
+For example, the binary trees with 3 internal nodes form a circuit of
+length~5: They are
+$$\mathcode`.="2201 % \cdot
+(a.b).(c.d),\quad a.(b.(c.d)),\quad a.((b.c).d),\quad (a.(b.c)).d,\quad
+((a.b).c).d,$$
+if we use infix notation and name the leaves $(a,b,c,d)$ from left to right.
+Here each tree is related to its two neighbors by associativity, and the
+first and last trees are also related in the same way.
+
+If |max_height=0|, it is changed to |n|, which means there is no
+restriction on the height of a leaf. In this case the graph will have
+exactly ${2n+1\choose n}/ (2n+1)$ vertices; furthermore, each vertex
+will have exactly $n-1$ neighbors, because a rotation will be possible
+just above every internal node except the root. The graph in this
+graph can also be interpreted geometrically: The vertices are in one
+to one correspondence with the triangulations of a regular
+$(n+2)$-gon; two triangulations are adjacent if and only if one is obtained
+from the other by replacing the pair of adjacent triangles $ABC,DCB$
+by the pair $ADC,BDA$.
+
+@(gb_basic.h@>=
+#define all_trees(n,directed) @[binary(n,0,directed)@]
+
+
+@ The program for |binary| is very similar in structure to the program
+for |parts| already considered. But the details are more exciting.
+
+@<Basic subroutines@>=
+Graph *binary(n,max_height,directed)
+ unsigned n; /* the number of internal nodes */
+ unsigned max_height; /* maximum height of a leaf */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ if (2*n+2>BUF_SIZE) panic(bad_specs); /* |n| is too huge for us */
+ if (max_height==0 || max_height>n) max_height=n;
+ if (max_height>30) panic(very_bad_specs); /* more than a billion vertices */
+ @<Create a graph with one vertex for each binary tree@>;
+ @<Name the trees and create the arcs or edges@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* uff da, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ The number of vertices is the coefficient of $z^n$
+in the power series $G_h$, where $h=|max_height|$ and the recurrence
+$$G_0=1,\qquad G_{h+1}=1+z G_h^2$$
+defines $G_h$.
+
+The coefficients of $G_5$ are $\le55308$, but the
+coefficients of $G_6$ are much larger; they exceed one billion when
+$28\le n\le49$, and they exceed one million when $17\le n\le 56$.
+In order to avoid overflow during this calculation, we use a
+special method when $h\ge6$ and $n\ge20$: In such cases, graphs
+of reasonable size arise only if $n\ge 2^h-7$, and we look at the
+coefficient of $z^{-(2^h-1-n)}$ in $R_h=G_h/z^{2^h-1}$, which is a
+power series in $z^{-1}$ defined by the recurrence
+$$R_0=1,\qquad R_{h+1}=R_h^2+z^{1-2^{h+1}}.$$
+
+@<Create a graph with one vertex for each binary tree@>=
+{@+long nverts; /* the number of vertices */
+ if (n>=20 && max_height>=6) @<Compute |nverts| using the $R$ series@>@;
+ else {
+ nn[0]=nn[1]=1;
+ for (k=2;k<=n;k++) nn[k]=0;
+ for (j=2;j<=max_height;j++)
+ for (k=n-1;k;k--) {
+ for (s=0,i=k;i>=0;i--) s+=nn[i]*nn[k-i]; /* overflow impossible */
+ nn[k+1]=s;
+ }
+ nverts=nn[n];
+ }
+ new_graph=gb_new_graph(nverts);
+ if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+ sprintf(new_graph->id,"binary(%u,%u,%d)",
+ n,max_height,directed?1:0);
+ strcpy(new_graph->format,"VVZZZZZZZZZZZZ"); /* hash table will be used */
+}
+
+@ The smallest nontrivial graph that is unilaterally disallowed by
+this procedure on the grounds of size limitations occurs when |max_height=6|
+and |n=20|; it has 14,162,220 vertices.
+
+@<Compute |nverts| using the $R$ series@>=
+{@+register float ss;
+ d=(1<<max_height)-1-n;
+ if (d>8) panic(bad_specs+1); /* too many vertices */
+ if (d<0) nverts=0;
+ else {
+ nn[0]=nn[1]=1;
+ for (k=2;k<=d;k++) nn[k]=0;
+ for (j=2;j<=max_height;j++) {
+ for (k=d;k;k--) {
+ for (ss=0.0,i=k;i>=0;i--) ss+=((float)nn[i])*((float)nn[k-i]);
+ if (ss>MAX_NNN) panic(very_bad_specs+1); /* way too big */
+ for (s=0,i=k;i>=0;i--) s+=nn[i]*nn[k-i]; /* overflow impossible */
+ nn[k]=s;
+ }
+ i=(1<<j)-1;
+ if (i<=d) nn[i]++; /* add $z^{1-2^j}$ */
+ }
+ nverts=nn[d];
+ }
+}
+
+@ We generate the trees in lexicographic order of their Polish prefix
+notation, encoded in binary notation as $x_0x_1\ldots x_{2n}$, using `1'
+for an internal node and `0' for a leaf. For example, the five
+trees when $n=3$ are
+$$1010100,\quad 1011000,\quad 1100100,\quad 1101000,\quad 1110000,$$
+in lexicographic order. The algorithm for lexicographic generation maintains
+three auxiliary arrays $l_j$, $y_j$, and $\sigma_j$, where
+$$\sigma_j\;=\;n-j+\sum_{i=0}^{j-1}x_i\;=\;-1+\sum_{i=j}^{2n}(1-x_i)$$
+is one less than the number of 0's (leaves) in $(x_j,\ldots,x_{2n})$.
+The values of $l_j$ and $y_j$ are harder
+to describe formally; $l_j$ is $2^{h-l}$ when $h=|max_height|$ and when
+$x_j$ represents a node at level~$l$ of the tree, based on the values
+of $(x_0,\ldots,x_{j-1})$. The value of $y_j$ is a binary encoding of
+tree levels in which an internal node has not yet received a right child;
+$y_j$ is also the maximum number of future leaves that can be produced by
+previously specified internal nodes, without exceeding the maximum height.
+The number of 1-bits in $y_j$ is the minimum number of future leaves,
+based on previous specifications.
+
+Therefore if $\sigma_j>y_j$, $x_j$ is forced to be~1. If $l_j=1$,
+$x_j$ is forced to be~0. If the number of 1-bits of $y_j$ is equal
+to $\sigma_j$, $x_j$ is forced to be~0. Otherwise $x_j$ can be
+either 0 or~1, and it will be possible to complete the partial
+solution $x_0\ldots x_j$ to a full Polish prefix code $x_0\ldots x_{2n}$.
+
+For example, here are the arrays for one of the binary trees
+that is generated when $n=h=3$:
+$$\vcenter{\halign{$\hfil#$\quad=&&\quad#\cr
+j &0&1&2&3&4&5&6\cr
+l_j &8&4&2&2&1&1&4\cr
+y_j &0&4&6&4&5&4&0\cr
+\sigma_j&3&3&3&2&2&1&0\cr
+x_j &1&1&0&1&0&0&0\cr}}$$
+If $x_j=1$ and $j<2n$, we have $l_{j+1}=l_j/2$, $y_{j+1}=y_j+l_{j+1}$,
+and $\sigma_{j+1}=\sigma_j$. If $x_j=0$ and $j<2n$, we have $l_{j+1}=
+2^t$, $y_{j+1}=y_j-2^t$, and $\sigma_{j+1}=\sigma_j-1$, where $2^t$ is the
+least power of~2 in the binary representation of~$y_j$. It is not difficult to
+prove by induction that $\sigma_j<y_j+l_j$, assuming that $n<2^h$.
+
+@<Name the trees and create the arcs or edges@>=
+{@+register long *xtab,*ytab,*ltab,*stab;
+ @<Initialize |xtab|, |ytab|, |ltab|, and |stab|; also set |d=2n|@>;
+ v=new_graph->vertices;
+ if (ltab[0]>n) {
+ k=0;@+xtab[0]=n?1:0;
+ while (1) {
+ @<Complete the partial tree $x_0\ldots x_k$@>;
+ @<Assign a Polish prefix code name to vertex~|v|@>;
+ @<Create arcs or edges from |v| to previous trees@>;
+ v++;
+ @<Advance to the next partial tree $x_0\ldots x_k$, where |k| is
+ as large as possible; |goto last| if there are no more solutions@>;
+ }
+ }
+}
+last:@+if (v!=new_graph->vertices+new_graph->n)
+ panic(impossible); /* can't happen */
+gb_free(working_storage);
+
+@ @<Initialize |xtab|, |ytab|, |ltab|, and |stab|...@>=
+xtab=gb_alloc_type(8*n+4,@[int@],working_storage);
+if (gb_alloc_trouble) { /* no room for |xtab| */
+ gb_recycle(new_graph);@+panic(no_room+2);@+}
+d=n+n;
+ytab=xtab+(d+1);
+ltab=ytab+(d+1);
+stab=ltab+(d+1);
+ltab[0]=1<<max_height;
+stab[0]=n; /* |ytab[0]=0| */
+
+@ @<Complete the partial tree...@>=
+for (j=k+1;j<=d;j++) {
+ if (xtab[j-1]) {
+ ltab[j]=ltab[j-1]>>1;
+ ytab[j]=ytab[j-1]+ltab[j];
+ stab[j]=stab[j-1];
+ } else {
+ ytab[j]=ytab[j-1]&(ytab[j-1]-1); /* remove least significant 1-bit */
+ ltab[j]=ytab[j-1]-ytab[j];
+ stab[j]=stab[j-1]-1;
+ }
+ if (stab[j]<=ytab[j]) xtab[j]=0;
+ else xtab[j]=1; /* this is the lexicographically smallest completion */
+}
+
+@ As in previous routines, we seek the largest $k$ such that $x_k$ can
+be increased without violating the necessary and sufficient conditions
+stated earlier.
+
+@<Advance to the next partial tree...@>=
+for (k=d-1;;k--) {
+ if (k<=0) goto last; /* this happens only when |n<=1| */
+ if (xtab[k]) break; /* find rightmost 1 */
+}
+for (k--;;k--) {
+ if (xtab[k]==0 && ltab[k]>1) break;
+ if (k==0) goto last;
+}
+xtab[k]++;
+
+@ In the |name| field, we encode internal nodes of the binary tree by
+`\..' and leaves by `\.x'. Thus the five trees shown above in binary
+code will be named
+$$\.{.x.x.xx},\quad \.{.x..xxx},\quad \.{..xx.xx},\quad \.{..x.xxx},\quad
+\.{...xxxx},$$
+respectively.
+
+@<Assign a Polish prefix...@>=
+{@+register char *p=buffer; /* string pointer */
+ for (k=0;k<=d;k++,p++) *p=(xtab[k]? '.': 'x');
+ v->name=gb_save_string(buffer);
+ hash_in(v); /* enter |v->name| into the hash table
+ (via utility fields |u,v|) */
+}
+
+@ Since we are generating the trees in lexicographic order of their
+Polish prefix notation, it is relatively easy to find all pairs of trees that
+are adjacent via one application of the associative law: We simply
+replace a substring of the form $\..\..\alpha\beta$ by
+$\..\alpha\..\beta$, when $\alpha$ and $\beta$ are Polish prefix
+strings. The result comes earlier in lexicographic order, so it will
+be an existing vertex unless it violates the |max_height| restriction.
+
+@<Create arcs or edges from |v| to previous trees@>=
+for (j=0;j<d;j++)
+ if (xtab[j]==1 && xtab[j+1]==1) {
+ for (i=j+1,s=0;s>=0;s+=(xtab[i+1]<<1)-1,i++) xtab[i]=xtab[i+1];
+ xtab[i]=1;
+ {@+register char *p=buffer; /* string pointer */
+ register Vertex *u;
+ for (k=0;k<=d;k++,p++) *p=(xtab[k]? '.': 'x');
+ u=hash_out(buffer);
+ if (u) {
+ if (directed) gb_new_arc(v,u,1);
+ else gb_new_edge(v,u,1);
+ }
+ }
+ for (i--;i>j;i--) xtab[i+1]=xtab[i]; /* restore |xtab| */
+ xtab[i+1]=1;
+ }
+
+@* Complementing and copying. We have seen how to create a wide
+variety of basic graphs with the |board|, |simplex|, |subsets|,
+|perms|, |parts|, and |binary| procedures. The remaining routines
+of |gb_basic| are somewhat different. They transform existing
+graphs into new ones, thereby presenting us with an almost
+mind-boggling array of further possibilities.
+
+The first of these transformations is perhaps the simplest: It
+complements a given graph, i.e., makes vertices adjacent if and only if
+they were previously non-adjacent. More precisely, the subroutine call
+`|complement(g,copy,self,directed)|' returns a graph with the
+same vertices as |g|, but with complemented arcs.
+If |self!=0|, the new graph will have a self-loop from a vertex |v| to itself
+when the original graph did not; if |self=0|, the new graph will
+have no self-loops. If |directed!=0|, the new graph will have
+an arc from |u| to |v| when the original graph did not; if |directed=0|,
+the new graph will be undirected, and it will have an edge between |u|
+and~|v| when the original graph did not. In the latter case, the original
+graph should also be undirected (i.e., its arcs should come in pairs,
+as described in the |gb_new_edge| routine of |gb_graph|).
+
+If |copy!=0|, a double complement will actually be done. This means that
+the new graph will essentially be a copy of the old, except that
+duplicate arcs (and possibly self-loops) will be removed. Information
+that may have been in the utility fields is not copied, and arc lengths
+are all set to~1.
+
+One possibly useful feature of the graphs returned by |complement| is
+worth noting: The vertices adjacent to~|v|, namely the list
+$$\hbox{|v->arcs->tip|,\quad |v->arcs->next->tip|,\quad
+ |v->arcs->next->next->tip|,\quad \dots\thinspace,}$$
+will be in strictly decreasing order (except in the case of an
+undirected self-loop, when |v| itself will appear twice in succession).
+
+@ @<Basic subroutines@>=
+Graph *complement(g,copy,self,directed)
+ Graph *g; /* graph to be complemented */
+ int copy; /* should we double-complement? */
+ int self; /* should we produce self-loops? */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register int n;
+ register Vertex *u;
+ register unsigned long delta; /* difference in memory addresses */
+ if (g==NULL) panic(missing_operand); /* where's |g|? */
+ @<Set up a graph with the vertices of |g|@>;
+ sprintf(buffer,",%d,%d,%d)",copy?1:0,self?1:0,directed?1:0);
+ make_compound_id(new_graph,"complement(",g,buffer);
+ @<Insert complementary arcs or edges@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault);
+ /* worse luck, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ In several of the following routines it is efficient to circumvent
+\Cee's normal rules for pointer arithmetic, and to use the
+fact that the vertices of a graph being copied are a constant distance away
+in memory from the vertices of its clone.
+
+@d vert_offset(v,delta) ((Vertex*)(((unsigned long)v)+delta))
+@^pointer hacks@>
+
+@<Set up a graph with the vertices of |g|@>=
+n=g->n;
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+delta=((unsigned long)(new_graph->vertices))-((unsigned long)(g->vertices));
+for (u=new_graph->vertices,v=g->vertices;v<g->vertices+n;u++,v++)
+ u->name=gb_save_string(v->name);
+
+@ A temporary utility field in the new graph is used to remember which
+vertices are adjacent to a given vertex in the old one. We stamp the |tmp|
+field of~|v| with a pointer to~|u| when there's an arc from |u| to~|v|.
+
+@d tmp u.v /* utility field |u| for temporary use as a vertex pointer */
+
+@<Insert comp...@>=
+for (v=g->vertices;v<g->vertices+n;v++) {@+register Vertex *vv;
+ u=vert_offset(v,delta);
+ /* vertex in |new_graph| corresponding to |v| in |g| */
+ {@+register Arc *a;
+ for (a=v->arcs;a;a=a->next) vert_offset(a->tip,delta)->tmp=u;
+ }
+ if (directed) {
+ for (vv=new_graph->vertices;vv<new_graph->vertices+n;vv++)
+ if ((vv->tmp==u && copy) || (vv->tmp!=u && !copy))
+ if (vv!=u || self) gb_new_arc(u,vv,1);
+ } else {
+ for (vv=(self?u:u+1);vv<new_graph->vertices+n;vv++)
+ if ((vv->tmp==u && copy) || (vv->tmp!=u && !copy))
+ gb_new_edge(u,vv,1);
+ }
+}
+for (v=new_graph->vertices;v<new_graph->vertices+n;v++) v->tmp=NULL;
+
+@* Graph union and intersection. Another simple way to get new graphs
+from old ones is to take the union or intersection of their sets of arcs. The
+subroutine call `|gunion(g,gg,multi,directed)|' produces a graph
+with the vertices and arcs of |g| together with the
+arcs of another graph~|gg|. The subroutine call `|intersection(g,gg,multi,
+directed)|' produces a graph with the vertices of |g| but with only the
+arcs that appear in both |g| and |gg|. In both cases we assume
+that |gg| has the same vertices as |g|, in the sense that vertices
+in the same relative position from the beginning of the vertex array
+are considered identical. If the actual number of vertices in |gg| exceeds
+the number in |g|, the extra vertices and all arcs touching them in~|gg| are
+suppressed.
+
+The input graphs are assumed to be undirected, unless the |directed|
+parameter is nonzero. Peculiar results may occur if you mix directed
+and undirected graphs, but the subroutines will not ``crash''
+when they are asked to produce undirected output from directed input.
+
+If |multi| is nonzero, the new graph may have multiple edges: Suppose
+there are $k_1$ arcs from $u$ to $v$ in |g|, and $k_2$ in |gg|. Then
+there will be $k_1+k_2$ in the union and $\min(k_1,k_2)$ in the
+intersection when |multi!=0|, but at most
+one in the union or intersection when |multi=0|.
+
+The lengths of arcs are copied to the union graph when |multi!=0|;
+the minimum length of multiple arcs is retained in the union when |multi=0|.
+
+The lengths of arcs in the intersection graph are a bit trickier.
+If multiple arcs occur in |g|, their minimum length, |l|, is computed. Then
+we compute the maximum of |l| and the lengths of corresponding arcs
+in |gg|. If |multi=0|, only the minimum of those maxima will survive.
+
+@ @<Basic subroutines@>=
+Graph *gunion(g,gg,multi,directed)
+ Graph *g,*gg; /* graphs to be united */
+ int multi; /* should we reproduce multiple arcs? */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register int n;
+ register Vertex *u;
+ register unsigned long delta,ddelta; /* differences in memory addresses */
+ if (g==NULL || gg==NULL) panic(missing_operand);
+ /* where are |g| and |gg|? */
+ @<Set up a graph with the vertices of |g|@>;
+ sprintf(buffer,",%d,%d)",multi?1:0,directed?1:0);
+ make_double_compound_id(new_graph,"gunion(",g,",",gg,buffer);
+ ddelta=((unsigned long)(new_graph->vertices))-((unsigned long)(gg->vertices));
+ @<Insert arcs or edges present in either |g| or |gg|@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* uh oh, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Insert arcs or edges present in either |g| or |gg|@>=
+for (v=g->vertices;v<g->vertices+n;v++) {@+register Arc *a;
+ register Vertex *vv=vert_offset(v,delta);
+ /* vertex in |new_graph| corresponding to |v| in |g| */
+ register Vertex *vvv=vert_offset(vv,-ddelta);
+ /* vertex in |gg| corresponding to |v| in |g| */
+ for (a=v->arcs;a;a=a->next) {
+ u=vert_offset(a->tip,delta);
+ @<Insert a union arc or edge from |vv| to |u|, if appropriate@>;
+ }
+ if (vvv<gg->vertices+gg->n) for (a=vvv->arcs;a;a=a->next) {
+ u=vert_offset(a->tip,ddelta);
+ if (u<new_graph->vertices+n)
+ @<Insert a union arc or edge from |vv| to |u|, if appropriate@>;
+ }
+}
+for (v=new_graph->vertices;v<new_graph->vertices+n;v++)
+ v->tmp=NULL,v->tlen=NULL;
+
+@ We use the |tmp| trick of |complement| to remember which arcs have
+already been recorded from |u|, and we extend it so that we can maintain
+minimum lengths. Namely, |uu->tmp| will equal |u| if and only
+if we have already seen an arc from |u| to |uu|; and if so, |uu->tlen|
+will be one such arc. In the undirected case, |uu->tlen| will point to the
+first arc of an edge pair that touches~|u|.
+
+The only thing slightly nontrivial here is the way we keep undirected
+edges grouped in pairs. We generate a new edge from |vv| to |u| only
+if |vv<=u|, and if equality holds we advance~|a| so that we don't
+see the self-loop in both directions. Similar logic will be repeated
+in many of the programs below.
+
+@d tlen z.a /* utility field |z| regarded as a pointer to an arc */
+
+@<Insert a union arc or edge from |vv| to |u|, if appropriate@>=
+{@+register Arc *b;
+ if (directed) {
+ if (multi || u->tmp!=vv) gb_new_arc(vv,u,a->len);
+ else {
+ b=u->tlen;
+ if (a->len<b->len) b->len=a->len;
+ }
+ u->tmp=vv; /* remember that we've seen this */
+ u->tlen=vv->arcs;
+ } else if (u>=vv) {
+ if (multi || u->tmp!=vv) gb_new_edge(vv,u,a->len);
+ else {
+ b=u->tlen;
+ if (a->len<b->len) b->len=(b+1)->len=a->len;
+ }
+ u->tmp=vv;
+ u->tlen=vv->arcs;
+ if (u==vv && a->next==a+1) a++; /* bypass second half of self-loop */
+ }
+}
+
+@ @<Basic subroutines@>=
+Graph *intersection(g,gg,multi,directed)
+ Graph *g,*gg; /* graphs to be intersected */
+ int multi; /* should we reproduce multiple arcs? */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register int n;
+ register Vertex *u;
+ register unsigned long delta,ddelta; /* differences in memory addresses */
+ if (g==NULL || gg==NULL) panic(no_room+1); /* where are |g| and |gg|? */
+ @<Set up a graph with the vertices of |g|@>;
+ sprintf(buffer,",%d,%d)",multi?1:0,directed?1:0);
+ make_double_compound_id(new_graph,"intersection(",g,",",gg,buffer);
+ ddelta=((unsigned long)(new_graph->vertices))-((unsigned long)(gg->vertices));
+ @<Insert arcs or edges present in both |g| and |gg|@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* whoops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ Two more temporary utility fields are needed here.
+
+@d mult v.i /* utility field |v|, counts multiplicity of arcs */
+@d minlen w.i /* utility field |w|, records the smallest length */
+
+@<Insert arcs or edges present in both |g| and |gg|@>=
+for (v=g->vertices;v<g->vertices+n;v++) {@+register Arc *a;
+ register Vertex *vv=vert_offset(v,delta);
+ /* vertex in |new_graph| corresponding to |v| in |g| */
+ register Vertex *vvv=vert_offset(vv,-ddelta);
+ /* vertex in |gg| corresponding to |v| in |g| */
+ if (vvv>=gg->vertices+gg->n) continue;
+ @<Take note of all arcs from |v|@>;
+ for (a=vvv->arcs;a;a=a->next) {
+ u=vert_offset(a->tip,ddelta);
+ if (u>=new_graph->vertices+n) continue;
+ if (u->tmp==vv) {@+int l=u->minlen;
+ if (a->len>l) l=a->len; /* maximum */
+ if (u->mult<0) @<Update minimum of multiple maxima@>@;
+ else @<Generate a new arc or edge for the intersection,
+ and reduce the multiplicity@>;
+ }
+ }
+}
+@<Clear out the temporary utility fields@>;
+
+@ @<Generate a new arc or edge for the intersection...@>=
+{
+ if (directed) gb_new_arc(vv,u,l);
+ else {
+ if (vv<=u) gb_new_edge(vv,u,l);
+ if (vv==u && a->next==a+1) a++; /* skip second half of self-loop */
+ }
+ if (!multi) {
+ u->tlen=vv->arcs;
+ u->mult=-1;
+ } else if (u->mult==0) u->tmp=NULL;
+ else u->mult--;
+}
+
+@ We get here if and only |multi=0| and |gg|~has more than one arc from |vv|
+to~|u| and |g|~has at least one arc from |vv| to~|u|.
+
+@<Update minimum of multiple maxima@>=
+{@+register Arc *b=u->tlen; /* previous arc or edge from |vv| to |u| */
+ if (l<b->len) {
+ b->len=l;
+ if (!directed) (b+1)->len=l;
+ }
+}
+
+@ @<Take note of all arcs from |v|@>=
+for (a=v->arcs;a;a=a->next) {
+ u=vert_offset(a->tip,delta);
+ if (u->tmp==vv) {
+ u->mult++;
+ if (a->len<u->minlen) u->minlen=a->len;
+ } else u->tmp=vv, u->mult=0, u->minlen=a->len;
+ if (u==vv && !directed && a->next==a+1) a++;
+ /* skip second half of self-loop */
+}
+
+@ @<Clear out the temporary utility fields@>=
+for (v=new_graph->vertices;v<new_graph->vertices+n;v++) {
+ v->tmp=NULL;
+ v->tlen=NULL;
+ v->mult=0;
+ v->minlen=0;
+}
+
+@* Line graphs. The next operation in |gb_basic|'s repertoire constructs
+the so-called line graph of a given graph~$g$. The subroutine that does
+this is invoked by calling `|lines(g,directed)|'.
+
+If |directed=0|, the line graph has one vertex for each edge of~|g|;
+two vertices are adjacent if and only if the corresponding edges
+have a common vertex.
+
+If |directed!=0|, the line graph has one vertex for each arc of~|g|;
+there is an arc from vertex |u| to vertex |v| if and only if the
+arc corresponding to~|u| ends at the vertex that begins the arc
+corresponding to~|v|.
+
+All arcs of the line graph will have length~1.
+
+Utility fields |u.v| and |v.v| of each vertex in the line graph will point to
+the vertices of |g| that define the corresponding arc or edge, and |w.a| will
+point to the arc from |u.v| to |v.v| in~|g|. In the undirected case we will
+have |u.v<=v.v|.
+
+@<Basic subroutines@>=
+Graph *lines(g,directed)
+ Graph *g; /* graph whose lines will become vertices */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register int m; /* the number of lines */
+ register Vertex *u;
+ if (g==NULL) panic(no_room+1); /* where is |g|? */
+ @<Set up a graph whose vertices are the lines of |g|@>;
+ if (directed) @<Insert arcs of a directed line graph@>@;
+ else @<Insert edges of an undirected line graph@>;
+ @<Restore |g| to its pristine original condition@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* (sigh) we ran out of memory somewhere back there */
+ }
+ return new_graph;
+near_panic:@<Recover from potential disaster due to bad data@>;
+}
+
+@ We want to add a data structure to |g| so that the line graph can be
+built efficiently. But we also want to preserve |g| so that it
+exhibits no traces of occupation when |lines| has finished its
+work. To do this, we will move utility field~|v->z| temporarily into
+a utility field~|u->z| of the line graph, where |u| is the first
+vertex having |u->u.v==v|, whenever such a |u| exists. Then we'll
+set |v->map=u|. We will then be able to find |u| when |v|
+is given, and we'll be able to cover our tracks later.
+
+In the undirected case further structure is needed. We will temporarily
+change the |tip| field in the second arc of each edge pair so that
+it points to the line-graph vertex that points to the first arc of the pair.
+
+The |format| field of the graph does not indicate the fact that utility
+fields |u.v|, |v.v|, and |w.a| of each vertex will be set, because those
+utility fields are pointers from the new graph to the original graph.
+The |save_graph| procedure does not deal with pointers between graphs.
+
+@d map z.v /* the |z| field treated as a vertex pointer */
+
+@<Restore |g| to its pristine original condition@>=
+for (u=new_graph->vertices,v=NULL;u<new_graph->vertices+m;u++) {
+ if (u->u.v!=v) {
+ v=u->u.v; /* original vertex of |g| */
+ v->map=u->map; /* restore original value of |v->z| */
+ u->map=NULL;
+ }
+ if (!directed) ((u->w.a)+1)->tip=v;
+}
+
+@ Special care must be taken to avoid chaos when the user is trying to
+construct the undirected line graph of a directed graph. Otherwise we
+might trash the memory, or leave the original graph in a garbled state
+with pointers leading into supposedly free space.
+
+@<Set up a graph whose vertices are the lines of |g|@>=
+m=(directed? g->m: (g->m)/2);
+new_graph=gb_new_graph(m);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+make_compound_id(new_graph,"lines(",g,directed? ",1)": ",0)");
+u=new_graph->vertices;
+for (v=g->vertices+g->n-1;v>=g->vertices;v--) {@+register Arc *a;
+ register int mapped=0; /* has |v->map| been set? */
+ for (a=v->arcs;a;a=a->next) {@+register Vertex *vv=a->tip;
+ if (!directed) {
+ if (vv<v) continue;
+ if (vv>=g->vertices+g->n) goto near_panic;
+ /* original graph not undirected */
+ }
+ @<Make |u| a vertex representing the arc |a| from |v| to |vv|@>;
+ if (!mapped) {
+ u->map=v->map; /* |z.v=map| incorporates all bits of utility field |z|,
+ whatever its type */
+ v->map=u;
+ mapped=1;
+ }
+ u++;
+ }
+}
+if (u!=new_graph->vertices+m) goto near_panic;
+
+@ @<Recover...@>=
+m=u-new_graph->vertices;
+@<Restore |g| to its pristine...@>;
+gb_recycle(new_graph);
+panic(invalid_operand);
+ /* |g| did not obey the conventions for an undirected graph */
+
+@ The vertex names in the line graph are pairs of original vertex names,
+separated by `\.{--}' when undirected, `\.{->}' when directed. If either
+of the original names is horrendously long, the villainous Procrustes
+chops it off arbitrarily so that it fills at most half of the name buffer.
+
+@<Make |u| a vertex representing the arc |a| from |v| to |vv|@>=
+u->u.v=v;
+u->v.v=vv;
+u->w.a=a;
+if (!directed) {
+ if (u>=new_graph->vertices+m || (a+1)->tip!=v) goto near_panic;
+ if (v==vv && a->next==a+1) a++; /* skip second half of self-loop */
+ else (a+1)->tip=u;
+}
+sprintf(buffer,"%.*s-%c%.*s",(BUF_SIZE-3)/2,v->name,@|
+ directed? '>': '-',BUF_SIZE/2-1,vv->name);
+u->name=gb_save_string(buffer);
+
+@ @<Insert arcs of a directed line graph@>=
+for (u=new_graph->vertices;u<new_graph->vertices+m;u++) {
+ v=u->v.v;
+ if (v->arcs) { /* |v->map| has been set up */
+ v=v->map;
+ do@+{gb_new_arc(u,v,1);
+ v++;
+ }@+while (v->u.v==u->v.v);
+ }
+}
+
+@ An undirected line graph will contain no self-loops. It contains
+multiple edges only if the original graph did; in that case, there
+are two edges joining a line to each of its parallel mates, because
+each mate hits both of its endpoints.
+
+The details of this section are worthy of careful study. We use the
+fact that the first vertices of the lines occur in nonincreasing order.
+
+@<Insert edges of an undirected line graph@>=
+for (u=new_graph->vertices;u<new_graph->vertices+m;u++) {@+register Vertex *vv;
+ register Arc *a;@+register int mapped=0;
+ v=u->u.v; /* we look first for prior lines that touch the first vertex */
+ for (vv=v->map;vv<u;vv++) gb_new_edge(u,vv,1);
+ v=u->v.v; /* then we look for prior lines that touch the other one */
+ for (a=v->arcs;a;a=a->next) {
+ vv=a->tip;
+ if (vv<u && vv>=new_graph->vertices) gb_new_edge(u,vv,1);
+ else if (vv>=v && vv<g->vertices+g->n) mapped=1;
+ }
+ if (mapped && v>u->u.v)
+ for (vv=v->map;vv->u.v==v;vv++) gb_new_edge(u,vv,1);
+}
+
+@* Graph products. Three ways have traditionally been used to define the
+product of two graphs. In all three cases the vertices of the product graph
+are ordered pairs $(v,v')$, where $v$ and $v'$ are vertices of the original
+graphs; the difference occurs in the definition of arcs. Suppose $g$ has
+$m$ arcs and $n$ vertices, while $g'$ has $m'$ arcs and $n'$ vertices. The
+{\it cartesian product\/} of $g$ and~$g'$ has $mn'+m'n$ arcs, namely from
+$(u,u')$ to $(v,u')$ whenever there's an arc from $u$ to $v$ in~$g$, and from
+$(u,u')$ to $(u,v')$ whenever there's an arc from $u'$ to $v'$ in~$g'$.
+The {\it direct product\/} has $mm'$ arcs, namely from $(u,u')$ to
+$(v,v')$ in the same circumstances. The {\it strong product\/}
+has both the arcs of the cartesian product and the direct product.
+
+Notice that an undirected graph with $m$ edges has $2m$ arcs. Thus the
+number of edges in the direct product of two undirected graphs is
+twice the product of the number of edges in the individual graphs.
+A self-loop in~$g$ will combine with an edge in~$g'$ to make
+two parallel edges in the direct product.
+
+The subroutine call `|product(g,gg,type,directed)|' produces the product
+graph of one of these three types, where |type=0| for cartesian product,
+|type=1| for direct product, and |type=2| for strong product.
+The length of an arc in the cartesian product is copied from the length
+of the original arc that it replicates; the length of an arc in the direct
+product is the minimum of the two arc lengths that induce it. If |directed=0|,
+the product graph will be an undirected graph, with its edges consisting
+of consecutive arc pairs according to the standard GraphBase conventions,
+and the input graphs should adhere to the same conventions.
+
+@(gb_basic.h@>=
+#define cartesian 0
+#define direct 1
+#define strong 2
+
+@ @<Basic subroutines@>=
+Graph *product(g,gg,type,directed)
+ Graph *g,*gg; /* graphs to be multiplied */
+ int type; /* |cartesian|, |direct|, or |strong| */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register Vertex *u,*vv;
+ register long n; /* the number of vertices in the product graph */
+ if (g==NULL || gg==NULL) panic(no_room+1); /* where are |g| and |gg|? */
+ @<Set up a graph with ordered pairs of vertices@>;
+ if ((type&1)==0) @<Insert arcs or edges for cartesian product@>;
+ if (type) @<Insert arcs or edges for direct product@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault);
+ /* @@?`$*$\#!\&, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ We must be constantly on guard against running out of memory, especially
+when multiplying information.
+
+The vertex names in the product are pairs of original vertex names, separated
+by a comma.
+
+@<Set up a graph with ordered pairs of vertices@>=
+{@+float test_product=((float)(g->n))*((float)(gg->n));
+ if (test_product>MAX_NNN) panic(very_bad_specs); /* way too many vertices */
+}
+n=(g->n)*(gg->n);
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+for (u=new_graph->vertices,v=g->vertices,vv=gg->vertices;@|
+ u<new_graph->vertices+n;u++) {
+ sprintf(buffer,"%.*s,%.*s",BUF_SIZE/2-1,v->name,(BUF_SIZE-1)/2,vv->name);
+ u->name=gb_save_string(buffer);
+ if (++vv==gg->vertices+gg->n) vv=gg->vertices,v++; /* ``carry'' */
+}
+sprintf(buffer,",%d,%d)",(type?2:0)-(type&1),directed?1:0);
+make_double_compound_id(new_graph,"product(",g,",",gg,buffer);
+
+@ @<Insert arcs or edges for cartesian product@>=
+{@+register Vertex *uu,*uuu;
+ register Arc *a;
+ register unsigned long delta; /* difference in memory addresses */
+ delta=((unsigned long)(new_graph->vertices))-((unsigned long)(gg->vertices));
+ for (u=gg->vertices;u<gg->vertices+gg->n;u++)
+ for (a=u->arcs;a;a=a->next) {
+ v=a->tip;
+ if (!directed) {
+ if (u>v) continue;
+ if (u==v && a->next==a+1) a++; /* skip second half of self-loop */
+ }
+ for (uu=vert_offset(u,delta),vv=vert_offset(v,delta);@|
+ uu<new_graph->vertices+n;uu+=gg->n,vv+=gg->n)
+ if (directed) gb_new_arc(uu,vv,a->len);
+ else gb_new_edge(uu,vv,a->len);
+ }
+ @<Insert arcs or edges for first component of cartesian product@>;
+}
+
+@ @<Insert arcs or edges for first component...@>=
+for (u=g->vertices,uu=new_graph->vertices;uu<new_graph->vertices+n;
+ u++,uu+=gg->n)
+ for (a=u->arcs;a;a=a->next) {
+ v=a->tip;
+ if (!directed) {
+ if (u>v) continue;
+ if (u==v && a->next==a+1) a++; /* skip second half of self-loop */
+ }
+ vv=new_graph->vertices+((gg->n)*(v-g->vertices));
+ for (uuu=uu;uuu<uu+gg->n;uuu++,vv++)
+ if (directed) gb_new_arc(uuu,vv,a->len);
+ else gb_new_edge(uuu,vv,a->len);
+ }
+
+@ @<Insert arcs or edges for direct product@>=
+{@+Vertex *uu;@+Arc *a;
+ unsigned long delta0=
+ ((unsigned long)(new_graph->vertices))-((unsigned long)(gg->vertices));
+ unsigned long del=(gg->n)*sizeof(Vertex);
+ register unsigned long delta,ddelta;
+ for (uu=g->vertices,delta=delta0;uu<g->vertices+g->n;uu++,delta+=del)
+ for (a=uu->arcs;a;a=a->next) {
+ vv=a->tip;
+ if (!directed) {
+ if (uu>vv) continue;
+ if (uu==vv && a->next==a+1) a++; /* skip second half of self-loop */
+ ddelta=delta0+del*(vv-g->vertices);
+ for (u=gg->vertices;u<gg->vertices+gg->n;u++) {@+register Arc *aa;
+ for (aa=u->arcs;aa;aa=aa->next) {@+long length=a->len;
+ if (length>aa->len) length=aa->len;
+ v=aa->tip;
+ if (directed)
+ gb_new_arc(vert_offset(u,delta),vert_offset(v,ddelta),length);
+ else gb_new_edge(vert_offset(u,delta),vert_offset(v,ddelta),length);
+ }
+ }
+ }
+ }
+}
+
+@* Induced graphs. Another important way to transform a graph is to
+remove, identify, or split some of its vertices. All of these
+operations are performed by the |induced| routine, which users can
+invoke by calling `|induced(g,description,self,multi,directed)|'.
+
+Each vertex |v| of |g| should first be assigned an ``induction code'' in
+its field |v->ind|, which is actually utility field~|z|. The
+induction code is 0~if |v| is to be eliminated; it is 1~if |v| is to be
+retained; it is |k>1| if |v| is to be split into $k$ nonadjacent vertices
+having the same neighbors as~|v| did; and it is |k<0| if |v| is to be
+identified with all other vertices having the same value of~|k|.
+
+For example, suppose |g| is a circuit with vertices $\{0,1,\ldots,9\}$,
+where |j| is adjacent to~|k| if and only if $k=(j\pm1)\bmod10$.
+If we set
+$$\vcenter{\halign{\hbox{\hfil#\hfil}\cr
+|0->ind=0|,\quad |1->ind=5->ind=9->ind=-1|,\quad |2->ind=3->ind=-2|,\cr
+|4->ind=6->ind=8->ind=1|,\quad and |7->ind=3|,\cr}}$$
+the induced graph will have vertices $\{-1,-2,4,6,7,7',7'',8\}$.
+The vertices adjacent to 6, say, will be $-1$ (formerly~5), 7, $7'$,
+and~$7''$. The vertices adjacent to $-1$ will be those formerly
+adjacent to 1, 5, or~9, namely $-2$ (formerly~2), 4, 6, and~8. The
+vertices adjacent to $-2$ will be those formerly adjacent to 2 or~3,
+namely $-1$ (formerly~1), $-2$ (formerly~3), $-2$ (formerly~2), and~4.
+Duplicate edges will be discarded if |multi==0|, and self-loops will
+be discarded if |self==0|.
+
+The total number of vertices in the induced graph will be the sum
+of the positive |ind| fields plus the absolute value of the most
+negative |ind| field. This rule implies, for example, that if at least
+one vertex has |ind=-5|, the induced graph will always have a vertex $-4$,
+even though no |ind| field has been set to~$-4$.
+
+The |description| parameter is a string that will appear as part of
+the name of the induced graph; if |description=0|, this string will
+be empty. In the latter case, users are encouraged to assign a suitable
+name to the |id| field of the induced graph, characterizing the method
+by which the |ind| codes were set.
+
+If the |directed| parameter is zero, the input graph will be assumed to
+be undirected, and the output graph will be undirected.
+
+When |multi=0|, the length of an arc that represents multiple arcs
+will be the minimum of the multiple arc lengths.
+
+@d ind z.i
+
+@(gb_basic.h@>=
+#define ind @[z.i /* utility field |z| when used to induce a graph */@]
+
+@ Here's a simple example: To get a complete bipartite graph with
+parts of sizes |n1| and |n2|, we can start with a trivial two-point
+graph and split its vertices into |n1| and |n2| parts.
+
+@<Applications...@>=
+Graph *complete_bipartite(n1,n2,directed)
+ unsigned n1; /* size of first part */
+ unsigned n2; /* size of second part */
+ int directed; /* should all arcs go from first part to second? */
+{@+Graph *new_graph=board(2,0,0,0,1,0,directed);
+ if (new_graph) {
+ new_graph->vertices->ind=n1;
+ (new_graph->vertices+1)->ind=n2;
+ new_graph=induced(new_graph,0,0,0,directed);
+ if (new_graph) {
+ sprintf(new_graph->id,"complete_bipartite(%u,%u,%d)",@|
+ n1,n2,directed?1:0);
+ mark_bipartite(new_graph,n1);
+ }
+ }
+ return new_graph;
+}
+
+@ The |induced| routine also provides a special feature not mentioned
+above: If the |ind| field of any vertex |v| is |IND_GRAPH| or greater
+(where |IND_GRAPH| is a large constant, much larger than the number
+of vertices that would fit in computer memory), then utility field |v->subst|
+should point to a graph. A copy of the vertices of
+that graph will then be substituted for |v| in the induced graph.
+
+This feature extends the ordinary case when |v->ind>0|, which essentially
+substitutes an empty graph for~|v|.
+
+If substitution is being used to replace all of $g$'s vertices
+by disjoint copies of some other graph~$g'$,
+the induced graph will be somewhat similar to
+a product graph. But it will not be the same as any of the three
+types of output produced by |product|, because the relation between
+$g$ and $g'$ is not symmetrical. Assuming that no self-loops are
+present, and that graphs $(g,g')$ have respectively $(m,m')$ arcs and
+$(n,n')$ vertices, the resulting of substituting $g'$ for all
+vertices of~$g$ has $m'n+mn'^2$ arcs.
+
+
+@d IND_GRAPH 1000000000 /* when |ind| is a billion or more, */
+@d subst y.g /* we'll look at the |subst| field */
+
+@(gb_basic.h@>=
+#define IND_GRAPH 1000000000
+#define subst @[y.g@]
+
+@ For example, we can use the |IND_GRAPH| feature to create a
+``wheel'' of $n$ vertices arranged cyclically, all connected to one or
+more center points. In the directed case, the arcs will run from the
+center(s) to a cycle; in the undirected case, the edges will join the
+center(s) to a circuit.
+
+@<Applications...@>=
+Graph *wheel(n,n1,directed)
+ unsigned n; /* size of the rim */
+ unsigned n1; /* number of center points */
+ int directed; /* should all arcs go from center to rim and around? */
+{@+Graph *new_graph=board(2,0,0,0,1,0,directed); /* trivial 2-vertex graph */
+ if (new_graph) {
+ new_graph->vertices->ind=n1;
+ (new_graph->vertices+1)->ind=IND_GRAPH;
+ (new_graph->vertices+1)->subst=board(n,0,0,0,1,1,directed);
+ /* cycle or circuit */
+ new_graph=induced(new_graph,0,0,0,directed);
+ if (new_graph) {
+ sprintf(new_graph->id,"wheel(%u,%u,%d)",@|
+ n,n1,directed?1:0);
+ }
+ }
+ return new_graph;
+}
+
+@ @(gb_basic.h@>=
+extern Graph *complete_bipartite();
+extern Graph *wheel(); /* standard applications of |induced| */
+
+@ @<Basic subroutines@>=
+Graph *induced(g,description,self,multi,directed)
+ Graph *g; /* graph marked for induction in its |ind| fields */
+ char *description; /* string to be mentioned in |new_graph->id| */
+ int self; /* should self-loops be permitted? */
+ int multi; /* should multiple arcs be permitted? */
+ int directed; /* should the graph be directed? */
+{@+@<Vanilla local variables@>@;
+ register Vertex *u;
+ register long n=0; /* total number of vertices in induced graph */
+ register long nn=0; /* number of negative vertices in induced graph */
+ if (g==NULL) panic(missing_operand); /* where is |g|? */
+ @<Set up a graph with the induced vertices@>;
+ @<Insert arcs or edges for induced vertices@>;
+ @<Restore |g| to its original state@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* aargh, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Set up a graph with the induced vertices@>=
+@<Determine |n| and |nn|@>;
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+@<Assign names to the new vertices, and create a map from |g| to |new_graph|@>;
+sprintf(buffer,",%s,%d,%d,%d)",@|description?description:null_string,@|
+ self?1:0,multi?1:0,directed?1:0);
+make_compound_id(new_graph,"induced(",g,buffer);
+
+@ @<Determine |n| and |nn|@>=
+for (v=g->vertices;v<g->vertices+g->n;v++)
+ if (v->ind>0) {
+ if (n>IND_GRAPH) panic(very_bad_specs); /* way too big */
+ if (v->ind>=IND_GRAPH) {
+ if (v->subst==NULL) panic(missing_operand+1);
+ /* substitute graph is missing */
+ n+=v->subst->n;
+ } else n+=v->ind;
+ } else if (v->ind<-nn) nn=-(v->ind);
+if (n>IND_GRAPH || nn>IND_GRAPH) panic(very_bad_specs+1); /* gigantic */
+n+=nn;
+
+@ The negative vertices get the negative number as their name. Split vertices
+get names with an optional prime appended, if the |ind| field is 2;
+otherwise split vertex names are obtained by appending a colon and an index
+number between |0| and~|ind-1|. The name of a vertex within a
+graph |v->subst| is composed of the name of |v| followed by a
+colon and the name within that graph.
+
+We store the original |ind| field in the |mult| field of the first
+corresponding vertex in the new graph, and change |ind| to point to
+that vertex. That convention will make it easy
+to determine the location of each vertex's clone or clones.
+Of course, if the original |ind| field is zero, we leave it zero (|NULL|),
+because it has no corresponding vertex in the new graph.
+
+@<Assign names to the new vertices, and create a map from |g| to |new_graph|@>=
+for (k=1,u=new_graph->vertices;k<=nn;k++,u++) {
+ u->mult=-k;
+ sprintf(buffer,"%d",-k);
+ u->name=gb_save_string(buffer);
+}
+for (v=g->vertices;v<g->vertices+g->n;v++)
+ if ((k=v->ind)<0) v->map=(new_graph->vertices)-(k+1);
+ else if (k>0) {
+ u->mult=k;
+ v->map=u;
+ if (k<=2) {
+ u->name=gb_save_string(v->name);
+ u++;
+ if (k==2) {
+ sprintf(buffer,"%s'",v->name);
+ u->name=gb_save_string(buffer);
+ u++;
+ }
+ } else if (k>=IND_GRAPH) @<Make names and arcs for a substituted graph@>@;
+ else for (j=0;j<k;j++,u++) {
+ sprintf(buffer,"%.*s:%d",BUF_SIZE-12,v->name,j);
+ u->name=gb_save_string(buffer);
+ }
+ }
+
+@ @<Restore |g| to its original state@>=
+for (v=g->vertices;v<g->vertices+g->n;v++)
+ if (v->map) v->ind=v->map->mult;
+for (v=new_graph->vertices;v<new_graph->vertices+n;v++)
+ v->u.i=v->v.i=v->z.i=0; /* clear |tmp|, |mult|, |tlen| */
+
+@ The heart of the procedure to construct an induced graph is, of course,
+the part where we map the arcs of |g| into arcs of |new_graph|.
+
+Notice that if |v| has a self-loop
+in the original graph and if |v| is being split into several vertices,
+it will produce arcs between different clones of itself, but it will not
+produce self-loops unless |self!=0|. In an undirected graph, a loop
+from a vertex to itself will not produce multiple edges among its clones,
+even if |multi!=0|.
+
+More precisely, if |v| has |k| clones |u| through |u+k-1|, an original
+directed arc from |v| to~|v| will generate all $k^2$ possible arcs between
+them, except that the |k| self-loops will be eliminated when
+|self==0|. An original undirected edge from |v| to~|v| will generate
+$k\choose2$ edges between distinct clones, together with |k|
+undirected self-loops if |self!=0|.
+
+@<Insert arcs or edges for induced vertices@>=
+for (v=g->vertices;v<g->vertices+g->n;v++) {
+ u=v->map;
+ if (u) {@+register Arc *a;@+register Vertex *uu,*vv;
+ k=u->mult;
+ if (k<0) k=1; /* |k| is the number of clones of |v| */
+ else if (k>=IND_GRAPH) k=v->subst->n;
+ for (;k;k--,u++) {
+ if (!multi)
+ @<Take note of existing edges that touch |u|@>;
+ for (a=v->arcs;a;a=a->next) {
+ vv=a->tip;
+ uu=vv->map;
+ if (uu==NULL) continue;
+ j=uu->mult;
+ if (j<0) j=1; /* |j| is the number of clones of |vv| */
+ else if (j>=IND_GRAPH) j=vv->subst->n;
+ if (!directed) {
+ if (vv<v) continue;
+ if (vv==v) {
+ if (a->next==a+1) a++; /* skip second half of self-loop */
+ j=k,uu=u; /* also skip duplicate edges generated by self-loop */
+ }
+ }
+ @<Insert arcs or edges from vertex |u| to vertices
+ |uu| through |uu+j-1|@>;
+ }
+ }
+ }
+}
+
+@ Again we use the |tmp| and |tlen| trick of |gunion| to handle
+multiple arcs. (This trick explains why the code in the previous
+section tries to generate as many arcs as possible from a single
+vertex |u|, before changing~|u|.)
+
+@<Take note of existing edges that touch |u|@>=
+for (a=u->arcs;a;a=a->next) {
+ a->tip->tmp=u;
+ if (directed || a->tip>u || a->next==a+1) a->tip->tlen=a;
+ else a->tip->tlen=a+1;
+}
+
+@ @<Insert arcs or edges from vertex |u| to vertices |uu|...@>=
+for (;j;j--,uu++) {
+ if (u==uu && !self) continue;
+ if (uu->tmp==u && !multi)
+ @<Update the minimum arc length from |u| to |uu|, then |continue|@>;
+ if (directed) gb_new_arc(u,uu,a->len);
+ else gb_new_edge(u,uu,a->len);
+ uu->tmp=u;
+ uu->tlen=((directed || u<=uu)? u->arcs: uu->arcs);
+}
+
+@ @<Update the minimum arc length from |u| to |uu|, then |continue|@>=
+{@+register Arc *b=uu->tlen; /* existing arc or edge from |u| to |uu| */
+ if (a->len<b->len) {
+ b->len=a->len; /* remember the minimum length */
+ if (!directed) (b+1)->len=a->len;
+ }
+ continue;
+}
+
+@ We have now accumulated enough experience to finish off the one
+remaining piece of program with ease.
+
+@<Make names and arcs for a sub...@>=
+{@+register Graph *gg=v->subst;
+ register Vertex *vv=gg->vertices;
+ register Arc *a;
+ unsigned long delta=((unsigned long)u)-((unsigned long)vv);
+ for (j=0;j<v->subst->n;j++,u++,vv++) {
+ sprintf(buffer,"%.*s:%.*s",BUF_SIZE/2-1,v->name,(BUF_SIZE-1)/2,vv->name);
+ u->name=gb_save_string(buffer);
+ for (a=vv->arcs;a;a=a->next) {@+register Vertex *vvv=a->tip;
+ Vertex *uu=vert_offset(vvv,delta);
+ if (vvv==vv && !self) continue;
+ if (uu->tmp==u && !multi) @<Update the minimum arc length...@>;
+ if (!directed) {
+ if (vvv<vv) continue;
+ if (vvv==vv && a->next==a+1) a++; /* skip second half of self-loop */
+ gb_new_edge(u,uu,a->len);
+ } else gb_new_arc(u,uu,a->len);
+ uu->tmp=u;
+ uu->tlen=((directed || u<=uu)? u->arcs: uu->arcs);
+ }
+ }
+}
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_basic} are defined and used.
diff --git a/support/graphbase/gb_books.w b/support/graphbase/gb_books.w
new file mode 100644
index 0000000000..520bfb8685
--- /dev/null
+++ b/support/graphbase/gb_books.w
@@ -0,0 +1,542 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace BOOKS}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\def\<#1>{\hbox{$\langle$\rm#1$\rangle$}}
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the |book|
+subroutine, which creates a family of undirected graphs that are based on
+classic works of literature. It also contains the |bi_book|
+subroutine, which creates a related family of bipartite graphs.
+An example of the use of |book| can be found in the demonstration
+program |book_components|.
+
+@(gb_books.h@>=
+extern Graph *book();
+extern Graph *bi_book();
+
+@ The subroutine call `|book(@t\<title>@>,n,x,first_chapter,last_chapter,
+in_weight,out_weight,seed)|'
+constructs a graph based on the information in \<title>\.{.dat},
+where \<title> is either \.{"anna"} (for {\sl Anna Karenina\/}),
+\.{"david"} (for {\sl David Copperfield\/}),
+\.{"jean"} (for {\sl Les Mis\'erables\/}),
+\.{"huck"} (for {\sl Huckleberry Finn\/}), or
+\.{"homer"} (for {\sl The Iliad\/}).
+Each vertex of the graph corresponds to one of the characters in the
+selected book. Edges between vertices correspond to encounters between
+those characters. The length of each edge is~1.
+
+Subsets of the book can be selected by specifying that the edge data should be
+restricted to chapters between |first_chapter| and |last_chapter|,
+inclusive. If |first_chapter=0|, the result is the same as if
+|first_chapter=1|. If |last_chapter=0|, or if |last_chapter| exceeds
+the total number of chapters in the book, the result is the same as
+if |last_chapter| were the number of the book's final chapter.
+
+The constructed graph will have $\min(n,m)-x$ vertices, where |m| is the
+total number of characters in the selected book.
+However, if |n| is zero, |n| is automatically made equal to the maximum
+possible value,~|m|. If |n| is less than~|m|, the |n-x| characters will be
+selected by assigning a weight to each character and choosing the |n| with
+largest weight, then excluding the largest~|x| of these,
+using random numbers to break ties in case of equal weights.
+Weights are computed by the formula
+$$ |in_weight|\cdot\\{chapters\_in}+|out_weight|\cdot\\{chapters\_out}, $$
+where \\{chapters\_in} is the number of chapters between |first_chapter|
+and |last_chapter| in which a particular character appears, and
+\\{chapters\_out} is the number of other chapters in which that
+character appears. Both |in_weight| and |out_weight| must be at most
+1,000,000 in absolute value.
+
+Vertices of the graph will appear in order of decreasing weight.
+The |seed| parameter defines the pseudo-random numbers used wherever
+a ``random'' choice between equal-weight vertices needs to be made.
+As usual with GraphBase routines, different choices of |seed|
+will in general produce different selections,
+but in a system-independent manner; identical results will be obtained on
+all computers when identical parameters have been specified.
+Any |seed| value between 0 and $2^{31}-1$ is permissible.
+
+@ Examples: The call |book("anna",0,0,0,0,0,0,0)| will construct a
+graph on 138 vertices, representing all 138 characters of Tolstoy's
+{\sl Anna Karenina\/} that are recorded in \.{anna.dat}. Two vertices will
+be adjacent if the corresponding characters
+encounter each other anywhere in the book. The call
+|book("anna",50,0,0,0,1,1,0)| is similar, but it is restricted to
+the 50 characters that occur most frequently, i.e., in the most chapters.
+The call |book("anna",50,0,10,120,1,1,0)| has the same vertices, but it
+has edges only for encounters that take place between chapter~10
+and chapter~120, inclusive. The call |book("anna",50,0,10,120,1,0,0)| is
+similar, but its vertices are the 50 characters that occur most often in
+chapters 10 through~120, without regard to how often they occur in
+the rest of the book. The call |book("anna",50,0,10,120,0,0,0)| is
+also similar, but it chooses 50 characters completely at random
+(possibly from those that don't occur in the selected chapters at all).
+
+Parameter |x|, which causes the |x| vertices of highest weight to be
+excluded, is usually either 0 or~1. It is provided primarily so that
+users can set |x=1| with respect to {\sl David Copperfield\/} and {\sl
+Huckleberry Finn}; those novels are narrated by their principal
+character, so they have edges between the principal character and
+almost everybody else. (Characters cannot get into the action of a
+first-person account unless they encounter the narrator or unless the
+narrator is quoting some other person's story.) The corresponding
+graphs tend to have more interesting connectivity properties if we
+leave the narrator out by setting |x=1|. For example, there are 87
+characters in {\sl David Copperfield\/}; the call
+|book("david",0,1,0,0,1,1,0)| produces a graph with 86 vertices, one
+for every character except David Copperfield himself.
+
+@ The subroutine call |bi_book(@t\<title>@>,n,x,first_chapter,last_chapter,
+in_weight,out_weight,seed)| produces a bipartite graph in which the
+vertices of the first part are exactly the same as the vertices of the
+graph returned by |book|, while the vertices of the second part are
+the selected chapters. For example,
+$|bi_book|(|"anna"|,\allowbreak 50,0,10,120,1,1,0)$
+creates a bipartite graph with $50+111$ vertices. There is an edge between
+each character and the chapters in which that character appears.
+
+@ Chapter numbering needs further explanation. {\sl Anna Karenina\/}
+has 239 chapters, which are numbered 1.1 through 8.19 in the
+work itself but renumbered 1 through 239 as far as the |book| routine
+is concerned. Thus, setting |first_chapter=10| and |last_chapter=120|
+turns out to be equivalent to selecting chapters 1.10 through 4.19
+(more precisely, chapter~10 of book~1 through chapter~19 of book~4).
+{\sl Les Mis\'erables\/} has an even more involved scheme; its
+356 chapters range from 1.1.1 (part~1, book~1, chapter~1) to
+5.9.6 (part~5, book~9, chapter~6). After |book| or |bi_book| has created
+a graph, the external integer variable |chapters| will contain the total
+number of chapters, and |chap_name| will be an array of strings
+containing the structured chapter numbers. For example, after
+|book("jean",@t\dots@>)|, we will have |chapters=356|,
+|chap_name[1]="1.1.1"|, \dots, |chap_name[356]="5.9.6"|;
+|chap_name[0]| will be~|""|.
+
+@d MAX_CHAPS 360 /* no book will have this many chapters */
+
+@<External variables@>=
+int chapters; /* the total number of chapters in the selected book */
+char *chap_name[MAX_CHAPS]={""}; /* string names of those chapters */
+
+@ As usual, we put declarations of the external variables into the header file
+for user to {\bf include}.
+
+@(gb_books.h@>=
+extern int chapters; /* the total number of chapters in the selected book */
+extern char *chap_name[]; /* string names of those chapters */
+
+@ If the |book| or |bi_book| routine encounters a problem, it
+returns |NULL| (\.{NULL}),
+after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |book| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in |gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+@f node int /* the \&{node} type is defined below */
+
+@ The \Cee\ file \.{gb\_books.c} has the overall shape shown here.
+It makes use of an internal subroutine
+called |bgraph|, which combines the work of |book| and |bi_book|.
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_flip.h" /* we will use the |gb_flip| routines
+ for random numbers */
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+#include "gb_sort.h" /* and the |gb_linksort| routine */
+@#
+@<Type declarations@>@;
+@<Private variables@>@;
+@<External variables@>@;
+@#
+static Graph *bgraph(bipartite,
+ title,n,x,first_chapter,last_chapter,in_weight,out_weight,seed)
+ int bipartite; /* should we make the graph bipartite? */
+ char *title; /* identification of the selected book */
+ unsigned n; /* number of vertices desired before exclusion */
+ unsigned x; /* number of vertices to exclude */
+ unsigned first_chapter, last_chapter;
+ /* interval of chapters leading to edges */
+ long in_weight; /* weight coefficient pertaining to chapters
+ in that interval */
+ long out_weight; /* weight coefficient pertaining to chapters
+ not in that interval */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+ gb_init_rand(seed);
+ @<Check that the parameters are valid@>;
+ @<Skim the data file, recording the characters and computing their weights@>;
+ @<Choose the vertices and put them into an empty graph@>;
+ @<Read the data file more carefully and fill the graph as instructed@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* (expletive deleted)
+ we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+@#
+Graph *book(title,n,x,first_chapter,last_chapter,in_weight,out_weight,seed)
+ char *title;
+ unsigned n, x, first_chapter, last_chapter;
+ long in_weight,out_weight,seed;
+{@+return bgraph(0,title,n,x,first_chapter,last_chapter,
+ in_weight,out_weight,seed);@+}
+Graph *bi_book(title,n,x,first_chapter,last_chapter,in_weight,out_weight,seed)
+ char *title;
+ unsigned n, x, first_chapter, last_chapter;
+ long in_weight,out_weight,seed;
+{@+return bgraph(1,title,n,x,first_chapter,last_chapter,
+ in_weight,out_weight,seed);@+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |book| or |bi_book| */
+register int j,k; /* all-purpose indices */
+register node *p;
+int characters; /* the total number of characters in the selected book */
+
+@ @d MAX_CHARS 600 /* there won't be more characters than this */
+
+@<Check that the parameters are valid@>=
+if (n==0) n=MAX_CHARS;
+if (first_chapter==0) first_chapter=1;
+if (last_chapter==0) last_chapter=MAX_CHAPS;
+if (in_weight>1000000 || in_weight<-1000000 ||
+ out_weight>1000000 || out_weight<-1000000)
+ panic(bad_specs); /* the magnitude of at least one weight is too big */
+sprintf(file_name,"%.6s.dat",title);
+if (gb_open(file_name)!=0)
+ panic(early_data_fault); /* couldn't open the file; |io_errors| tells why */
+
+@ @<Priv...@>=
+static char file_name[]="xxxxxx.dat";
+static char null_string[1]; /* a null string constant */
+
+@*Vertices.
+Each character in a book has been given a two-letter code name for
+internal use. The code names are explained at the beginning of each
+data file by a number of lines that look like this:
+$$\hbox{\tt XX \<name>,\<description>}$$
+For example, here's one of the lines near the beginning of |"anna.dat"|:
+$$\hbox{\tt AL Alexey Alexandrovitch Karenin, minister of state}$$
+The \<name> does not contain a comma; the \<description> might.
+
+A blank line follows the cast of characters.
+
+Internally, we will think of the two-letter code as a radix-36 integer.
+Thus, \.{AA} will be the number $10\times36+10$, and \.{ZZ} will be
+$35\times36+35$. The |gb_number| routine in |gb_io| is set up to
+input radix-36 integers just as it does hexadecimal ones.
+In {\sl The Iliad}, many of the minor characters have numeric digits
+in their code names, because the total number of characters is too
+large to permit mnemonic codes for everybody.
+
+@d MAX_CODE 1296 /* $36\times36$, the number of two-digit codes in radix 36 */
+
+@ In order to choose the vertices, we want to represent each character
+as a node whose key corresponds to its weight; then the |gb_linksort|
+routine of |gb_sort| will provide the desired rank-ordering. We will
+find it convenient to use these nodes for all the data processing that
+|bgraph| has to do.
+
+@<Type dec...@>=
+typedef struct node_struct { /* records to be sorted by |gb_linksort| */
+ long key; /* the nonnegative sort key (weight plus $2^{30}$) */
+ struct node_struct *link; /* pointer to next record */
+ int code; /* code number of this character */
+ int in; /* number of occurrences in selected chapters */
+ int out; /* number of occurrences in unselected chapters */
+ int chap; /* seen most recently in this chapter */
+ Vertex *v; /* vertex corresponding to this character */
+} node;
+
+@ Not only do nodes point to codes, we also want codes to point to nodes.
+
+@<Priv...@>=
+static node node_block[MAX_CHARS]; /* array of nodes for working storage */
+static node *xnode[MAX_CODE]; /* the node, if any, having a given code */
+
+@ We will read the data file twice, once quickly (to collect statistics)
+and once more thoroughly (to record detailed information). Here is the
+quick version.
+
+@<Skim the data file, recording the characters and computing their weights@>=
+@<Read the character codes at the beginning of the data file, and
+ prepare a node for each one@>;
+@<Skim the chapter information, counting the number of chapters in
+ which each character appears@>;
+if (gb_close()!=0)
+ panic(late_data_fault);
+ /* check sum or other failure in data file; see |io_errors| */
+
+@ @<Read the character codes...@>=
+for (k=0;k<MAX_CODE;k++) xnode[k]=NULL;
+{@+register int c; /* current code entering the system */
+ p=node_block; /* current node entering the system */
+ while ((c=gb_number(36))!=0) { /* note that \.{00} is not a legal code */
+ if (c>=MAX_CODE || gb_char()!=' ') panic(syntax_error);
+ /* unreadable line in data file */
+ if (p>=&node_block[MAX_CHARS])
+ panic(syntax_error+1); /* data has too many characters */
+ p->link=(p==node_block?NULL:p-1);
+ p->code=c;
+ xnode[c]=p;
+ p->in=p->out=p->chap=0;
+ p->v=NULL;
+ p++;
+ gb_newline();
+ }
+ characters=p-node_block;
+ gb_newline(); /* bypass the blank line that terminates the character data */
+}
+
+@ Later we will read through this part of the file again, extracting
+additional information if it turns out to be relevant. The
+\<description> string is provided to users in a |desc| field,
+in case anybody cares to look at it. The |in| and |out| statistics
+are also made available in utility fields called |in_count| and |out_count|.
+The code value is placed in the |short_code| field.
+
+@d desc z.s /* utility field |z| points to the \<description> string */
+@d in_count y.i /* utility field |y| counts appearances in selected chapters */
+@d out_count x.i /* utility field |x| counts appearances in other chapters */
+@d short_code u.i /* utility field |u| contains a radix-36 number */
+
+@<Read the data about characters again, noting vertex names and the
+ associated descriptions@>=
+{@+register int c; /* current code entering the system a second time */
+ while ((c=gb_number(36))!=0) {@+register Vertex *v=xnode[c]->v;
+ if (v) {
+ if (gb_char()!=' ') panic(impossible); /* can't happen */
+ gb_string(str_buf,','); /* scan the \<name> part */
+ v->name=gb_save_string(str_buf);
+ if (gb_char()!=',')
+ panic(syntax_error+2); /* missing comma after \<name> */
+ gb_string(str_buf,'\n'); /* scan the \<description> part */
+ v->desc=gb_save_string(str_buf);
+ v->in_count=xnode[c]->in;
+ v->out_count=xnode[c]->out;
+ v->short_code=c;
+ }
+ gb_newline();
+ }
+ gb_newline(); /* bypass the blank line that terminates the character data */
+}
+
+@ @(gb_books.h@>=
+#define desc @t\quad@> z.s /* utility field definitions for the header file */
+#define in_count @t\quad@> y.i
+#define out_count @t\quad@> x.i
+#define short_code @t\quad@> u.i
+
+@*Edges.
+The second part of the data file has a line for each chapter, containing
+``cliques of encouters.'' For example, the line
+$$\hbox{\tt3.22:AA,BB,CC,DD;CC,DD,EE;AA,FF}$$
+means that, in chapter 22 of book 3, there were encounters between the pairs
+$$\def\\{{\rm,} }
+\hbox{\tt AA-BB\\AA-CC\\AA-DD\\BB-CC\\BB-DD\\CC-DD\\CC-EE\\DD-EE\\{\rm and }%
+AA-FF\rm.}$$
+(The encounter \.{CC-DD} is specified twice, once in the clique
+\.{AA,BB,CC,DD} and once in \.{CC,DD,EE}; this does not imply anything about
+the actual number of encounters between \.{CC} and \.{DD} in the chapter.)
+
+A clique might involve one character only, when that character is featured
+in sort of a soliloquy.
+
+A chapter might contain no references to characters at all. In such a case
+the `\.:' following the chapter number is omitted.
+
+There may be more encounters than will fit on a single line. In such cases,
+continuation lines begin with `\.{\&:}'. This convention turns out to be
+needed only in \.{homer.dat}; chapters in {\sl The Iliad\/} are
+substantially more complex than the chapters in other GraphBase books.
+
+On our first pass over the data, we simply want to compute statistics about
+who appears in what chapters, so we ignore the distinction between
+commas and semicolons.
+
+@<Skim the chapter information, counting the number of chapters in
+ which each character appears@>=
+for (k=1; k<MAX_CHAPS && !gb_eof(); k++) {
+ gb_string(str_buf,':'); /* read past the chapter number */
+ if (str_buf[0]=='&') k--; /* continuation of previous chapter */
+ while (gb_char()!='\n') {@+register int c=gb_number(36);
+ register node *p;
+ if (c>=MAX_CODE)
+ panic(syntax_error+3); /* missing punctuation between characters */
+ p=xnode[c];
+ if (p==NULL) panic(syntax_error+4); /* unknown character */
+ if (p->chap!=k) {
+ p->chap=k;
+ if (k>=first_chapter && k<=last_chapter) p->in++;
+ else p->out++;
+ }
+ }
+ gb_newline();
+}
+if (k==MAX_CHAPS) panic(syntax_error+5); /* too many chapters */
+chapters=k;
+
+@ Our second pass over the data is very similar to the first, if we
+are simply computing a bipartite graph. In that case we add an edge
+to the graph between each selected chapter and each selected character
+in that chapter. Local variable |chap_base| will point to a
+vertex such that |chap_base+k| is the vertex corresponding to chapter~|k|.
+
+The |in_count| of a chapter vertex is the degree of that vertex, i.e., the
+number of selected characters that appear in the corresponding chapter.
+The |out_count| is the number of characters that appear in the
+chapter but were omitted from the graph. Thus, the |in_count| and
+|out_count| for chapters are analogous to the |in_count| and |out_count|
+for characters.
+
+@<Read the chapter information a second time and create the
+ appropriate bipartite edges@>=
+{
+ for (p=node_block;p<node_block+characters;p++) p->chap=0;
+ for (k=1; !gb_eof(); k++) {
+ gb_string(str_buf,':'); /* read the chapter number */
+ if (str_buf[0]=='&') k--;
+ else chap_name[k]=gb_save_string(str_buf);
+ if (k>=first_chapter && k<=last_chapter) {@+register Vertex *u=chap_base+k;
+ if (str_buf[0]!='&') {
+ u->name=chap_name[k];
+ u->desc=null_string;
+ u->in_count=u->out_count=0;
+ }
+ while (gb_char()!='\n') {@+register int c=gb_number(36);
+ p=xnode[c];
+ if (p->chap!=k) {@+register Vertex *v=p->v;
+ p->chap=k;
+ if (v) {
+ gb_new_edge(v,u,1);
+ u->in_count++;
+ } else u->out_count++;
+ }
+ }
+ }
+ gb_newline();
+ }
+}
+
+@ @<Local variables@>=
+Vertex *chap_base;
+ /* the bipartite vertex for chapter~|k| is |chap_base+k| */
+
+@ The second pass has to work a little harder when we are recording
+encounters from cliques, but the logic isn't difficult really.
+We insert a reference to the first chapter that generated each edge, in
+utility field |chap_no| of the corresponding |Arc| record.
+
+@d chap_no a.i /* utility field |a| holds a chapter number */
+
+@<Read the chapter information a second time and create the
+ appropriate edges for encounters@>=
+for (k=1; !gb_eof(); k++) {
+ gb_string(str_buf,':'); /* read the chapter number */
+ if (str_buf[0]=='&') k--;
+ else chap_name[k]=gb_save_string(str_buf);
+ if (k>=first_chapter && k<=last_chapter) {@+register int c=gb_char();
+ while (c!='\n') {@+register Vertex **pp=clique_table;
+ register Vertex **qq,**rr; /* pointers within the clique table */
+ do@+{
+ c=gb_number(36); /* set |c| to code for next character of clique */
+ if (xnode[c]->v) /* is that character a selected vertex? */
+ *pp++=xnode[c]->v; /* if so, that vertex joins the current clique */
+ c=gb_char();
+ }@+while (c==','); /* repeat until end of the clique */
+ for (qq=clique_table;qq+1<pp;qq++)
+ for (rr=qq+1;rr<pp;rr++)
+ @<Make the vertices |*qq| and |*rr| adjacent,
+ if they aren't already@>;
+ }
+ }
+ gb_newline();
+}
+
+@ @(gb_books.h@>=
+#define chap_no @[a.i@] /* utility field definition in the header file */
+
+@ @<Priv...@>=
+static Vertex *clique_table[30];
+ /* pointers to vertices in the current clique */
+
+@ @<Make the vertices |*qq| and |*rr| adjacent...@>=
+{@+register Vertex *u=*qq, *v=*rr;
+ register Arc *a;
+ for (a=u->arcs; a; a=a->next)
+ if (a->tip==v) goto found;
+ gb_new_edge(u,v,1); /* not found, so they weren't already adjacent */
+ if (u<v) a=u->arcs;
+ else a=v->arcs; /* the new edge consists of arcs |a| and |a+1| */
+ a->chap_no=(a+1)->chap_no=k;
+found:;
+}
+
+@*Administration.
+The program is now complete except for a few missing organizational details.
+I will add these after lunch.
+@^out to lunch@>
+
+@ OK, I'm back; what needs to be done? The main thing is to create
+the graph itself.
+
+@<Choose the vertices and put them into an empty graph@>=
+if (n>characters) n=characters;
+if (x>n) x=n;
+if (last_chapter>chapters) last_chapter=chapters;
+if (first_chapter>last_chapter) first_chapter=last_chapter+1;
+new_graph=gb_new_graph(n-x+(bipartite?last_chapter-first_chapter+1:0));
+if (new_graph==NULL) panic(no_room); /* out of memory already */
+strcpy(new_graph->format,"IZZIISIZZZZZZZ");
+ /* declare the types of utility fields */
+sprintf(new_graph->id,"%sbook(\"%s\",%u,%u,%u,%u,%ld,%ld,%ld)",
+ bipartite?"bi_":"",title,n,x,first_chapter,last_chapter,
+ in_weight,out_weight,seed);
+if (bipartite) {
+ mark_bipartite(new_graph,n-x);
+ chap_base=new_graph->vertices+(new_graph->n_1-first_chapter);
+}
+@<Compute the weights and assign vertices to chosen nodes@>;
+
+@ @<Compute the weights and assign vertices to chosen nodes@>=
+for (p=node_block; p<node_block+characters; p++)
+ p->key=in_weight*(p->in)+out_weight*(p->out)+0x40000000;
+gb_linksort(node_block+characters-1);
+k=n; /* we will look at this many nodes */
+{@+register Vertex *v=new_graph->vertices; /* the next vertex to define */
+ for (j=127; j>=0; j--)
+ for (p=(node*)gb_sorted[j]; p; p=p->link) {
+ if (x>0) x--; /* ignore this node */
+ else p->v=v++; /* choose this node */
+ if (--k==0) goto done;
+ }
+}
+done:;
+
+@ Once the graph is there, we're ready to fill it in.
+
+@<Read the data file more carefully and fill the graph as instructed@>=
+if (gb_open(file_name)!=0)
+ panic(impossible+1);
+ /* this can't happen, because we were successful before */
+@<Read the data about characters again, noting vertex names and the
+ associated descriptions@>;
+if (bipartite)
+ @<Read the chapter information a second time and create the
+ appropriate bipartite edges@>@;
+else @<Read the chapter information a second time and create the
+ appropriate edges for encounters@>;
+if (gb_close()!=0)
+ panic(impossible+2); /* again, can hardly happen the second time around */
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_books} are defined and used.
diff --git a/support/graphbase/gb_dijk.w b/support/graphbase/gb_dijk.w
new file mode 100644
index 0000000000..038f8f32e9
--- /dev/null
+++ b/support/graphbase/gb_dijk.w
@@ -0,0 +1,445 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace DIJK}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GRAPH}
+@* Introduction. The GraphBase demonstration routine |dijkstra(uu,vv,gg,hh)|
+finds a shortest path from vertex~|uu| to vertex~|vv| in graph~|gg|, with the
+aid of an optional heuristic function~|hh|. This function implements a
+version of Dijkstra's algorithm, a general procedure for determining
+shortest paths in a directed graph that has nonnegative arc lengths
+[E.~W. Dijkstra, ``A note a two problems in connexion with graphs,''
+{\sl Numerische Mathematik\/ \bf1} (1959), 269--271].
+
+If |hh| is null, the length of
+every arc in |gg| must be nonnegative. If |hh| is non-null, |hh| should be
+a function defined on the vertices of the graph such that the
+length |d| of an arc from |u| to~|v| always satisfies the condition
+$$ d \ge |hh|(u)-|hh|(v)\,. $$
+In such a case, we can effectively replace each arc length |d| by
+|d-hh(u)+hh(v)|, obtaining a graph with nonnegative arc lengths;
+the shortest paths between vertices in this modified graph
+are the same as they were in the original graph.
+
+The basic idea of Dijkstra's algorithm is to explore the vertices of
+the graph in order of their distance from the starting vertex~|uu|,
+proceeding until |vv| is encountered. If the distances have been
+modified by a heuristic function |hh| such that |hh(u)| happens to equal
+the true distance from |u| to~|vv|, for all~|u|,
+then all of the modified distances on
+shortest paths to |vv| will be zero; this means that the algorithm
+will explore all of the most useful arcs first, so it will not waste
+time wandering off in unfruitful directions. In practice we usually
+don't know the exact distances to |vv| in advance, but we can often
+compute an approximate value |hh(u)| that will help focus the search.
+
+If the external variable |verbose| is nonzero, |dijkstra| will record
+its activities, by printing the distances from |uu| to all vertices
+it visits on the standard output file.
+
+After |dijkstra| has found a shortest path, it returns the length of
+that path. If no path from |uu| to~|vv| exists (in particular, if
+|vv| is~|NULL|), it returns |-1|; in such a case, the shortest distances from
+|uu| to all vertices reachable from it will have been computed and
+they can be found in the graph.
+An auxiliary function, |print_dijkstra_result(vv)|, can be used
+to display the actual path found, if one exists.
+
+Examples of the use of |dijkstra| appear in the |ladders| demonstration module.
+
+@f Vertex int
+@f Arc int
+@f Graph int
+
+@ This \Cee\ module is meant to be loaded as part of another program.
+It has the following simple structure:
+
+@p
+#include "gb_graph.h" /* define the standard GraphBase data structures */
+@<Priority queue procedures@>@;
+@<Global declarations@>@;
+@<The |dijkstra| procedure@>@;
+@<The |print_dijkstra_result| procedure@>@;
+
+@ Users of |gb_dijk| should include the header file \.{gb\_dijk.h}:
+
+@(gb_dijk.h@>=
+extern long dijkstra(); /* procedure to calculate shortest paths */
+extern void print_dijkstra_result(); /* procedure to display the answer */
+
+@* The main algorithm.
+As Dijkstra's algorithm proceeds, it ``knows'' shortest paths from |uu|
+to more and more vertices; we will call these vertices ``known.''
+Initially only |uu| itself is known. The procedure terminates when |vv|
+becomes known, or when all vertices reachable from~|uu| are known.
+
+Dijkstra's algorithm looks at all vertices adjacent to known vertices.
+A vertex is said to have been ``seen'' if it is either known or
+adjacent to a vertex that's known.
+
+The algorithm proceeds by learning to know all vertices in a greater
+and greater radius from the starting point. Thus, if |v|~is a known
+vertex at distance~|d| from~|uu|, every vertex at distance |<d| from
+|uu| will also be known. (Throughout this discussion the word
+``distance'' actually means ``distance modified by the heuristic
+function''; we omit mentioning the heuristic because we can assume that
+the algorithm is operating on a graph with modified distances.)
+
+The algorithm maintains an auxiliary list of all vertices that have been
+seen but aren't yet known. For every such vertex~|v|, it remembers
+the shortest distance~|d| from |uu| to~|v| by a path that passes entirely
+through known vertices except for the very last arc.
+
+This auxiliary list is actually a priority queue, ordered by the |d| values.
+If |v|~is a vertex of the priority queue having the smallest |d|, we can
+remove |v| from the queue and consider it known, because there cannot be
+a path of length less than~|d| from |uu| to~|v|. (This is where the
+assumption of nonnegative arc length is crucial to the algorithm's validity.)
+
+@ To implement the ideas just sketched, we use several of the utility
+fields in vertex records. Each vertex~|v| has a |dist| field |v->dist|,
+representing its true distance from |uu| if |v| is known, otherwise
+representing the shortest distance from |uu| discovered so far.
+
+Each vertex |v| also has a |backlink| field |v->backlink|, which is non-|NULL|
+if and only if |v| has been seen. In that case |v->backlink| is a vertex one
+step ``closer'' to |uu|, on a path from |uu| to |v| that achieves the
+current distance |v->dist|. (Exception:
+Vertex~|uu| has a backlink pointing to itself.) The backlink
+fields thereby allow us to construct shortest paths from |uu| to all the
+known vertices, if desired.
+
+@d dist z.i /* distance from |uu|, modified by |hh|,
+ appears in vertex utility field |z| */
+@d backlink y.v /* pointer to previous vertex appears in utility field |y| */
+
+@(gb_dijk.h@>=
+#define dist @[z.i@]
+#define backlink @[y.v@]
+
+@ The priority queue is implemented by four procedures:
+
+\def\]#1 {\smallskip\hangindent2\parindent \hangafter1 \indent #1 }
+
+\]|init_queue(d)| makes the queue empty and prepares for subsequent keys |>=d|.
+
+\]|enqueue(v,d)| puts vertex |v| in the queue and assigns it the key
+value |v->dist=d|.
+
+\]|requeue(v,d)| takes vertex |v| out of the queue and enters it again
+with the smaller key value |v->dist=d|.
+
+\]|delete_min()| removes a vertex with minimum key from the queue and
+returns a pointer to that vertex. If the queue is empty, |NULL| is returned.
+
+\smallskip\noindent
+These procedures are accessed via external pointers,
+so that the user of |gb_dijk| can supply alternate queueing methods if desired.
+
+@(gb_dijk.h@>=
+extern void (*init_queue)(); /* create an empty priority queue for |dijkstra| */
+extern void (*enqueue)(); /* insert a new element in the priority queue */
+extern void (*requeue)(); /* decrease the key of an element in the queue */
+extern Vertex *(*delete_min)(); /* remove an element with smallest key */
+
+@ The heuristic function may take awhile to compute, so we avoid recomputation
+by storing |hh(v)| in another utility field |v->hh_val| once we've
+evaluated it.
+
+@d hh_val x.i /* computed value of |hh(u)| */
+
+@(gb_dijk.h@>=
+#define hh_val @[x.i@]
+
+@ If no heuristic function is supplied by the user, we replace it by a
+dummy function that simply returns 0 in all cases.
+
+@<Global...@>=
+long dummy(v)
+ Vertex *v;
+{@+return 0;@+}
+
+@ Here now is |dijkstra|:
+
+@<The |dijkstra| procedure@>=
+long dijkstra(uu,vv,gg,hh)
+ Vertex *uu; /* the starting point */
+ Vertex *vv; /* the ending point */
+ Graph *gg; /* the graph they belong to */
+ long (*hh)(); /* heuristic function */
+{@+register Vertex *t; /* current vertex of interest */
+ if (hh==NULL)
+ hh=dummy; /* change to default heuristic */
+ @<Make |uu| the only vertex seen; also make it known@>;
+ t=uu;
+ if (verbose) @<Print initial message@>;
+ while (t!=vv) {
+ @<Put all unseen vertices adjacent to |t| into the queue,
+ and update the distances of other vertices adjacent to~|t|@>;
+ t=(*delete_min)();
+ if (t==NULL)
+ return -1; /* if the queue becomes, there's no way to get to |vv| */
+ if (verbose) @<Print the distance to |t|@>;
+ }
+ return vv->dist-vv->hh_val+uu->hh_val; /* true distance from |uu| to |vv| */
+}
+
+@ As stated above, a vertex is considered seen only when its backlink
+isn't null, and known only when it is seen but not in the queue.
+
+@<Make |uu| the only...@>=
+for (t=gg->vertices+gg->n-1; t>=gg->vertices; t--) t->backlink=NULL;
+uu->backlink=uu;
+uu->dist=0;
+uu->hh_val=(*hh)(uu);
+(*init_queue)(0); /* make the priority queue empty */
+
+@ Here we help the \Cee\ compiler in case it hasn't got a great optimizer.
+
+@<Put all unseen vertices adjacent to |t| into the queue...@>=
+{@+register Arc *a; /* an arc leading from |t| */
+ register long d = t->dist - t->hh_val;
+ for (a=t->arcs; a; a=a->next) {
+ register Vertex *v = a->tip; /* a vertex adjacent to |t| */
+ if (v->backlink) { /* |v| has already been seen */
+ register long dd = d + a->len + v->hh_val;
+ if (dd< v->dist) {
+ v->backlink = t;
+ (*requeue)(v,dd); /* we found a better way to get there */
+ }
+ } else { /* |v| hasn't been seen before */
+ v->hh_val = (*hh)(v);
+ v->backlink = t;
+ (*enqueue)(v, d + a->len + v->hh_val);
+ }
+ }
+}
+
+@ The |dist| fields don't contain true distances in the graph; they
+represent distances modified by the heuristic function. The true distance
+from |uu| to vertex |v| is |v->dist - v->hh_val + uu->hh_val|.
+
+When printing the results, we show true distances. Also, if a nontrivial
+heuristic is being used, we give the |hh| value in brackets; the user can then
+observe that vertices are becoming known in order of true distance
+plus |hh| value.
+
+@<Print initial message@>=
+{@+printf("Distances from %s", uu->name);
+ if (hh!=dummy) printf(" [%ld]", uu->hh_val);
+ printf(":\n");
+}
+
+@ @<Print the distance to |t|@>=
+{@+printf(" %ld to %s", t->dist - t->hh_val + uu->hh_val, t->name);
+ if (hh!=dummy) printf(" [%ld]", t->hh_val);
+ printf(" via %s\n", t->backlink->name);
+}
+
+@ After |dijkstra| has found a shortest path, the backlinks from~|vv|
+specify the steps of that path. We want to print the path in the forward
+direction, so we reverse the links.
+
+We also unreverse them again, just in case the user didn't want the backlinks
+to be trashed. Indeed, this procedure can be used for any vertex |vv| whose
+backlink is nonnull, not only the |vv| that was a parameter to |dijkstra|.
+
+List reversal is conveniently regarded as a process of popping off one stack
+and pushing onto another.
+
+@<The |print_dijkstra_result| procedure@>=
+void print_dijkstra_result(vv)
+ Vertex *vv; /* ending vertices */
+{@+register Vertex *t, *p, *q; /* registers for reversing links */
+ t=NULL, p=vv;
+ if (!p->backlink) {
+ printf("Sorry, %s is unreachable.\n",p->name);
+ return;
+ }
+ do { /* pop an item from |p| to |t| */
+ q=p->backlink;
+ p->backlink=t;
+ t=p;
+ p=q;
+ } while (t!=p); /* the loop stops with |t==p==uu| */
+ do {
+ printf("%10ld %s\n", t->dist-t->hh_val+p->hh_val, t->name);
+ t=t->backlink;
+ } while (t);
+ t=p;
+ do { /* pop an item from |t| to |p| */
+ q=t->backlink;
+ t->backlink=p;
+ p=t;
+ t=q;
+ } while (p!=vv);
+}
+
+@* Priority queues. Here we provide a simple doubly linked list
+for queueing; this is a convenient default, good enough for applications
+that aren't too large. (See |miles_span| for implementations of
+other schemes that are more efficient when the queue gets large.)
+
+@<Glob...@>=
+void (*init_queue)() = init_dlist; /* create an empty dlist */
+void (*enqueue)() = enlist; /* insert a new element in dlist */
+void (*requeue)() = reenlist ; /* decrease the key of an element in dlist */
+Vertex *(*delete_min)() = delete_first; /* remove element with smallest key */
+
+@ The two queue links will occupy two of a vertex's remaining utility fields.
+There's a special list head, from which we get to everything else in the
+queue in decreasing order of keys by following |llink| fields.
+
+The following declaration actually provides for 128 list heads. Only the first
+of these will be used here, but we'll find something to do with the
+other 127 later.
+
+@d llink v.v /* |llink| is stored in utility field |v| of a vertex */
+@d rlink w.v /* |rlink| is stored in utility field |w| of a vertex */
+
+@<Prior...@>=
+Vertex head[128]; /* list-head elements that are always present */
+@#
+void init_dlist(d)
+ long d;
+{
+ head->llink=head->rlink=head;
+ head->dist=d-1; /* a value guaranteed to be smaller than any actual key */
+}
+
+@ It seems reasonable to assume that an element entering the queue for the
+first time will tend to have a larger key than the other elements.
+
+Indeed, in the special case that all arcs in the graph have the same
+length, this strategy turns out to be quite fast. For in that case,
+every vertex will be added to the end of the queue and deleted from the
+front, without any requeueing; the algorithm will produce a strict
+first-in-first-one queueing discipline.
+
+@<Prior...@>=
+void enlist(v,d)
+ Vertex *v;
+ long d;
+{@+register Vertex *t=head->llink;
+ v->dist=d;
+ while (d<t->dist) t=t->llink;
+ v->llink=t;
+ (v->rlink=t->rlink)->llink=v;
+ t->rlink=v;
+}
+
+@ @<Prior...@>=
+void reenlist(v,d)
+ Vertex *v;
+ long d;
+{@+register Vertex *t=v->llink;
+ (t->rlink=v->rlink)->llink=v->llink; /* remove |v| */
+ v->dist=d; /* we assume that the new |dist| is smaller than it was before */
+ while (d<t->dist) t=t->llink;
+ v->llink=t;
+ (v->rlink=t->rlink)->llink=v;
+ t->rlink=v;
+}
+
+@ @<Prior...@>=
+Vertex *delete_first()
+{@+Vertex *t;
+ t=head->rlink;
+ if (t==head) return NULL;
+ (head->rlink=t->rlink)->llink=head;
+ return t;
+}
+
+@* A special case. When the arc lengths in the graph are all fairly small,
+we can substitute another queuing discipline that does each operation
+quickly. Suppose the only lengths are 0, 1, \dots,~|k-1|; then we can
+prove easily that the priority queue will never contain more than |k|
+different values at once. Moreover, we can implement it by maintaining
+|k| doubly linked lists, one for each key value mod~|k|.
+
+For example, let |k=128|. Here is an alternate set of queue commands,
+to be used when the arc lengths are known to be less than~128.
+
+@ @<Prior...@>=
+long master_key; /* smallest key that may be present in the priority queue */
+@#
+void init_128(d)
+ long d;
+{@+register Vertex *u;
+ master_key=d;
+ for (u=head; u<head+128; u++)
+ u->llink=u->rlink=u;
+}
+
+@ If the number of lists were not a power of 2, we would calculate a remainder
+by division instead of by logical-anding with |0x7f|.
+
+@<Prior...@>=
+Vertex *delete_from_128()
+{@+long d;
+ register Vertex *u, *t;
+ for (d=master_key; d<master_key+128; d++) {
+ u=head+(d&0x7f); /* that's |d%128| */
+ t=u->rlink;
+ if (t!=u) { /* we found a nonempty list with minimum key */
+ master_key=d;
+ (u->rlink = t->rlink)->llink = u;
+ return t; /* incidentally, |t->dist = d| */
+ }
+ }
+ return NULL; /* all 128 lists are empty */
+}
+
+@ @<Prior...@>=
+void enqueue_128(v,d)
+ Vertex *v; /* new vertex for the queue */
+ long d; /* its |dist| */
+{@+register Vertex *u=head+(d&0x7f);
+ v->dist = d;
+ (v->llink = u->llink)->rlink = v;
+ v->rlink = u;
+ u->llink = v;
+}
+
+@ All of these operations have been so simple, one wonders why the lists
+should be doubly linked. Single linking would indeed be plenty---if we
+didn't have to support the |requeue| operation.
+
+But requeueing involves deleting an arbitrary element from the middle of
+its list. And we do seem to need two links for that.
+
+In the application to Dijkstra's algorithm, the new |d| will always
+be |master_key| or more. But we want to implement requeueing in general,
+so that this procedure can be used also for other algorithms,
+such as the calculation of minimum spanning trees (see |miles_span|).
+
+@<Prior...@>=
+void requeue_128(v,d)
+ Vertex *v; /* vertex to be moved to another list */
+ long d; /* its new |dist| */
+{@+register Vertex *u=head+(d&0x7f);
+ (v->llink->rlink=v->rlink)->llink=v->llink; /* remove |v| */
+ v->dist=d; /* the new |dist| is smaller than it was before */
+ (v->llink=u->llink)->rlink = v;
+ v->rlink = u;
+ u->llink = v;
+ if (d<master_key) master_key=d; /* not needed for Dijkstra's algorithm */
+}
+
+@ The user of |gb_dijk| needs to know the names of these queueing procedures
+if changes to the defaults are made, so we'd better put the necessary info
+into the header file.
+
+@(gb_dijk.h@>=
+extern void init_dlist();
+extern void enlist();
+extern void reenlist();
+extern Vertex *delete_first();
+extern void init_128();
+extern Vertex *delete_from_128();
+extern void enqueue_128();
+extern void requeue_128();
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
+
diff --git a/support/graphbase/gb_econ.w b/support/graphbase/gb_econ.w
new file mode 100644
index 0000000000..42317b2a78
--- /dev/null
+++ b/support/graphbase/gb_econ.w
@@ -0,0 +1,635 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace ECON}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the |econ| subroutine,
+which creates a family of directed graphs related to the flow of money
+between industries. An example of the use of this procedure can be
+found in the demo program |econ_order|.
+
+@(gb_econ.h@>=
+extern Graph *econ();
+
+@ The subroutine call `|econ(n,omit,threshold,seed)|'
+constructs a directed graph based on the information in \.{econ.dat}.
+Each vertex of the graph corresponds to one of 81 sectors of the U.S.
+economy. The data comes from the year 1985; it was derived from
+tables published in {\sl Survey of Current Business\/ \bf70} (1990), 41--56.
+
+If |omit=threshold=0|, the directed graph is a ``circulation'';
+i.e., each arc has an associated |flow| value, and
+the sum of arc flows leaving each vertex is equal to the
+sum of arc flows entering. This sum is called the ``total commodity output''
+for the sector in question. The flow in an arc from sector $j$~to
+sector~$k$ is the amount of the commodity made by sector~$j$ that was
+used by sector~$k$, rounded to millions of dollars at producers' prices.
+For example, the total commodity output of the sector called \.{Apparel}
+is 54031, meaning that the total cost of making all kinds of apparel in
+1985 was about 54 billion dollars. There is an arc from \.{Apparel} to
+itself with a flow of 9259, meaning that 9.259 billion dollars' worth
+of apparel went from one group within the apparel industry to another;
+there is also an arc of flow~44 from \.{Apparel} to \.{Household}
+\.{furniture}, indicating that some 44 million dollars' worth of apparel
+went into the making of household furniture. By looking at all
+arcs leaving the \.{Apparel} vertex, you can see where all that
+new apparel went; by looking at all arcs that enter \.{Apparel}, you can
+see what ingredients the apparel industry needed to make~it.
+
+One vertex, called \.{Users}, represents people like you and me, the
+non-industrial end users of everything. The arc from \.{Apparel} to
+\.{Users} has flow 42172; this is the ``total final demand'' for
+apparel, the amount that didn't flow into other sectors of the economy
+before it reached people like us. The arc from \.{Users} to \.{Apparel}
+has flow 19409, which is called the ``value added'' by users; it
+represents wages and salaries paid to support the manufacturing
+process. The sum of total final demand over all sectors, which also
+equals the sum of value added over all sectors, is conventionally
+called the Gross National Product (GNP). In 1985 the GNP was 3999362,
+nearly 4 trillion dollars, according to \.{econ.dat}. (The sum of all
+arc flows coming out of all vertices was 7198680; this sum
+overestimates the total economic activity, because it counts some
+items more than once---statistics are recorded whenever an item
+passes a statistics gatherer. Economists try to adjust the data so that
+they avoid double-counting as much as possible.)
+
+Speaking of economists, there is another special vertex called
+\.{Adjustments}, included by economists so that GNP is measured
+more accurately. This vertex takes account of such things as changes in
+the value of inventories, and imported materials that cannot be obtained
+within the U.S., as well as work done for the government and for foreign
+concerns. In 1985, these adjustments accounted for about 11\% of the GNP.
+
+Incidentally, some of the ``total final demand'' arcs
+are negative. For example, the arc from \.{Petroleum} \.{and}
+\.{natural} \.{gas} \.{production} to \.{Users} has flow $-27032$.
+This may seem strange at first, but it makes sense, because crude oil
+and natural gas go more to other industries than to end users. Total
+final demand does not mean total user demand.
+
+@d flow a.i /* utility field |a| specifies the flow in an arc */
+
+@ If |omit=1|, the \.{Users} vertex is omitted from the digraph; in
+particular, this will eliminate all arcs of negative flow. If
+|omit=2|, the \.{Adjustments} vertex is also omitted, thereby leaving
+79~sectors with arcs showing inter-industry flow. (The graph is no
+longer a ``circulation,'' of course, when |omit>0|.) If \.{Users} and
+\.{Adjustments} are not omitted, \.{Users} is the last vertex of the
+graph, and \.{Adjustments} is next-to-last.
+
+If |threshold=0|, the digraph has an arc for every nonzero |flow|.
+But if |threshold>0|, the digraph becomes more sparse;
+there is then an arc from $j$ to~$k$ if and
+only if the amount of commodity $j$ used by sector~$k$ exceeds
+|threshold/65536| times the total input of sector~$k$. (The total
+input figure always includes value added, even if |omit>0|.)
+Thus, the arcs go to each sector from
+that sector's main suppliers. When |n=79|, |omit=2|, and
+|threshold=0|, the digraph has 4602 arcs out of a possible
+$79\times79=6241$; raising |threshold| to 1 decreases the number of
+arcs to 4473; raising it to 6000 leaves only~72 arcs.
+The |len| field in each arc is~1.
+
+The constructed graph will have $\min(n,81-|omit|)$ vertices. If |n| is less
+than |81-omit|, the |n| vertices will be selected by repeatedly combining
+related sectors. For example, two of the 81 original sectors are called
+`\.{Paper} \.{products,} \.{except} \.{containers}' and
+`\.{Paperboard} \.{containers} \.{and} \.{boxes}'; these might be combined
+into a sector called `\.{Paper} \.{products}'. There is a binary tree
+with 79 leaves, which describes a fixed hierarchical breakdown of the
+79 non-special sectors. This tree is
+pruned, if necessary, by replacing pairs of leaves by their parent node,
+which becomes a new leaf; pruning continues
+until just |n| leaves remain. Although pruning is a bottom-up process, its
+effect can also be obtained from the top down if we imagine ``growing''
+the tree, starting out with a whole economy as a single sector and
+repeatedly subdividing a sector into two parts. For example,
+if |omit=2| and |n=2|, the two sectors will
+be called \.{Goods} and \.{Services}. If |n=3|, \.{Goods} might be
+subdivided into \.{Natural} \.{Resources} and \.{Manufacturing}; or
+\.{Services} might be subdivided into \.{Indirect} \.{Services} and
+\.{Direct} \.{Services}.
+
+If |seed=0|, the binary tree is pruned in such a way that the |n|
+resulting sectors are as equal as possible with respect to total
+input and output, while respecting the tree structure. If |seed>0|,
+the pruning is carried out at random, in such a way that all |n|-leaf
+subtrees of the original tree are obtained with approximately equal
+probability (depending on |seed| in a machine-independent fashion).
+Any |seed| value from 1 to $2^{31}-1=2147483647$ is permissible.
+
+As usual in GraphBase routines, you can set |n=0| to get the default
+situation where |n| has its maximum value. For example, either
+|econ(0,0,0,0)| or |econ(81,0,0,0)| produces the full graph;
+|econ(0,2,0,0)| or |econ(79,2,0,0)| produces the full graph except
+for the two special vertices.
+
+@d MAX_N 81 /* maximum number of vertices in constructed graph */
+@d NORM_N MAX_N-2 /* the number of normal BEA sectors */
+@d ADJ_SEC MAX_N-1 /* code number for the \.{Adjustments} sector */
+
+@ The U.S. Bureau of Economic Analysis (BEA) has assigned code numbers
+1--79 to the individual sectors for which statistics are given in
+\.{econ.dat}. If for some reason you wish to know the BEA codes for
+all sectors represented by vertex |v| of a graph generated by |econ|,
+you can access them via a list of |Arc| nodes starting at the utility
+field |v->BEA_codes|.
+This list is linked by |next| fields in the usual way, and each
+BEA code appears in the |len| field; the |tip| field is unused.
+
+The special vertex \.{Adjustments} is given code number~80; it is
+actually a composite of six different BEA categories, numbered 80--86 in their
+published tables.
+
+For example, if |n=80| and |omit=1|, each list will have length~1;
+hence |v->BEA_codes->next| will equal |NULL| for each~|v|, and
+|v->BEA_codes->len| will be |v|'s BEA code, a number between 1 and~80.
+
+The special vertex \.{Users} has no BEA code; it is the only vertex
+whose |BEA_codes| field will be null in the graph returned by |econ|.
+
+@d BEA_codes z.a /* utility field |z| leads to the BEA codes for a vertex */
+
+@ The total output of each sector, which also equals the total input of that
+sector, is placed in utility field |sector_total| of the corresponding vertex.
+
+@d sector_total y.i /* utility field |y| holds the total flow in and out */
+
+@(gb_econ.h@>=
+#define flow @t\quad@> a.i
+ /* definitions of utility fields in the header file */
+#define BEA_codes @t\quad@> z.a
+#define sector_total @t\quad@> y.i
+
+@ If the |econ| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a nonzero number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |econ| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in
+|gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@ The \Cee\ file \.{gb\_econ.c} has the following overall shape:
+
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_flip.h"
+ /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h"
+ /* and of course we'll use the |gb_graph| data structures */
+@#
+@<Type declarations@>@;
+@<Private variables@>@;
+@#
+Graph *econ(n,omit,threshold,seed)
+ unsigned n; /* number of vertices desired */
+ unsigned omit; /* number of special vertices to omit */
+ unsigned long threshold; /* minimum per-64K-age in arcs leading in */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+ gb_init_rand(seed);
+ init_area(working_storage);
+ @<Check the parameters and adjust them for defaults@>;
+ @<Set up a graph with |n| vertices@>;
+ @<Read \.{econ.dat} and note the binary tree structure@>;
+ @<Determine the |n| sectors to use in the graph@>;
+ @<Put the appropriate arcs into the graph@>;
+ if (gb_close()!=0)
+ panic(late_data_fault);
+ /* something's wrong with |"econ.dat"|; see |io_errors| */
+ gb_free(working_storage);
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |econ| */
+register int j,k; /* all-purpose indices */
+Area working_storage; /* tables needed while |econ| does its thinking */
+
+@ @<Check the param...@>=
+if (omit>2) omit=2;
+if (n==0 || n>MAX_N-omit) n=MAX_N-omit;
+else if (n+omit<3) omit=3-n; /* we need at least one normal sector */
+if (threshold>65536) threshold=65536;
+
+@ @<Set up a graph with |n| vertices@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"econ(%u,%u,%lu,%ld)",n,omit,threshold,seed);
+strcpy(new_graph->format,"ZZZZIAIZZZZZZZ");
+
+@* The economic tree.
+As we read in the data, we construct a sequential list of nodes,
+each of which represents either a micro-sector of the economy (one of
+the basic BEA sectors) or a macro-sector (which is the union of two subnodes).
+In more technical terms, the nodes form an extended binary tree,
+whose external nodes correspond to micro-sectors and whose internal nodes
+correspond to macro-sectors. The nodes of the tree appear in preorder.
+Subsequently we will do a variety of operations on this binary tree,
+proceeding either top-down (from the beginning of the list to the end)
+or bottom-up (from the end to the beginning).
+
+Each node is a rather large record, because we will store a complete
+vector of sector output data in each node.
+
+@<Type declarations@>=
+typedef struct node_struct { /* records for micro and macro-sectors */
+ struct node_struct *rchild; /* pointer to right child of macro-sector */
+ char title[44]; /* |"Sector name"| */
+ long table[MAX_N+1]; /* outputs from this sector */
+ unsigned long total; /* total input to this sector ($=$ total output) */
+ long thresh; /* |flow| must exceed |thresh| in arcs to this sector */
+ int BEA_code; /* BEA code number; initially zero in macro-sectors */
+ int tag; /* 1 if this node will be a vertex in the graph */
+ struct node_struct *link; /* next smallest unexplored sector */
+ Arc *BEA_list; /* first item on list of BEA codes */
+} node;
+
+@ When we read the given data in preorder, we'll need a stack to remember
+what nodes still need to have their |rchild| pointer filled in.
+(There is a no need for an |lchild| pointer, because the left child
+always follows its parent immediately in preorder.)
+
+@<Private v...@>=
+static node *stack[NORM_N+NORM_N];
+static node **stack_ptr; /* current position in |stack| */
+static node *node_block; /* array of nodes, specifies the tree in preorder */
+static node *node_index[MAX_N+1]; /* which node has a given BEA code */
+
+@ @<Local v...@>=
+register node *p,*pl,*pr; /* current node and its children */
+register node *q,*r; /* registers for list manipulation */
+
+@ @<Read \.{econ.dat} and note the binary tree structure@>=
+node_block=gb_alloc_type(2*MAX_N-3,@[node@],working_storage);
+if (gb_alloc_trouble) panic(no_room+1); /* no room to copy the data */
+if (gb_open("econ.dat")!=0)
+ panic(early_data_fault);
+ /* couldn't open |"econ.dat"| using GraphBase conventions */
+@<Read and store the sector names and BEA numbers@>;
+for (k=1; k<=MAX_N; k++)
+ @<Read and store the output coefficients for sector |k|@>;
+
+@ The first part of \.{econ.dat} specifies the nodes of the binary
+tree in preorder. Each line contains a node name
+followed by a colon, and the colon is followed by the BEA number if
+that node is a leaf.
+
+The tree is uniquely specified in this way,
+because of the nature of preorder. (Think of Polish prefix notation,
+in which a formula like `${+}x{+}xx$' means `${+}(x,{+}(x,x))$'; the
+parentheses in Polish notation are redundant.)
+
+The two special sector names don't appear in the file; we manufacture
+them ourselves.
+
+The program here is careful not to clobber itself in the
+presence of arbitrarily garbled data.
+
+@<Read and store the sector names...@>=
+stack_ptr=stack;
+for (p=node_block; p<node_block+NORM_N+NORM_N-1; p++) {@+register int c;
+ gb_string(p->title,':');
+ if (strlen(p->title)>43) panic(syntax_error); /* sector name too long */
+ if (gb_char()!=':') panic(syntax_error+1); /* missing colon */
+ p->BEA_code=c=gb_number(10);
+ if (c==0) /* macro-sector */
+ *stack_ptr++=p; /* left child is |p+1|, we'll know |rchild| later */
+ else { /* micro-sector; |p+1| will be somebody's right child */
+ node_index[c]=p;
+ if (stack_ptr>stack) (*--stack_ptr)->rchild=p+1;
+ }
+ if (gb_char()!='\n') panic(syntax_error+2); /* garbage on the line */
+ gb_newline();
+}
+if (stack_ptr!=stack) panic(syntax_error+3); /* tree malformed */
+for (k=NORM_N;k;k--) if (node_index[k]==0)
+ panic(syntax_error+4); /* BEA code not mentioned in the tree */
+strcpy(p->title,"Adjustments");@+p->BEA_code=ADJ_SEC;@+node_index[ADJ_SEC]=p;
+strcpy((p+1)->title,"Users");@+node_index[MAX_N]=p+1;
+
+@ The remaining part of \.{econ.dat} is an $81\times80$ matrix in which
+the $k$th row contains the outputs of sector~$k$ to all sectors except
+\.{Users}. Each row consists of
+a blank line followed by 8 lines of 10 numbers each, separated by commas;
+zero entries are represented by |""| instead of by |"0"|. For example,
+the line
+$$\hbox{\tt 8490,2182,42,467,,,,,,}$$
+follows the initial blank line; it means that sector~1 output 8490 million
+dollars to itself, \$2182M to sector~2, \dots, \$0M to sector~10.
+
+@<Read and store the output...@>=
+{@+register int s=0; /* row sum */
+ register int x; /* entry read from \.{econ.dat} */
+ if (gb_char()!='\n') panic(syntax_error+5);
+ /* blank line missing between rows */
+ gb_newline();
+ p=node_index[k];
+ for (j=1;j<MAX_N;j++) {
+ p->table[j]=x=gb_number(10);@+s+=x;
+ node_index[j]->total+=x;
+ if ((j%10)==0) {
+ if (gb_char()!='\n') panic(syntax_error+6);
+ /* out of synch in input file */
+ gb_newline();
+ } else if (gb_char()!=',') panic(syntax_error+7);
+ /* missing comma after entry */
+ }
+ p->table[MAX_N]=s; /* sum of |table[1]| through |table[80]| */
+}
+
+@* Growing a subtree.
+Once all the data appears in |node_block|, we want to extract from it and
+combine~it as specified by parameters |n|, |omit|, and |seed|. This may mean
+pruning the tree; or, rather, growing a subtree of the full economic tree.
+
+@<Determine the |n| sectors to use in the graph@>=
+{@+int l=n+omit-2; /* the number of leaves in the desired subtree */
+ if (l==NORM_N) @<Choose all sectors@>@;
+ else if (seed) @<Grow a random subtree with |l| leaves@>@;
+ else @<Grow a subtree with |l| leaves by subdividing largest sectors first@>;
+}
+
+@ The chosen leaves of our subtree will be identified by having their
+|tag| field set to~1.
+
+@<Choose all sectors@>=
+for (k=NORM_N;k;k--) node_index[k]->tag=1;
+
+@ To grow the |l|-leaf subtree when |seed=0|, we first pass over the
+tree bottom-up to compute the total input (and output) of each macro-sector;
+then we proceed from the top down to subdivide sectors in decreasing
+order of their total input. This provides a good introduction to the
+bottom-up and top-down tree methods we will be using in several other
+parts of the program.
+
+The |special| node is used here for two purposes: It is the head of a
+linked list of unexplored nodes, sorted by decreasing order of
+their |total| fields; and it appears at the end of that list, because
+|special->total=0|.
+
+@<Grow a subtree with |l| leaves by subdividing largest sectors first@>=
+{@+register node *special=node_index[MAX_N];
+ /* the \.{Users} node at the end of |node_block| */
+ for (p=node_index[ADJ_SEC]-1;p>=node_block;p--) /* bottom up */
+ if (p->rchild)
+ p->total=(p+1)->total+p->rchild->total;
+ special->link=node_block;@+node_block->link=special; /* start at the root */
+ k=1; /* |k| is the number of nodes we have tagged or put onto the list */
+ while (k<l) @<If the first node on the list is a leaf, delete it and tag it;
+ otherwise replace it by its two children@>;
+ for (p=special->link;p!=special;p=p->link)
+ p->tag=1; /* tag everything on the list */
+}
+
+@ @<If the first node on the list is a leaf,...@>=
+{
+ p=special->link; /* remove |p|, the node with greatest |total| */
+ special->link=p->link;
+ if (p->rchild==0) p->tag=1; /* |p| is a leaf */
+ else {
+ pl=p+1;@+pr=p->rchild;
+ for (q=special;q->link->total>pl->total;q=q->link) ;
+ pl->link=q->link;@+q->link=pl; /* insert left child in proper place */
+ for (q=special;q->link->total>pr->total;q=q->link) ;
+ pr->link=q->link;@+q->link=pr; /* insert right child in proper place */
+ k++;
+ }
+}
+
+@ We can obtain a uniformly distributed |l|-leaf subtree of a given tree
+by choosing the root when |l=1| or by using the following idea when |l>1|:
+Suppose the given tree~$T$ has subtrees $T_0$ and $T_1$. Then it has
+$T(l)$ subtrees with |l|~leaves, where $T(l)=\sum_k T_0(k)T_1(l-k)$.
+We choose a random number $r$ between 0 and $T(l)-1$, and we find the
+smallest $m$ such that $\sum_{k\le m}T_0(k)T_1(l-k)>r$. Then we
+proceed recursively to
+compute a random $m$-leaf subtree of~$T_0$ and a random $(l-m)$-leaf
+subtree of~$T_1$.
+
+A difficulty arises when $T(l)$ is $2^{31}$ or more. But then we can replace
+$T_0(k)$ and $T_1(l-k)$ in the formulas above by $\lceil T_0(k)/d_0\rceil$
+and $\lceil T_1(k)/d_1\rceil$, respectively, where $d_0$ and $d_1$ are
+arbitrary constants; this yields smaller values
+$T(l)$ that define approximately the same distribution of~$k$.
+
+The program here computes the $T(l)$ values bottom-up, then grows a
+random tree top-down. If node~|p| is not a leaf, its |table[0]| field
+will be set to the number of leaves below it; and its |table[l]| field
+will be set to $T(l)$, for |1<=l<=table[0]|.
+
+The data in |econ.dat| is sufficiently simple that most of the $T(l)$
+values are less than $2^{31}$. We need to scale them
+down to avoid overflow only at the root node of the tree; this
+case is handled separately.
+
+We will set the |tag| field of a node equal to the number of leaves to be
+grown in the subtree rooted at that node. This convention is consistent
+with our previous stipulation that |tag=1| should characterize the
+nodes that are chosen to be vertices.
+
+@<Grow a random subtree with |l| leaves@>=
+{
+ node_block->tag=l;
+ for (p=node_index[ADJ_SEC]-1;p>node_block;p--) /* bottom up, except root */
+ if (p->rchild) @<Compute the $T(l)$ values for subtree |p|@>;
+ for (p=node_block;p<node_index[ADJ_SEC];p++) /* top down, from root */
+ if (p->tag>1) {
+ l=p->tag;
+ pl=p+1;@+pr=p->rchild;
+ if (pl->rchild==NULL) {
+ pl->tag=1;@+pr->tag=l-1;
+ } else if (pr->rchild==NULL) {
+ pl->tag=l-1;@+pr->tag=1;
+ } else @<Stochastically determine the number of leaves to grow in
+ each of |p|'s children@>;
+ }
+}
+
+@ Here we are essentially multiplying two generating functions.
+Suppose $f(z)=\sum_l T(l)z^l$; then we are computing $f_p(z)=
+z+f_{pl}(z)f_{pr}(z)$.
+
+@<Compute the $T(l)$ values for subtree |p|@>=
+{
+ pl=p+1;@+pr=p->rchild;
+ p->table[1]=p->table[2]=1; /* $T(1)$ and $T(2)$ are always 1 */
+ if (pl->rchild==0) { /* left child is a leaf */
+ if (pr->rchild==0) p->table[0]=2; /* and so is the right child */
+ else { /* no, it isn't */
+ for (k=2;k<=pr->table[0];k++) p->table[1+k]=pr->table[k];
+ p->table[0]=pr->table[0]+1;
+ }
+ } else if (pr->rchild==0) { /* right child is a leaf */
+ for (k=2;k<=pl->table[0];k++) p->table[1+k]=pl->table[k];
+ p->table[0]=pl->table[0]+1;
+ } else { /* neither child is a leaf */
+ @<Set |p->table[2]|, |p->table[3]|, \dots\ to convolution of
+ |pl| and |pr| table entries@>;
+ p->table[0]=pl->table[0]+pr->table[0];
+ }
+}
+
+@ @<Set |p->table[2]|, |p->table[3]|, \dots\ to convolution...@>=
+p->table[2]=0;
+for (j=pl->table[0];j;j--) {@+register long t=pl->table[j];
+ for (k=pr->table[0];k;k--)
+ p->table[j+k]+=t*pr->table[k];
+}
+
+@ @<Stochastically determine the number of leaves to grow...@>=
+{@+register long s,r;
+ j=0; /* we will set |j=1| if scaling is necessary at the root */
+ if (p==node_block) {
+ s=0;
+ if (l>29 && l<67) {
+ j=1; /* more than $2^{31}$ possibilities exist */
+ for (k=(l>pr->table[0]? l-pr->table[0]: 1);k<=pl->table[0] && k<l;k++)
+ s+=((pl->table[k]+0x3ff)>>10)*pr->table[l-k];
+ /* scale with $d_0=1024$, $d_1=1$ */
+ } else
+ for (k=(l>pr->table[0]? l-pr->table[0]: 1);k<=pl->table[0] && k<l;k++)
+ s+=pl->table[k]*pr->table[l-k];
+ } else s=p->table[l];
+ r=gb_unif_rand(s);
+ if (j)
+ for (s=0,k=(l>pr->table[0]? l-pr->table[0]: 1);s<=r;k++)
+ s+=((pl->table[k]+0x3ff)>>10)*pr->table[l-k];
+ else for (s=0,k=(l>pr->table[0]? l-pr->table[0]: 1);s<=r;k++)
+ s+=pl->table[k]*pr->table[l-k];
+ pl->tag=k-1;@+pr->tag=l-k+1;
+}
+
+@* Arcs.
+In the general case, we have to combine some of the basic micro-sectors
+into macro-sectors by adding together the appropriate input/output
+coefficients. This is a bottom-up pruning process.
+
+Suppose |p| is being formed as the union of |pl| and~|pr|.
+Then the arcs leading out of |p| are obtaining by summing the numbers
+on arcs leading out of |pl| and~|pr|; the arcs leading into |p| are
+obtained by summing the numbers on arcs leading into |pl| and~|pr|;
+the arcs from |p| to itself are obtained by summing the four numbers
+on arcs leading from |pl| or~|pr| to |pl| or~|pr|.
+
+We maintain the |node_index| table so that its non-|NULL| entries
+contain all the currently active nodes. When |pl| and~|pr| are
+being pruned in favor of~|p|, node |p|~inherits |pl|'s place in
+|node_index|; |pr|'s former place becomes~|NULL|.
+
+@<Put the appropriate arcs into the graph@>=
+@<Prune the sectors that are used in macro-sectors, and form
+ the lists of BEA sector codes@>;
+@<Make the special nodes invisible if they are omitted, visible otherwise@>;
+@<Compute individual thresholds for each chosen sector@>;
+{@+register Vertex *v=new_graph->vertices+n;
+ for (k=MAX_N;k;k--)
+ if ((p=node_index[k])!=NULL) {
+ vert_index[k]=--v;
+ v->name=gb_save_string(p->title);
+ v->BEA_codes=p->BEA_list;
+ v->sector_total=p->total;
+ }
+ if (v!=new_graph->vertices)
+ panic(impossible); /* bug in algorithm; this can't happen */
+ for (j=MAX_N;j;j--)
+ if ((p=node_index[j])!=NULL) {@+register Vertex *u=vert_index[j];
+ for (k=MAX_N;k;k--)
+ if ((v=vert_index[k])!=NULL)
+ if (p->table[k]!=0 && p->table[k]>node_index[k]->thresh) {
+ gb_new_arc(u,v,1);
+ u->arcs->flow=p->table[k];
+ }
+ }
+}
+
+@ @<Private v...@>=
+static Vertex *vert_index[MAX_N+1]; /* the vertex assigned to a BEA code */
+
+@ The theory underlying this step is the following, for integers
+$a,b,c,d$ with $b,d>0$:
+$$ {a\over b}>{c\over d} \qquad\iff\qquad
+ a>\biggl\lfloor{b\over d}\biggr\rfloor\,c +
+ \biggl\lfloor{(b\bmod d)c\over d}\biggr\rfloor\,.$$
+In our case, |b=p->total| and $c=threshold\le d=65536=2^{16}$, hence
+the multiplications cannot overflow. (But they can come awfully darn close.)
+
+@<Compute individual thresholds for each chosen sector@>=
+for (k=MAX_N;k;k--)
+ if ((p=node_index[k])!=NULL) {
+ if (threshold==0) p->thresh=-99999999;
+ else p->thresh=((p->total>>16)*threshold)+
+ (((p->total&0xffff)*threshold)>>16);
+ }
+
+@ @<Prune the sectors that are used in macro-sectors, and form
+ the lists of BEA sector codes@>=
+for (p=node_index[ADJ_SEC];p>=node_block;p--) { /* bottom up */
+ if (p->BEA_code) { /* original leaf */
+ p->BEA_list=gb_virgin_arc();
+ p->BEA_list->len=p->BEA_code;
+ } else {
+ pl=p+1;@+pr=p->rchild;
+ if (p->tag==0) p->tag=pl->tag+pr->tag;
+ if (p->tag<=1) @<Replace |pl| and |pr| by their union, |p|@>;
+ }
+}
+
+@ @<Replace |pl| and |pr| by their union, |p|@>=
+{@+register Arc *a=pl->BEA_list;
+ register int jj=pl->BEA_code, kk=pr->BEA_code;
+ p->BEA_list=a;
+ while (a->next) a=a->next;
+ a->next=pr->BEA_list;
+ for (k=MAX_N;k;k--)
+ if ((q=node_index[k])!=NULL) {
+ if (q!=pl && q!=pr) q->table[jj]+=q->table[kk];
+ p->table[k]=pl->table[k]+pr->table[k];
+ }
+ p->total=pl->total+pr->total;
+ p->BEA_code=jj;
+ p->table[jj]+=p->table[kk];
+ node_index[jj]=p;
+ node_index[kk]=NULL;
+}
+
+@ If the \.{Users} vertex is not omitted, we need to compute each
+sector's total final demand, which is calculated so that the row sums
+and column sums of the input/output coefficients come out equal. We've
+already computed the column sum, |p->total|; we've also computed
+|p->table[1]+@t\hbox{$\cdots$}@>+p->table[ADJ_SEC]|, and put it into
+|p->table[MAX_N]|. So now we want to replace |p->table[MAX_N]| by
+|p->total-p->table[MAX_N]|. As remarked earlier, this quantity might
+be negative.
+
+In the special node |p| for the \.{Users} vertex, the preliminary
+processing has made |p->total=0|; moreover, |p->table[MAX_N]| is the
+sum of value added, or GNP. We want to switch those fields.
+
+We don't have to set the |tag| fields to 1 in the special nodes, because
+the remaining parts of the arc-generation algorithm don't look at those fields.
+
+@<Make the special nodes invisible if they are omitted, visible otherwise@>=
+if (omit==2) node_index[ADJ_SEC]=node_index[MAX_N]=NULL;
+else if (omit==1) node_index[MAX_N]=NULL;
+else {
+ for (k=ADJ_SEC;k;k--)
+ if ((p=node_index[k])!=NULL) p->table[MAX_N]=p->total-p->table[MAX_N];
+ p=node_index[MAX_N]; /* the special node */
+ p->total=p->table[MAX_N];
+ p->table[MAX_N]=0;
+}
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_econ} are defined and used.
diff --git a/support/graphbase/gb_flip.w b/support/graphbase/gb_flip.w
new file mode 100644
index 0000000000..c24528f189
--- /dev/null
+++ b/support/graphbase/gb_flip.w
@@ -0,0 +1,254 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace FLIP}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+@* Introduction. This is |gb_flip|, the module used by GraphBase
+programs to generate random numbers.
+
+To use the routines in this file, first call the function |gb_init_rand(seed)|.
+Subsequent uses of the macro |gb_next_rand()| will then return pseudo-random
+integers between 0 and $2^{31}-1$, inclusive.
+
+GraphBase programs are designed to produce identical results on almost
+all existing computers and operating systems. An improved version of the
+portable subtractive method recommended in {\sl Seminumerical Algorithms},
+Section~3.6, is used to generate random numbers in the routines below.
+The period length of the generated numbers is at least $2^{55}-1$, and
+it is in fact plausibly conjectured to be $2^{85}-2^{30}$ for all but
+at most one choice of the |seed| value. The low-order bits of the
+generated numbers are just as random as the high-order bits.
+
+@ Changes might be needed when these routines are ported to different
+systems, because the programs have been written to be most efficient
+on binary computers that use two's complement notation. Almost all
+modern computers are based on two's complement arithmetic, but if you have a
+nonconformist machine you may have to revise the code in sections that
+are listed under `system dependencies' in the index.
+
+A validation program is provided so that installers can tell if |gb_flip|
+is working properly. To make the test, simply run |test_flip|.
+
+@(test_flip.c@>=
+#include <stdio.h>
+#include "gb_flip.h" /* all users of |gb_flip| should do this */
+main()
+{@+int j;
+ gb_init_rand(-314159);
+ if (gb_next_rand()!=119318998) {
+ fprintf(stderr,"Failure on the first try!\n"); return -1;
+ }
+ for (j=1; j<=133; j++)
+ gb_next_rand();
+ if (gb_unif_rand(0x55555555)!=748103812) {
+ fprintf(stderr,"Failure on the second try!\n"); return -2;
+ }
+ fprintf(stderr,"OK, the gb_flip routines seem to work!\n");
+}
+
+@ The \Cee\ code for |gb_flip| doesn't have a main routine; it's just a
+bunch of subroutines to be incorporated into programs at a higher level,
+via the system loading routine. Here is the general outline of \.{gb\_flip.c}:
+
+@p
+@<Private declarations@>@;
+@<External declarations@>@;
+@<External functions@>
+
+@* The subtractive method. If $m$ is any even number, and if the
+numbers $a_0$, $a_1$, \dots,~$a_{54}$ are not all even, then the numbers
+generated by the recurrence
+$$ a_n=(a_{n-24}-a_{n-55})\bmod m $$
+have a period length of at least $2^{55}-1$, because the residues
+$a_n\bmod2$ have a period of this length. Furthermore, the numbers 24 and~55
+in this recurrence are sufficiently large that deficiencies in randomness
+due to the simplicity of the recurrence are negligible in most applications.
+
+Here we take $m=2^{31}$ so as to get the full set of nonnegative numbers
+on a 32-bit computer. The recurrence is computed by maintaining an array
+of 55 values, $A[1]\ldots A[55]$. We also set |A[0]=-1| to act as a sentinel.
+
+@<Private...@>=
+static long A[56] = {-1}; /* pseudo-random values */
+
+@ Every external variable should be declared twice in this \.{CWEB} file:
+once for |gb_flip| itself (the ``real'' declaration for storage allocation
+purposes), and once in \.{gb\_flip.h} (for cross-references by |gb_flip|
+users).
+
+The pointer variable |gb_flip_ptr| should not actually be mentioned explicitly
+by user routines; it is made public only for efficiency, so that the
+|gb_next_rand| macro can access the private |A| table.
+
+@<External declarations@>=
+long *gb_flip_ptr=A; /* the next |A| value to be exported */
+
+@ Incidentally, we hope that optimizing compilers are smart enough to
+do the right thing with |gb_next_rand|.
+
+@d gb_next_rand() (*gb_flip_ptr>=0? *gb_flip_ptr--: gb_flip_cycle())
+
+@(gb_flip.h@>=
+#define gb_next_rand()@t\quad@>(*gb_flip_ptr>=0?*gb_flip_ptr--:gb_flip_cycle())
+extern long *gb_flip_ptr; /* the next |A| value to be used */
+extern long gb_flip_cycle(); /* compute 55 more pseudo-random numbers */
+
+@ The user is not supposed to call |gb_flip_cycle| directly either.
+It is a routine invoked by the macro |gb_next_rand()| when |gb_flip_ptr|
+points to the negative value in |A[0]|.
+
+The purpose of |gb_flip_cycle| is to do 55 more steps of the basic
+recurrence, at high speed, and to reset |gb_flip_ptr|.
+
+The nonnegative remainder of $(x-y)\bmod 2^{31}$ is computed here by
+doing a logical-and with the constant |0x7fffffff|. On computers without
+two's complement arithmetic it may be more efficient to add the
+value $2^{30}$ twice to $(x-y)$, if $(x-y)$ turns out to be negative.
+Careful calculations are essential to preserve system-independence of
+the GraphBase results.
+@^system dependencies@>
+
+The sequence of random numbers returned by successive calls of |gb_next_rand()|
+isn't really $a_n$, $a_{n+1}$, \dots, as defined by the basic recurrence above;
+blocks of 55 consecutive values are essentially being ``flipped'' or
+``reflected,'' i.e., output in reverse order, because |gb_next_rand()|
+makes the value of |gb_flip_ptr| decrease instead of increase.
+But such flips don't make the results any less random.
+
+@<External functions@>=
+long gb_flip_cycle()
+{@+register long *ii, *jj;
+ for (ii=&A[1],jj=&A[32];jj<=&A[55];ii++,jj++)
+ *ii=(*ii-*jj)&0x7fffffff;
+ for (jj=&A[1];ii<=&A[55];ii++,jj++)
+ *ii=(*ii-*jj)&0x7fffffff;
+ gb_flip_ptr=&A[54];
+ return A[55];
+}
+
+@* Initialization. To get everything going, we use a scheme like that
+recommended in {\sl Seminumerical Algorithms}, but revised so that the
+least significant bits of the starting values depend on the entire
+seed, not just on the seed's least significant bits.
+
+Notice that we jump around in the array by increments of 21, a number that is
+relatively prime to~55. Repeated skipping by steps of 21~mod~55 keeps the
+values we're computing spread out as far from each other as possible in the
+array, since 21, 34, and 55 are consecutive
+Fibonacci numbers (see the discussion of Fibonacci hashing in
+Section 6.4 of {\sl Sorting and Searching\/}). Our initialization mechanism
+would be rather poor if we didn't do something like that to disperse the values
+(see {\sl Seminumerical Algorithms}, exercise 3.2.2--2).
+
+@<External f...@>=
+void gb_init_rand(seed)
+ long seed;
+{@+register int i;
+ register long prev=seed, next=1;
+ seed=prev=prev & 0x7fffffff; /* strip off the sign */
+ A[55]=prev;
+ for (i=21; i; i=(i+21)%55) {
+ A[i]=next;
+ @<Compute a new |next| value, based on |next|, |prev|, and |seed|@>;
+ prev=A[i];
+ }
+ @<Get the array values ``warmed up''@>;
+}
+
+@ Here we have two more instances of $(x-y)\bmod 2^{31}$ that should
+be computed in some other way on atypical machines.
+@^system dependencies@>
+
+Incidentally, if |test_flip| fails, the person debugging these routines will
+want to know some of the intermediate numbers computed during initialization.
+The first nontrivial values calculated by |gb_init_rand| are
+|A[42]=2147326568|; |A[8]=1073977445|; |A[29]=536517481|.
+Once you get these right, the rest should be easy.
+
+An early version of this routine simply said `|seed>>1|' instead of making
+|seed| shift cyclically. This method had an interesting flaw:
+When the original |seed| was a number of the form $4s+1$, the first
+54 elements $A[1]$, \dots,~$A[54]$ were set to exactly the same values
+as when |seed| was $4s+2$. Therefore one out of every four seed values
+was effectively being wasted.
+
+@<Compute a new |next|...@>=
+next=(prev-next) & 0x7fffffff;
+if (seed&1) seed=0x40000000+(seed>>1);
+else seed>>=1; /* cyclic shift right 1 */
+next=(next-seed) & 0x7fffffff;
+
+@ After the first 55 values have been computed as a function of |seed|,
+they aren't random enough for us to start using them right away. For example,
+we have set |A[21]=1|, in order to ensure that at least one starting value
+is an odd number. But once the sequence $a_n$ gets going far enough from
+its roots, the initial transients become imperceptible. Therefore we will call
+|gb_flip_cycle| five times, effectively skipping past the first 275
+elements of the sequence; this has the desired effect, and it also
+initializes |gb_flip_ptr|.
+
+Note: It is possible to express the least significant bit of the
+generated numbers as a linear combination mod~2 of the 31 bits of
+|seed| and of the constant~1. For example, the first generated number
+turns out to be odd if and only if
+$$s_{24}+s_{23}+s_{22}+s_{21}+s_{19}+s_{18}+s_{15}+s_{14}+s_{13}+s_{11}+
+s_{10}+s_{8}+s_{7}+s_{6}+s_{2}+s_{1}+s_{0}$$ is odd, when
+$|seed|=(s_{31}\ldots s_1s_0)_2$. We can represent this linear
+combination conveniently by the hexadecimal number |0x01ecedc7|; the
+\.1 stands for $s_{24}$ and the final \.7 stands for $s_2+s_1+s_0$.
+The first ten least-significant bits turn out to be respectively
+|0x01ecedc7|, |0xdbbdc362|, |0x400e0b06|, |0x0eb73780|, |0xda0d66ae|,
+|0x002b63bc|, |0xadb801ed|, |0x8077bbbc|, |0x803d9db5|, and
+|0x401a0eda| in this notation (using the sign bit to indicate cases
+when 1 must be added to the sum).
+
+We must admit that these ten 32-bit patterns do not look at all
+random; the number of \.b's, \.d's, and \.0's is unusually high. (Before
+the ``warmup cycles,'' the patterns are even more regular.) This
+phenomenon eventually disappears, however, as the sequence proceeds;
+and it does not seem to imply any serious deficiency in practice, even
+at the beginning of the sequence, once we've done the warmup exercises.
+
+@<Get the array...@>=
+(void) gb_flip_cycle();
+(void) gb_flip_cycle();
+(void) gb_flip_cycle();
+(void) gb_flip_cycle();
+(void) gb_flip_cycle();
+
+@ @(gb_flip.h@>=
+extern void gb_init_rand();
+
+@* Uniform integers.
+Here is a simple routine that produces a uniform integer between
+0 and~$m-1$, inclusive, when $m$ is any positive integer less than $2^{31}$.
+It avoids the bias toward small values that would occur if we simply
+calculated |gb_next_rand()%m|. (The bias is insignificant when |m| is
+small, but it can be serious when |m| is large. For example, if
+$m\approx 2^{32}/3$, the simple remainder algorithm would give an answer
+less than $m/2$ about 2/3 of the time.)
+
+This routine consumes fewer than two random numbers, on the average,
+for any fixed~$m$.
+
+In the |test_flip| program this routine should compute |t=m|,
+then it should reject the values |r=2081307921|, 1621414801, and
+1469108743 before returning the answer 748103812.
+
+@d two_to_the_31 ((unsigned long)0x80000000)
+
+@<External f...@>=
+long gb_unif_rand(m)
+ long m;
+{@+register unsigned long t=two_to_the_31-(two_to_the_31 % m);
+ register long r;
+ do {
+ r=gb_next_rand();
+ } while (t<=(unsigned long)r);
+ return r%m;
+}
+
+@ @(gb_flip.h@>=
+extern long gb_unif_rand();
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_games.w b/support/graphbase/gb_games.w
new file mode 100644
index 0000000000..fbb816b2d6
--- /dev/null
+++ b/support/graphbase/gb_games.w
@@ -0,0 +1,477 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace GAMES}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the |games| subroutine,
+which creates a family of undirected graphs based on college football
+scores. An example of the use of this procedure can be
+found in the demo program |football|.
+
+@(gb_games.h@>=
+extern Graph *games();
+
+@ The subroutine call `|games|(|n|, |ap0_weight|, |upi0_weight|, |ap1_weight|,
+|upi1_weight|, |first_day|, |last_day|, |seed|)'
+constructs a graph based on the information in \.{games.dat}.
+Each vertex of the graph corresponds to one of 120 football teams
+at American colleges and universities (more precisely, to the 106 college
+football teams of division I-A together with the 14 division I-AA teams
+of the Ivy League and the Patriot League).
+Each edge of the graph corresponds to one of the 638 games played
+between those teams during the 1990 season.
+
+An arc from vertex~|u| to vertex~|v| is assigned a length representing
+the number of points scored by |u| when playing~|v|. Thus, the graph
+isn't really ``undirected,'' although it is true that its arcs are
+paired (i.e., that |u| played~|v| if and only if |v| played~|u|).
+A truly undirected graph with the same vertices and edges can be obtained
+by applying the |copy| routine of |gb_basic|.
+
+The constructed graph will have $\min(n,120)$ vertices. If |n| is less
+than 120, the |n| teams will be selected by assigning a weight to
+each team and choosing the |n| with largest weight, using random
+numbers to break ties in case of equal weights. Weights are computed
+by the formula
+$$ |ap0_weight|\cdot|ap0|+|upi0_weight|\cdot|upi0|
+ +|ap1_weight|\cdot|ap1|+|upi1_weight|\cdot|upi1|, $$
+where |ap0| and |upi0| are the point scores given to a team in the
+Associated Press and United Press International polls at the beginning
+of the season, and |ap1| and |upi1| are the similar scores given at
+the end of the season. (The \\{ap} scores were obtained by asking 60
+sportswriters to choose and rank the top 25 teams, assigning 25 points
+to a team ranked 1st and 1 point to a team ranked 25th; thus, the
+total of each of the \\{ap} scores is 19500. The \\{upi} scores were
+obtained by asking football coaches to choose and rank the top 15
+teams, assigning 15 points to a team ranked 1st and 1 point to a team
+ranked 15th. In the case of \\{upi0}, there were 48 coaches voting,
+making 5760 points altogether; but in the case of \\{upi1}, 59 coaches
+were polled, yielding a total of 7080 points. The coaches agreed not
+to vote for any team that was on probation for violating NCAA rules,
+but the sportswriters had no such policy.)
+
+Parameters |first_day| and |last_day| can be used to vary the number of
+edges; only games played between |first_day| and |last_day|, inclusive,
+will be included in the constructed graph. Day~0 was August~26, 1990,
+when Colorado and Tennessee competed in the Disneyland Pigskin Classic.
+Day~128 was January~1, 1991, when the final end-of-season Bowl games
+were played. About half of each team's games were played between day~0 and
+day~50. If |last_day=0|, it is automatically increased to~128.
+
+As usual in GraphBase routines, you can set |n=0| to get the default
+situation where |n| has its maximum value. For example, either
+|games(0,0,0,0,0,0,0,0)| or |games(120,0,0,0,0,0,0,0)| produces the full graph;
+|games(0,0,0,0,0,50,0,0)| or |games(120,0,0,0,0,50,0,0)|
+or |games(120,0,0,0,0,50,128,0)| produces the graph for the last half
+of the season. One way to select a subgraph containing the
+30 ``best'' teams is to ask for |games(30,0,0,1,2,0,0,0)|, which adds
+the votes of the sportswriters to the votes of the coaches
+(considering that a coach's first choice is worth 30 points
+while a sportswriter's first choice is worth only 25). It turns out
+that 67 of the teams did not receive votes in any of the four polls;
+the subroutine call |games(53,1,1,1,1,0,0,0)| will pick out the 53 teams
+that were selected at least once by some sportswriter or coach, and
+|games(67,-1,-1,-1,-1,0,0,0)| will pick out the 67 that were not.
+A~random selection of 60 teams can be obtained by calling
+|games(60,0,0,0,0,0,0,s)|. Different choices of the seed number~|s|
+will produce different selections in a system-independent manner;
+any value of |s| between 0 and $2^{31}-1$ is permissible.
+If you ask for |games(120,0,0,0,0,0,0,s)| with different choices of~|s|,
+you always get the full graph, but the vertices will appear in different
+(random) orderings depending on~|s|.
+
+Parameters |ap0_weight|, |upi0_weight|, |ap1_weight|, and |upi1_weight| must be
+at most $2^{17}=131072$ in absolute value.
+
+@d MAX_N 120
+@d MAX_DAY 128
+@d MAX_WEIGHT 131072
+@d ap0 u.i /* Associated Press score before the season */
+@d upi0 v.i /* United Press International score before the season */
+@d ap1 w.i /* Associated Press score after the season */
+@d upi1 x.i /* United Press International score after the season */
+
+@ Most of the teams belong to a ``conference,'' and they play against
+almost every other team that belongs to the same conference. For
+example, Stanford and nine other teams belong to the
+Pacific Ten conference. Eight of Stanford's eleven games were against
+other teams of the Pacific Ten; the other three were played against
+Colorado (from the Big Eight), San Jose State (from the Big West)
+and Notre Dame (which is independent). The graphs produced by |games|
+therefore illustrate ``cliquey'' patterns of social interaction.
+
+Eleven different conferences are included in \.{games.dat}. Utility
+field |z.s| of a vertex is the name of a team's conference, or |NULL|
+if that team is independent. (Exactly 24 of the I-A football teams
+were independent in 1990.) Two teams |u| and |v| belong to the same
+conference if and only if |u->conference==v->conference| and
+|u->conference!=NULL|.
+
+@d conference z.s
+
+@ Each team has a nickname, which is recorded in utility field |y.s|.
+For example, Georgia Tech's team is called the Yellow Jackets.
+Six teams (Auburn, Clemson, Memphis State, Missouri, Pacific, and
+Princeton) are called the Tigers, and five teams
+(Fresno State, Georgia, Louisiana Tech, Mississippi State,
+Yale) are called the Bulldogs. But most of the teams have a unique
+nickname, and 94 distinct nicknames exist.
+
+@d nickname y.s
+
+@ If |a| points to an arc from |u| to |v|, utility field |a->a.i| contains
+the value 3 if |u| was the home team, 1 if |v| was the home team, and 2 if both
+teams played on neutral territory. The date of that game, represented
+as a integer number of days after August~26, 1990, appears in utility
+field |a->b.i|. The arcs in each vertex list |v->arcs| appear in reverse order
+of their dates: last game first and first game last.
+
+@d HOME 1
+@d NEUTRAL 2 /* this value is halfway between |HOME| and |AWAY| */
+@d AWAY 3
+@d venue a.i
+@d date b.i
+
+@(gb_games.h@>=
+#define ap0 @[u.i@] /* repeat the definitions in the header file */
+#define upi0 @[v.i@]
+#define ap1 @[w.i@]
+#define upi1 @[x.i@]
+#define nickname @[y.s@]
+#define conference @[z.s@]
+#define HOME 1
+#define NEUTRAL 2
+#define AWAY 3
+#define venue @[a.i@]
+#define date @[b.i@]
+
+@ If the |games| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |games| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in |gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@ The \Cee\ file \.{gb\_games.c} has the following overall shape:
+
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_flip.h"
+ /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+#include "gb_sort.h" /* and |gb_linksort| for sorting */
+@#
+@<Type declarations@>@;
+@<Private variables@>@;
+@<Private functions@>@;
+@#
+Graph *games(n,ap0_weight,upi0_weight,ap1_weight,upi1_weight,
+ first_day,last_day,seed)
+ unsigned n; /* number of vertices desired */
+ long ap0_weight; /* coefficient of |ap0| in the weight function */
+ long ap1_weight; /* coefficient of |ap1| in the weight function */
+ long upi0_weight; /* coefficient of |upi0| in the weight function */
+ long upi1_weight; /* coefficient of |upi1| in the weight function */
+ int first_day; /* lower cutoff for games to be considered */
+ int last_day; /* upper cutoff for games to be considered */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+ gb_init_rand(seed);
+ @<Check that the parameters are valid@>;
+ @<Set up a graph with |n| vertices@>;
+ @<Read the first part of \.{games.dat} and compute team weights@>;
+ @<Determine the |n| teams to use in the graph@>;
+ @<Put the appropriate edges into the graph@>;
+ if (gb_close()!=0)
+ panic(late_data_fault);
+ /* something's wrong with |"games.dat"|; see |io_errors| */
+ gb_free(working_storage);
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |games| */
+register int j,k; /* all-purpose indices */
+
+@ @<Check that the parameters are valid@>=
+if (n==0 || n>MAX_N) n=MAX_N;
+if (ap0_weight>MAX_WEIGHT || ap0_weight<-MAX_WEIGHT ||
+ upi0_weight>MAX_WEIGHT || upi0_weight<-MAX_WEIGHT ||@|
+ ap1_weight>MAX_WEIGHT || ap1_weight<-MAX_WEIGHT ||
+ upi1_weight>MAX_WEIGHT || upi1_weight<-MAX_WEIGHT)
+ panic(bad_specs); /* the magnitude of at least one weight is too big */
+if (first_day<0) first_day=0;
+if (last_day==0 || last_day>MAX_DAY) last_day=MAX_DAY;
+
+@ @<Set up a graph with |n| vertices@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"games(%u,%ld,%ld,%ld,%ld,%d,%d,%ld)",
+ n,ap0_weight,upi0_weight,ap1_weight,upi1_weight,first_day,last_day,seed);
+strcpy(new_graph->format,"IIIISSIIZZZZZZ");
+
+@* Vertices.
+As we read in the data, we construct a list of nodes, each of which contains
+a team's name, nickname, conference, and weight. After this list
+has been sorted by weight, the top |n| entries will be the vertices of the
+new graph.
+
+@<Type decl...@>=
+typedef struct node_struct { /* records to be sorted by |gb_linksort| */
+ long key; /* the nonnegative sort key (weight plus $2^{30}$) */
+ struct node_struct *link; /* pointer to next record */
+ char name[24]; /* |"College Name"| */
+ char nick[22]; /* |"Team Nickname"| */
+ char abbr[6]; /* |"ABBR"| */
+ int a0,u0,a1,u1; /* team scores in press polls */
+ char *conf; /* pointer to conference name */
+ struct node_struct *hash_link; /* pointer to next \.{ABBR} in hash list */
+ Vertex *v; /* vertex corresponding to this team */
+} node;
+
+@ The data in \.{games.dat} appears in two parts. The first 120 lines
+have the form
+$$\hbox{\tt ABBR College Name(Team Nickname)Conference;a0,u0;a1,u1}$$
+and they give basic information about the teams. An internal abbreviation code
+\.{ABBR} is used to identify each team in the second part of the data.
+
+The second part presents scores of the games, and it
+contains two kinds of lines. If the first character of a line is
+`\.>', it means ``change the current date,''
+and it gives a date as a one-letter month code followed by the day
+of the month. Otherwise the line gives scores of a game, using the
+\.{ABBR} codes for two teams. The scores are separated by `\.@@' if
+the second team was the home team, by `\.,' if both teams were on
+neutral territory.
+
+For example, two games were played on December 8, namely the annual Army-Navy
+game and the California Raisin Bowl game. These are recorded in three lines
+of \.{games.dat} as follows:
+$$\vbox{\halign{\tt#\hfil\cr
+>D8\cr
+NAVY20@@ARMY30\cr
+SJSU48,CMICH24\cr}}$$
+We deduce that Navy played at Army's home stadium, losing 20 to~30;
+San Jose State played Central Michigan on neutral territory and
+won, 48 to~24. (The California Raisin Bowl is traditionally a playoff between
+the champions of the Big West and Mid-American conferences.)
+
+@ In order to map \.{ABBR} codes to team names, we use a simple
+hash coding scheme. Two abbreviations with the same hash address are
+linked together via the |hash_link| address in their node.
+
+The constants defined here are taken from the specific data in \.{games.dat},
+because this routine is not intended to be perfectly general.
+
+@d HASH_PRIME 1009
+
+@<Private v...@>=
+static int ma0=1451,mu0=666,ma1=1475,mu1=847;
+ /* maximum poll values in the data */
+static node *node_block; /* array of nodes holding team info */
+static node **hash_block; /* array of heads of hash code lists */
+static Area working_storage; /* memory needed only while |games| is working */
+static char **conf_block; /* array of conference names */
+static int m; /* the number of conference names known so far */
+
+@ @<Read the first part of \.{games.dat} and compute team weights@>=
+node_block=gb_alloc_type(MAX_N+2,@[node@],working_storage);
+ /* leave room for string overflow */
+hash_block=gb_alloc_type(HASH_PRIME,@[node*@],working_storage);
+conf_block=gb_alloc_type(MAX_N,@[char*@],working_storage);
+m=0;
+if (gb_alloc_trouble) {
+ gb_free(working_storage);
+ panic(no_room+1); /* nowhere to copy the data */
+}
+if (gb_open("games.dat")!=0)
+ panic(early_data_fault); /* couldn't open |"games.dat"| using
+ GraphBase conventions; |io_errors| tells why */
+for (k=0; k<MAX_N; k++) @<Read and store data for team |k|@>;
+
+@ @<Read and store...@>=
+{@+register node *p;
+ register char *q;
+ p=node_block+k;
+ if (k) p->link=p-1;
+ q=gb_string(p->abbr,' ');
+ if (q>&p->abbr[6] || gb_char()!=' ')
+ panic(syntax_error); /* out of sync in \.{games.dat} */
+ @<Enter |p->abbr| in the hash table@>;
+ q=gb_string(p->name,'(');
+ if (q>&p->name[24] || gb_char()!='(')
+ panic(syntax_error+1); /* team name too long */
+ q=gb_string(p->nick,')');
+ if (q>&p->nick[22] || gb_char()!=')')
+ panic(syntax_error+2); /* team nickname too long */
+ @<Read the conference name for |p|@>;
+ @<Read the press poll scores for |p| and compute |p->key|@>;
+ gb_newline();
+}
+
+@ @<Enter |p->abbr| in the hash table@>=
+{@+int h=0; /* the hash code */
+ for (q=p->abbr;*q;q++)
+ h=(h+h+*q)%HASH_PRIME;
+ p->hash_link=hash_block[h];
+ hash_block[h]=p;
+}
+
+@ @<Read the conference name for |p|@>=
+{@+int j;
+ gb_string(str_buf,';');
+ if (gb_char()!=';') panic(syntax_error+3); /* conference name clobbered */
+ if (strcmp(str_buf,"Independent")!=0) {
+ for (j=0;j<m;j++)
+ if (strcmp(str_buf,conf_block[j])==0) goto found;
+ conf_block[m++]=gb_save_string(str_buf);
+ found:p->conf=conf_block[j];
+ }
+}
+
+@ The key value computed here will be between 0 and~$2^{31}$, because of
+the bound we've imposed on the weight parameters.
+
+@<Read the press poll scores for |p| and compute |p->key|@>=
+p->a0=gb_number(10);
+if (p->a0>ma0 || gb_char()!=',') panic(syntax_error+4);
+ /* first AP number clobbered */
+p->u0=gb_number(10);
+if (p->u0>mu0 || gb_char()!=';') panic(syntax_error+5);
+ /* first UPI number clobbered */
+p->a1=gb_number(10);
+if (p->a1>ma1 || gb_char()!=',') panic(syntax_error+6);
+ /* second AP number clobbered */
+p->u1=gb_number(10);
+if (p->u1>mu1 || gb_char()!='\n') panic(syntax_error+7);
+ /* second UPI number clobbered */
+p->key=ap0_weight*(p->a0)+upi0_weight*(p->u0)
+ +ap1_weight*(p->a1)+upi1_weight*(p->u1)+0x40000000;
+
+@ Once all the nodes have been set up, we can use the |gb_linksort|
+routine to sort them into the desired order. It builds 128
+lists from which the desired nodes are readily accessed in decreasing
+order of weight, using random numbers to break ties.
+
+We set the abbreviation code to zero in every team that isn't chosen. Then
+games involving that team will be excluded when edges are generated below.
+
+@<Determine the |n| teams to use in the graph@>=
+{@+register node *p; /* the current node being considered */
+ register Vertex *v=new_graph->vertices; /* the next vertex to use */
+ gb_linksort(node_block+MAX_N-1);
+ for (j=127; j>=0; j--)
+ for (p=(node*)gb_sorted[j]; p; p=p->link) {
+ if (v<new_graph->vertices+n) @<Add team |p| to the graph@>@;
+ else p->abbr[0]='\0'; /* this team is not being used */
+ }
+}
+
+@ @<Add team |p| to the graph@>=
+{
+ v->ap0=p->a0;
+ v->upi0=p->u0;
+ v->ap1=p->a1;
+ v->upi1=p->u1;
+ v->nickname=gb_save_string(p->nick);
+ v->conference=p->conf;
+ v->name=gb_save_string(p->name);
+ p->v=v++;
+}
+
+@* Arcs.
+Finally, we read through the rest of \.{games.dat}, adding a pair of
+arcs for each game that belongs to the selected time interval,
+if it was played by two of the selected teams.
+
+@<Put the appropriate edges into the graph@>=
+{@+register Vertex *u,*v;
+ register int today; /* current day of play */
+ int su,sv; /* points scored by each team */
+ int ven; /* |HOME| if |v| is home team, |NEUTRAL| if on neutral ground */
+ while (!gb_eof()) {
+ if (gb_char()=='>') @<Change the current date@>@;
+ else gb_backup();
+ u=team_lookup();
+ su=gb_number(10);
+ ven=gb_char();
+ if (ven=='@@') ven=HOME;
+ else if (ven==',') ven=NEUTRAL;
+ else panic(syntax_error+8); /* bad syntax in game score line */
+ v=team_lookup();
+ sv=gb_number(10);
+ if (gb_char()!='\n') panic(syntax_error+9);
+ /* bad syntax in game score line */
+ if (u!=NULL && v!=NULL && today>=first_day && today<=last_day)
+ @<Enter a new edge@>;
+ gb_newline();
+ }
+}
+
+@ @<Change the current...@>=
+{@+register char q=gb_char(); /* month code */
+ register int d; /* day of football season */
+ switch(q) {
+ case 'A': d=-26;@+break; /* August */
+ case 'S': d=5;@+break; /* thirty days hath September */
+ case 'O': d=35;@+break; /* October */
+ case 'N': d=66;@+break; /* November */
+ case 'D': d=96;@+break; /* December */
+ case 'J': d=127;@+break; /* January */
+ default: d=1000;
+ }
+ d+=gb_number(10);
+ if (d<0 || d>MAX_DAY) panic(syntax_error-1); /* date was clobbered */
+ today=d;
+ gb_newline(); /* now ready to read a non-date line */
+}
+
+@ @<Private f...@>=
+static Vertex *team_lookup() /* read and decode an abbreviation */
+{@+register char *q=str_buf; /* position in |str_buf| */
+ register int h=0; /* hash code */
+ register node *p; /* position in hash list */
+ while (gb_digit(10)<0) {
+ *q=gb_char();
+ h=(h+h+*q)%HASH_PRIME;
+ q++;
+ }
+ gb_backup(); /* prepare to re-scan the digit following the abbreviation */
+ *q='\0'; /* null-terminate the abbreviation just scanned */
+ for (p=hash_block[h];p;p=p->hash_link)
+ if (strcmp(p->abbr,str_buf)==0) return p->v;
+ return NULL; /* not found */
+}
+
+@ We retain the convention of |gb_graph| that the arc from |v| to |u|
+appears immediately after a matching arc from |u| to |v| when |u<v|.
+
+@<Enter a new edge@>=
+{@+register Arc *a;
+ if (u>v) {@+register Vertex *w; register int sw;
+ w=u;@+u=v;@+v=w;
+ sw=su;@+su=sv;@+sv=sw;
+ ven=HOME+AWAY-ven;
+ }
+ gb_new_arc(u,v,su);
+ gb_new_arc(v,u,sv);
+ a=u->arcs; /* a pointer to the new arc */
+ if (v->arcs!=a+1) panic (99); /* can't happen */
+ a->venue=ven;@+(a+1)->venue=HOME+AWAY-ven;
+ a->date=(a+1)->date=today;
+}
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_games} are defined and used.
diff --git a/support/graphbase/gb_gates.w b/support/graphbase/gb_gates.w
new file mode 100644
index 0000000000..e010d61fa1
--- /dev/null
+++ b/support/graphbase/gb_gates.w
@@ -0,0 +1,1924 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace GATES}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GRAPH}
+@* Introduction. This GraphBase module provides six external subroutines:
+$$\vbox{\hsize=.8\hsize \everypar{\hangindent3em}
+\noindent|risc|, a routine that creates a directed acyclic graph based on the
+ logic of a simple RISC computer;\par
+\noindent|prod|, a routine that creates a directed acyclic graph based on the
+ logic of parallel multiplication circuits;\par
+\noindent|print_gates|, a routine that outputs a symbolic representation of
+ such directed acyclic graphs;\par
+\noindent|gate_eval|, a routine that evaluates such directed acyclic graphs by
+ assigning boolean values to each gate;\par
+\noindent|partial_gates|, a routine that extracts a subgraph by assigning
+ random values to some of the input gates;\par
+\noindent|run_risc|, a routine that can be used to play with the output
+ of |risc|.}$$
+Examples of the use of these routines can be found in the demo programs
+|take_risc| and |multiply|.
+
+@(gb_gates.h@>=
+extern Graph *risc(); /* make a network for a microprocessor */
+extern Graph *prod(); /* make a network for high-speed multiplication */
+extern void print_gates(); /* write a network to standard output file */
+extern int gate_eval(); /* evaluate a network */
+extern Graph *partial_gates(); /* reduce network size */
+extern int run_risc(); /* simulate the microprocessor */
+extern unsigned risc_state[]; /* the output of |run_risc| */
+
+@ The directed acyclic graphs produced by |gb_gates| are GraphBase
+graphs with special conventions related to logical networks. Each vertex
+represents a gate of a network, and utility field |val| is a boolean
+value associated with that gate. Utility field |typ| is an ASCII code
+that tells what kind of gate is present:
+{\advance\parindent 2em
+\smallskip
+\item{|'I'|} denotes an input gate, whose value is specified externally.
+
+\smallskip
+\item{|'&'|} denotes an \.{AND} gate, whose value is the logical {\sc AND} of
+two or more previous gates (namely, 1 if all those gates are~1, otherwise~0).
+
+\smallskip
+\item{|'|'|} denotes an \.{OR} gate, whose value is the logical {\sc OR} of
+two or more previous gates (namely, 0 if all those gates are~0, otherwise~1).
+
+\smallskip
+\item{|'^'|} denotes an \.{XOR} gate, whose value is the logical {\sc
+EXCLUSIVE-OR} of two or more previous gates (namely, their sum modulo~2).
+
+\smallskip
+\item{|'~'|} denotes an inverter, whose value is the logical complement of
+the value of a single previous gate.
+
+\smallskip
+\item{|'L'|} denotes a latch, whose value depends on past history; it is
+the value that was assigned to a subsequent gate when the network was most
+recently evaluated. Utility field |alt| points to that subsequent gate.
+
+\smallskip}\noindent
+Latches can be used to include ``state'' information in a circuit; for example,
+they correspond to registers of the RISC machine constructed by |risc|.
+The |prod| procedure does not use latches.
+
+The vertices of the directed acyclic graph appear in a special ``topological''
+order convenient for evaluation: All the input gates come first, followed
+by all the latches; then come the other types of gates, whose values are
+computed from their predecessors. The arcs of the graph run from each gate
+to its arguments, and all arguments to a gate precede that gate.
+
+If |g| points to such a graph of gates, the utility field |g->outs| points to
+a list of |Arc| records, denoting ``outputs'' that might be used in
+certain applications. For example, the outputs of the graphs
+created by |prod| correspond to the bits of the product of the numbers
+represented in the input gates.
+
+A special convention is used so that the routines will support partial
+evaluation: The |tip| fields in the output list either point to a
+vertex or hold one of the constant values 0 or~1 when regarded as an
+unsigned long integer.
+
+@d val x.i /* the field containing a boolean value */
+@d typ y.i /* the field containing the gate type */
+@d alt z.v /* the field pointing to another related gate */
+@d outs z.a /* the field pointing to the list of output gates */
+@d is_boolean(v) ((unsigned long)(v)<=1) /* is a |tip| field constant? */
+@d the_boolean(v) ((long)(v)) /* if so, this is its value */
+@d tip_value(v) (is_boolean(v)? the_boolean(v): (v)->val)
+@d AND '&'
+@d OR '|'
+@d NOT '~'
+@d XOR '^'
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@(gb_gates.h@>=
+#define val @t\quad@> x.i /* the definitions are repeated in the header file */
+#define typ @t\quad@> y.i
+#define alt @t\quad@> z.v
+#define outs @t\quad@> z.a
+#define is_boolean(v) @t\quad@> ((unsigned long)(v)<=1)
+#define the_boolean(v) @t\quad@> ((long)(v))
+#define tip_value(v) @t\quad@> (is_boolean(v)? the_boolean(v): (v)->val)
+#define AND @t\quad@> '&'
+#define OR @t\quad@> '|'
+#define NOT @t\quad@> '~'
+#define XOR @t\quad@> '^'
+
+@ Let's begin with the |gate_eval| procedure, because it is quite simple
+and because it illustrates the conventions just explained. Given a gate
+graph |g| and optional pointers |in_vec| and |out_vec|, the procedure
+|gate_eval| will assign values to each gate of~|g|. If |in_vec| is
+non-null, it should point to a string of characters, each |'0'| or~|'1'|,
+that will be assigned to the first gates of the network, in order;
+otherwise |gate_eval| assumes that all input gates have already received
+appropriate values and it will not change them. New values are computed for
+each gate after the bits of |in_vec| have been consumed.
+
+If |out_vec| is non-null, it should point to a memory area capable of
+receiving |m+1| characters, where |m| is the number of outputs of~|g|;
+a string containing the respective output values will be deposited there.
+
+If |gate_eval| encounters an unknown gate type, it terminates execution
+prematurely and returns the value |-1|. Otherwise it returns~0.
+
+@<The |gate_eval| routine@>=
+int gate_eval(g,in_vec,out_vec)
+ Graph *g; /* graph with gates as vertices */
+ char *in_vec; /* string for input values, or |NULL| */
+ char *out_vec; /* string for output values, or |NULL| */
+{@+register Vertex *v; /* the current vertex of interest */
+ Vertex *u, *uu; /* additional vertices being examined */
+ register Arc *a; /* the current arc of interest */
+ register char t; /* boolean value being computed */
+ if (!g) return -2; /* no graph supplied! */
+ v=g->vertices;
+ if (in_vec) @<Read a sequence of input values from |in_vec|@>;
+ for (; v<g->vertices+g->n; v++) {
+ switch (v->typ) { /* branch on type of gate */
+ case 'I': continue; /* this input gate's value should be externally set */
+ case 'L': t=v->alt->val;@+break;
+ @t\4\4@>@;@+@<Compute the value |t| of a classical logic gate@>;
+ default: return -1; /* unknown gate type! */
+ }
+ v->val=t; /* assign the computed value */
+ }
+ if (out_vec) @<Store the sequence of output values in |out_vec|@>;
+ return 0;
+}
+
+@ @<Read a sequence...@>=
+while (*in_vec && v<g->vertices+g->n)
+ (v++)->val = *in_vec++ - '0';
+
+@ @<Store the sequence of output values in |out_vec|@>=
+{
+ for (a=g->outs; a; a=a->next)
+ *out_vec++='0'+tip_value(a->tip);
+ *out_vec=0; /* terminate the string */
+}
+
+@ @<Compute the value |t| of a classical logic gate@>=
+case AND: t=1;
+ for (a=v->arcs; a; a=a->next)
+ t &= a->tip->val;
+ break;
+case OR: t=0;
+ for (a=v->arcs; a; a=a->next)
+ t |= a->tip->val;
+ break;
+case XOR: t=0;
+ for (a=v->arcs; a; a=a->next)
+ t ^= a->tip->val;
+ break;
+case NOT: t=1-v->arcs->tip->val;
+ break;
+
+@ Here now is an outline of the entire |gb_gates| module, as seen by
+the \Cee\ compiler:
+
+@p
+#include "gb_flip.h" /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h" /* and we will use the |gb_graph| data structures */
+@#
+@<Private variables@>@;
+@<Global variables@>@;
+@<Internal subroutines@>@;
+@<The |gate_eval| routine@>@;
+@<The |print_gates| routine@>@>;
+@<The |risc| routine@>@;
+@<The |run_risc| routine@>@;
+@<The |prod| routine@>@;
+@<The |partial_gates| routine@>@;
+
+@* The RISC netlist. The subroutine call `|risc(regs)|' creates a
+gate graph having |regs| registers; the value of |regs| must be
+between 2 and~16, inclusive, otherwise |regs| is set to~16.
+This gate graph describes the circuitry for a small RISC computer, defined
+below. The total number of gates turns out to be |1400+115*regs|;
+thus it lies between 1630 (when |regs=2|) and 3240 (when |regs=16|).
+Exclusive-or gates are not used; the effect of xoring is obtained where
+needed by means of {\sc AND}s, {\sc OR}s, and inverters.
+
+If |risc| cannot do its thing, it returns |NULL| (\.{NULL})
+ and sets |panic_code|
+to indicate the problem. Otherwise |risc| returns a pointer to the graph.
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+
+@<The |risc| routine@>=
+Graph *risc(regs)
+ unsigned regs; /* number of registers supported */
+{@+@<Local variables for |risc|@>@;
+ @#
+ @<Initialize |new_graph| to an empty graph of the appropriate size@>;
+ @<Add the RISC data to |new_graph|@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local variables for |risc|@>=
+Graph *new_graph; /* the graph constructed by |risc| */
+register int k,r; /* all-purpose indices */
+
+@ This RISC machine works with 16-bit registers and 16-bit data words.
+It cannot write into memory, but it assumes the existence of an
+external read-only memory. The circuit has 16 outputs, representing
+the 16 bits of a memory address register; it also has 17 inputs, the
+last 16 of which are supposed to be set to the contents of the memory
+address computed on the previous cycle. Thus, we can run the machine
+by accessing memory between calls of |gate_eval|. The first input
+bit, called \.{RUN}, is normally set to~1; if it is~0, the other
+inputs are effectively ignored and all registers and outputs will be
+cleared to~0. Input bits for the memory appear in ``little-endian
+order,'' i.e., least significant bit first; but the output bits for
+the memory address register appear in ``big-endian order,'' i.e., most
+significant bit first.
+
+Words read from memory are interpreted as instructions having the following
+format:
+$$\vbox{\offinterlineskip
+ \def\\#1&{\omit&#1&}
+ \hrule
+ \halign{&\vrule#&\strut\sevenrm\hbox to 1.7em{\hfil#\hfil}\cr
+ height 5pt&\multispan7\hfill&&\multispan7\hfill&&\multispan3\hfill
+ &&\multispan3\hfill&&\multispan7\hfill&\cr
+ &\multispan7\hfill\.{DST}\hfill&&\multispan7\hfill\.{MOD}\hfill
+ &&\multispan3\hfill\.{OP}\hfill&&\multispan3\hfill\.{A}\hfill
+ &&\multispan7\hfill\.{SRC}\hfill&\cr
+ height 5pt&\multispan7\hfill&&\multispan7\hfill&&\multispan3\hfill
+ &&\multispan3\hfill&&\multispan7\hfill&\cr
+ \noalign{\hrule}
+ \\15&\\14&\\13&\\12&\\11&\\10&\\9&\\8&\\7&\\6&\\5&\\4&\\3&\\2&\\1&%
+ \\0&\omit\cr}}$$
+The \.{SRC} and \.A fields specify a ``source'' value.
+If $\.A=0$, the source is \.{SRC}, treated as a 16-bit signed
+number between $-8$ and $+7$ inclusive.
+If $\.A=1$, the source is the contents of register \.{DST} plus the
+(signed) value of \.{SRC}. If $\.A=2$, the source is the contents of register
+\.{SRC}. And if $\.A=3$, the source is the contents of the memory location
+whose address is the contents of register \.{SRC}. Thus, for example,
+if $\.{DST}=3$ and $\.{SRC}=10$, and if \.{r3} contains 17 while \.{r10}
+contains 1009, the source value will be $-6$ if $\.A=0$,
+or $17-6=11$ if $\.A=1$, or 1009 if $\.A=2$, or the contents of memory location
+1009 if $\.A=3$.
+
+The \.{DST} field specifies the number of the destination register. This
+register receives a new value based on its previous value and the source
+value, as prescribed by the operation defined in the \.{OP} and \.{MOD}
+fields. For example, when $\.{OP}=0$, a general logical operation is
+performed: Suppose the bits of \.{MOD} are called $\mu_{11}\mu_{10}\mu_{01}
+\mu_{00}$ from left to right; then if the $k$th bit of the destination register
+currently is equal to~$i$ and the $k$th bit of the source value is
+equal to~$j$, the general logical operator changes the $k$th bit of
+the destination register to~$\mu_{ij}$. If the \.{MOD} bits are,
+for example, $1010$, the source value is simply copied to the
+destination register; if $\.{MOD}=0110$, an exclusive or is done;
+if $\.{MOD}=0011$, the destination register is complemented and the
+source value is effectively ignored.
+
+The machine contains four status bits called \.S (sign), \.N (nonzero),
+\.K (carry), and \.V (overflow). Every general logical operation sets
+\.S equal to the sign of the new result transferred to the destination
+register; this is bit~15, the most significant bit. A general logical
+operation also sets \.N to~1 if any of the other 15 bits are~1, to~0
+if all of the other bits are~0. Thus, \.S and \.N both become zero if and
+only if the new result is entirely zero. Logical operations do not change
+the values of \.K and~\.V; the latter are affected only by the arithmetic
+operations described below.
+
+The status of the \.S and \.N bits can be tested by using the
+conditional load operator, $\.{OP}=2$: This operation loads the source
+value into the destination register if and only if \.{MOD} bit
+$\mu_{ij}=1$, where $i$ and~$j$ are the current values of \.S and~\.N,
+respectively. For example, if $\.{MOD}=0011$, the source value is
+loaded if and only if $\.S=0$, which means that the last value
+affecting \.S and~\.N was greater than or equal to zero. If
+$\.{MOD}=1111$, loading is always done; this is a way to move source
+to destination without affecting \.S or~\.N.
+
+A second conditional load operator, $\.{OP}=3$, is similar but
+it is used for testing the status of \.K and~\.V instead of
+\.S and~\.N. For example, a command having $\.{MOD}=1010$,
+$\.{OP}=3$, $\.A=1$, and $\.{SRC}=1$ adds the current overflow bit to the
+destination register. (Please take a moment to understand why
+this is true.)
+
+We have now described all the operations except those that
+are performed when $\.{OP}=1$.
+As you might expect, our machine is able to do rudimentary arithmetic,
+and the general addition and subtraction operators can be found here,
+together with various shift operators, depending on the value of \.{MOD}.
+
+Eight of the $\.{OP}=1$ operations set the destination register to a shifted
+version of the source value: $\.{MOD}=0$ means ``shift left~1,''
+which is equivalent to multiplying the source by~2; $\.{MOD}=1$ means
+``cyclic shift left~1,'' which is the same but also adding the
+previous sign bit to the result; $\.{MOD}=2$ means ``shift left~4,''
+which is equivalent to multiplying by~16; $\.{MOD}=3$ means ``cyclic
+shift left~4''; $\.{MOD}=4$ means ``shift right~1,'' which is
+equivalent to dividing the source by~2 and rounding down to the
+next lower integer if there was a remainder; $\.{MOD}=5$ means
+``unsigned shift right~1,'' which is the same except that the
+most significant bit is always set to zero instead of retaining the
+previous sign; $\.{MOD}=6$ means ``shift right~4,'' which is equivalent
+to dividing the source by~16 and rounding down; $\.{MOD}=7$ means
+``unsigned shift right~4.'' Each of these shift operations affects
+\.S and~\.N, as in the case of logical operations. They also affect
+\.K and~\.V, as follows: Shifting left sets \.K to~1 if and
+only if at least one of the bits shifted off the left was nonzero,
+and sets \.V to~1 if and only if the corresponding multiplication
+would cause overflow.
+Shifting right~1 sets \.K to the value of the bit
+shifted out, and sets \.V to~0;
+shifting right~4 sets \.K to the value of the last
+bit shifted out, and sets \.V to the logical {\sc OR} of the other three
+lost bits. The same values of \.K and \.V arise from cyclic or unsigned
+shifts as from ordinary shifts.
+
+When $\.{OP}=1$ and $\.{MOD}=8$, the source value is added to the
+destination register. This sets \.S, \.N, and \.V as you would expect;
+and it sets \.K to the carry you would get if treating the values as
+16-bit unsigned integers. Another addition operation, having
+$\.{MOD}=9$, is similar, but the current value of \.K is also added to
+the result; in this case, the new value of \.N will be zero if and only if
+the 15 non-sign bits of the result are zero and the previous values of
+\.S and~\.N were also zero. This means
+that you can use the first addition operation on the lower
+halves of a 32-bit number and the second operation on the upper halves,
+thereby obtaining a correct 32-bit result, with appropriate sign,
+nonzero, carry, and overflow bits set.
+Higher precision (48 bits, 64 bits, etc.)~can be obtained in a similar way.
+
+When $\.{OP}=1$ and $\.{MOD}=10$, the source value is subtracted
+from the destination register. Again, \.S, \.N, \.K, and \.V are set;
+the \.K value in this case represents the ``borrow'' bit.
+An auxiliary subtraction operation, having $\.{MOD}=11$, subtracts
+also the current value of \.K, thereby allowing for correct 32-bit subtraction.
+
+The operations for $\.{OP}=1$ and $\.{MOD}=12$, 13, and~14 are
+``reserved for future expansion.'' Actually they will never change,
+since this RISC chip is merely academic; if you check out the logic
+below you will find that they simply set the destination register and
+the four status bits all to zero.
+
+There is one further operation, having $\.{OP}=1$ and $\.{MOD}=15$;
+this is the special \.{JUMP} operation described below. It does not
+affect \.S, \.N, \.K, or~\.V.
+
+If the RISC is made with fewer than 16 registers, the higher-numbered ones
+will effectively contain zero whenever their values are fetched.
+But if you use them as destination registers, you will set
+\.S, \.N, \.K, and~\.V as if actual numbers were being stored.
+
+Register 0 is different from the other 15 registers: It is the location
+of the current instruction. Therefore if you change the contents of
+register~0, you are changing the control flow of the program. If you
+do not change register~0, it automatically increases by~1.
+
+Special treatment occurs when $\.A=3$ and $\.{SRC}=0$:
+In such a case, the normal rules given above say that the source value
+should be the contents of the memory location specified by register~0. But
+that memory location holds the current instruction; so the machine
+uses the {\it following\/} location instead, as a 16-bit source
+operand. If the contents of register~0 are not changed by such a
+two-word instruction, register~0 will increase by~2 instead of~1.
+
+We have now learned everything about the machine except the operation
+of the \.{JUMP} command. This command moves the source value to
+register~0, thereby changing the flow of control; furthermore, if $\.{DST}\ne0$,
+it also sets register \.{DST} to the location of the instruction
+following the \.{JUMP}. Assembly language programmers will recognize
+this as a convenient way to jump to a subroutine.
+
+Example programs can be found in the |take_risc| module, which includes
+a simple subroutine for multiplication and division.
+
+@ A few auxiliary functions will ameliorate the task of constructing
+the RISC logic. First comes a routine that ``christens'' a new gate,
+assigning it a name and a type. The name is constructed from a prefix
+and a serial number, where the prefix indicates the current portion of
+logic being created.
+
+@<Internal...@>=
+static Vertex* new_vert(t)
+ char t; /* the type of the new gate */
+{@+register Vertex *v;
+ v=next_vert++;
+ if (count<0) v->name=gb_save_string(prefix);
+ else {
+ sprintf(name_buf,"%s%d",prefix,count);
+ v->name=gb_save_string(name_buf);
+ count++;
+ }
+ v->typ=t;
+ return v;
+}
+
+@ @d start_prefix(s) strcpy(prefix,s);@+count=0
+@d numeric_prefix(a,b) sprintf(prefix,"%c%d:",a,b);@+count=0;
+
+@<Private...@>=
+static Vertex* next_vert; /* the first vertex not yet assigned a name */
+static char prefix[5]; /* prefix string for vertex names */
+static int count; /* serial number for vertex names */
+static char name_buf[100]; /* place to form vertex names */
+
+@ Here are some trivial routines to create gates with 2, 3, or more
+arguments. The arcs from a gate to its inputs are assigned length 100;
+below we will assign length~1 to the arcs between an inverter and its
+unique input. This makes the lengths of shortest paths in the resulting
+network a bit more interesting than they would otherwise be.
+
+@d DELAY 100
+
+@<Internal...@>=
+static Vertex* make2(t,v1,v2)
+ char t; /* the type of the new gate */
+ Vertex *v1,*v2;
+{@+register Vertex *v=new_vert(t);
+ gb_new_arc(v,v1,DELAY);
+ gb_new_arc(v,v2,DELAY);
+ return v;
+}
+@#
+static Vertex* make3(t,v1,v2,v3)
+ char t; /* the type of the new gate */
+ Vertex *v1,*v2,*v3;
+{@+register Vertex *v=new_vert(t);
+ gb_new_arc(v,v1,DELAY);
+ gb_new_arc(v,v2,DELAY);
+ gb_new_arc(v,v3,DELAY);
+ return v;
+}
+@#
+static Vertex* make4(t,v1,v2,v3,v4)
+ char t; /* the type of the new gate */
+ Vertex *v1,*v2,*v3,*v4;
+{@+register Vertex *v=new_vert(t);
+ gb_new_arc(v,v1,DELAY);
+ gb_new_arc(v,v2,DELAY);
+ gb_new_arc(v,v3,DELAY);
+ gb_new_arc(v,v4,DELAY);
+ return v;
+}
+@#
+static Vertex* make5(t,v1,v2,v3,v4,v5)
+ char t; /* the type of the new gate */
+ Vertex *v1,*v2,*v3,*v4,*v5;
+{@+register Vertex *v=new_vert(t);
+ gb_new_arc(v,v1,DELAY);
+ gb_new_arc(v,v2,DELAY);
+ gb_new_arc(v,v3,DELAY);
+ gb_new_arc(v,v4,DELAY);
+ gb_new_arc(v,v5,DELAY);
+ return v;
+}
+
+@ We will use utility field |w.v| to store a pointer to the complement
+of a gate, if that complement has been formed; this will prevent the creation
+of a lot of gates that are equivalent to each other. The following subroutine
+returns a pointer to the complement of a given gate.
+
+@d bar w.v /* field pointing to complement, if known to exist */
+@d signed(s,v) ((s)&1? v: comp(v))
+
+@<Internal...@>=
+static Vertex* comp(v)
+ Vertex *v;
+{@+register Vertex *u;
+ if (v->bar) return v->bar;
+ u=next_vert++;
+ u->bar=v;@+v->bar=u;
+ sprintf(name_buf,"%s~",v->name);
+ u->name=gb_save_string(name_buf);
+ u->typ=NOT;
+ gb_new_arc(u,v,1);
+ return u;
+}
+
+@ To create a gate for the {\sc EXCLUSIVE-OR} of two arguments, we can
+either construct the {\sc OR} of two {\sc AND}s, or the {\sc AND} of two
+{\sc OR}s. We choose the former alternative:
+
+@<Internal...@>=
+static Vertex* make_xor(u,v)
+ Vertex *u,*v;
+{@+register Vertex *t1,*t2;
+ t1=make2(AND,u,comp(v));
+ t2=make2(AND,comp(u),v);
+ return make2(OR,t1,t2);
+}
+
+@ OK, let's get going.
+
+@<Initialize |new_graph|...@>=
+if (regs<2 || regs>16) regs=16;
+new_graph=gb_new_graph(1400+115*regs);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"risc(%u)",regs);
+strcpy(new_graph->format,"ZZZIIVZZZZZZZA");
+next_vert=new_graph->vertices;
+
+@ @<Add the RISC data to |new_graph|@>=
+@<Create the inputs and latches@>;
+@<Create gates for instruction decoding@>;
+@<Create gates for fetching the source value@>;
+@<Create gates for the general logic operation@>;
+@<Create gates for the conditional load operations@>;
+@<Create gates for the arithmetic operations@>;
+@<Create gates that bring everything together properly@>;
+if (next_vert!=new_graph->vertices+new_graph->n)
+ panic(impossible); /* oops, we miscounted; this should be impossible */
+
+@ We will want to assign internal names to many of the most important
+gates. Here are the names of inputs and latches.
+
+@<Local variables for |risc|@>=
+Vertex *run_bit; /* the \.{RUN} input */
+Vertex *mem[16]; /* 16 bits of input from read-only memory */
+Vertex *prog; /* first of 10 bits in the program register */
+Vertex *sign; /* the latched value of \.S */
+Vertex *nonzero; /* the latched value of \.N */
+Vertex *carry; /* the latched value of \.K */
+Vertex *overflow; /* the latched value of \.V */
+Vertex *extra; /* latched status bit: are we doing an extra memory cycle? */
+Vertex *reg[16]; /* the least-significant bit of a given register */
+
+@ @d first_of(n,t) new_vert(t);@+for (k=1;k<n;k++)@+new_vert(t);
+
+@<Create the inputs and latches@>=
+strcpy(prefix,"RUN");@+count=-1;@+run_bit=new_vert('I');
+start_prefix("M");@+for (k=0;k<16;k++)@+mem[k]=new_vert('I');
+start_prefix("P");@+prog=first_of(10,'L');
+strcpy(prefix,"S");@+count=-1;@+sign=new_vert('L');
+strcpy(prefix,"N");@+nonzero=new_vert('L');
+strcpy(prefix,"K");@+carry=new_vert('L');
+strcpy(prefix,"V");@+overflow=new_vert('L');
+strcpy(prefix,"X");@+extra=new_vert('L');
+for (r=0;r<regs;r++) {
+ numeric_prefix('R',r);
+ reg[r]=first_of(16,'L');
+}
+
+@ The order of evaluation of function arguments is not defined in \Cee,
+so we introduce a few macros that force left-to-right order.
+
+@d do2(result,t,v1,v2)
+ {@+t1=v1;@+t2=v2;
+ result=make2(t,t1,t2);@+}
+@d do3(result,t,v1,v2,v3)
+ {@+t1=v1;@+t2=v2;@+t3=v3;
+ result=make3(t,t1,t2,t3);@+}
+@d do4(result,t,v1,v2,v3,v4)
+ {@+t1=v1;@+t2=v2;@+t3=v3;@+t4=v4;
+ result=make4(t,t1,t2,t3,t4);@+}
+@d do5(result,t,v1,v2,v3,v4,v5)
+ {@+t1=v1;@+t2=v2;@+t3=v3;@+t4=v4;@+t5=v5;
+ result=make5(t,t1,t2,t3,t4,t5);@+}
+
+@<Local variables for |risc|@>=
+Vertex *t1,*t2,*t3,*t4,*t5; /* temporary holds to force evaluation order */
+Vertex *tmp[16]; /* additional holding places for partial results */
+Vertex *imm; /* is the source value immediate (a given constant)? */
+Vertex *rel; /* is the source value relative to the
+ current destination register? */
+Vertex *dir; /* should the source value be fetched directly
+ from a source register? */
+Vertex *ind; /* should the source value be fetched indirectly from memory? */
+Vertex *op; /* least significant bit of \.{OP} */
+Vertex *cond; /* most significant bit of \.{OP} */
+Vertex *mod[4]; /* the \.{MOD} bits */
+Vertex *dest[4]; /* the \.{DEST} bits */
+
+@ The sixth line of the program here can be translated into the logic
+equation
+$$ |op|=(|extra|\land|prog|)\lor(\mskip1mu\overline{|extra|}\land|mem[6]|)\,.$$
+Once you see why, you'll be able to read the rest of this curious code.
+
+@<Create gates for instruction decoding@>=
+start_prefix("D");
+do3(imm,AND,comp(extra),comp(mem[4]),comp(mem[5])); /* $\.A=0$ */
+do3(rel,AND,comp(extra),mem[4],comp(mem[5])); /* $\.A=1$ */
+do3(dir,AND,comp(extra),comp(mem[4]),mem[5]); /* $\.A=2$ */
+do3(ind,AND,comp(extra),mem[4],mem[5]); /* $\.A=3$ */
+do2(op,OR,make2(AND,extra,prog),make2(AND,comp(extra),mem[6]));
+do2(cond,OR,make2(AND,extra,prog+1),make2(AND,comp(extra),mem[7]));
+for (k=0;k<4;k++) {
+ do2(mod[k],OR,make2(AND,extra,prog+2+k),make2(AND,comp(extra),mem[8+k]));
+ do2(dest[k],OR,make2(AND,extra,prog+6+k),make2(AND,comp(extra),mem[12+k]));
+}
+
+@ @<Create gates for fetching the source value@>=
+start_prefix("F");
+@<Set |old_dest| to the present value of the destination register@>;
+@<Set |old_src| to the present value of the source register@>;
+@<Set |inc_dest| to |old_dest| plus \.{SRC}@>;
+for (k=0;k<16;k++)@/
+ do4(source[k],OR,
+ make2(AND,imm,mem[k<4?k:3]),
+ make2(AND,rel,inc_dest[k]),@|
+ make2(AND,dir,old_src[k]),
+ make2(AND,extra,mem[k]));
+
+@ Here and in the immediately following section we create {\sc OR} gates
+|old_dest[k]| and |old_src[k]| that might have as many as 16~inputs. (The actual
+number of inputs is |regs|.) All of the
+other gates in the network will have at most five inputs.
+
+@<Set |old_dest| to the present value of the destination register@>=
+for (r=0;r<regs;r++) @/
+ do4(dest_match[r],AND,signed(r,dest[0]),signed(r>>1,dest[1]),@|
+ signed(r>>2,dest[2]),signed(r>>3,dest[3]));
+for (k=0;k<16;k++) {
+ for (r=0;r<regs;r++)@/
+ tmp[r]=make2(AND,dest_match[r],reg[r]+k);
+ old_dest[k]=new_vert(OR);
+ for (r=0;r<regs;r++) gb_new_arc(old_dest[k],tmp[r],DELAY);
+}
+
+@ @<Set |old_src| to the present value of the source register@>=
+for (k=0;k<16;k++) {
+ for (r=0;r<regs;r++)@/
+ do5(tmp[r],AND,reg[r]+k,signed(r,mem[0]),signed(r>>1,mem[1]),
+ signed(r>>2,mem[2]),signed(r>>3,mem[3]));
+ old_src[k]=new_vert(OR);
+ for (r=0;r<regs;r++) gb_new_arc(old_src[k],tmp[r],DELAY);
+}
+
+@ @<Local variables for |risc|@>=
+Vertex *dest_match[16]; /* |dest_match[r]==1| iff $\.{DST}=r$ */
+Vertex *old_dest[16]; /* contents of destination register before operation */
+Vertex *old_src[16]; /* contents of source register before operation */
+Vertex *inc_dest[16]; /* |old_dest| plus the \.{SRC} field */
+Vertex *source[16]; /* source value for the operation */
+Vertex *log[16]; /* result of general logic operation */
+Vertex *shift[18]; /* result of shift operation, with carry and overflow */
+Vertex *sum[18]; /* |old_dest| plus |source| plus optional carry */
+Vertex *diff[18]; /* |old_dest| minus |source| minus optional borrow */
+Vertex *next_loc[16]; /* contents of register 0, plus 1 */
+Vertex *next_next_loc[16]; /* contents of register 0, plus 2 */
+Vertex *result[18]; /* result of operating on |old_dest| and |source| */
+
+@ @<Create gates for the general logic operation@>=
+start_prefix("L");
+for (k=0;k<16;k++)@/
+ do4(log[k],OR,@t}\3{-5@>
+ make3(AND,mod[0],comp(old_dest[k]),comp(source[k])),@t}\3{-5@>
+ make3(AND,mod[1],comp(old_dest[k]),source[k]),@t}\3{-5@>
+ make3(AND,mod[2],old_dest[k],comp(source[k])),@t}\3{-5@>
+ make3(AND,mod[3],old_dest[k],source[k]));
+
+@ @<Create gates for the conditional load operations@>=
+start_prefix("C");
+do4(tmp[0],OR,@t}\3{-5@>
+ make3(AND,mod[0],comp(sign),comp(nonzero)),@t}\3{-5@>
+ make3(AND,mod[1],comp(sign),nonzero),@t}\3{-5@>
+ make3(AND,mod[2],sign,comp(nonzero)),@t}\3{-5@>
+ make3(AND,mod[3],sign,nonzero));
+do4(tmp[1],OR,@t}\3{-5@>
+ make3(AND,mod[0],comp(carry),comp(overflow)),@t}\3{-5@>
+ make3(AND,mod[1],comp(carry),overflow),@t}\3{-5@>
+ make3(AND,mod[2],carry,comp(overflow)),@t}\3{-5@>
+ make3(AND,mod[3],carry,overflow));
+do3(change,OR,comp(cond),make2(AND,tmp[0],comp(op)),make2(AND,tmp[1],op));
+
+@ @<Local variables for |risc|@>=
+Vertex *change; /* is the destination register supposed to change? */
+
+@ Hardware is like software except that it performs all the operations
+all the time and then selects only the results it needs. (If you think about
+it, this is a profound observation about economics, society, and nature.
+Gosh.)
+
+@<Create gates that bring everything together properly@>=
+start_prefix("Z");
+@<Create gates for the |next_loc| and |next_next_loc| bits@>;
+@<Create gates for the |result| bits@>;
+@<Create gates for the new values of registers 1 to |regs|@>;
+@<Create gates for the new values of \.S, \.N, \.K, and \.V@>;
+@<Create gates for the new values of the program register and |extra|@>;
+@<Create gates for the new values of register 0
+ and the memory address register@>;
+
+@ @<Create gates for the |next_loc|...@>=
+next_loc[0]=comp(reg[0]);@+next_next_loc[0]=reg[0];
+next_loc[1]=make_xor(reg[0]+1,reg[0]);@+next_next_loc[1]=comp(reg[0]+1);
+for (t5=reg[0]+1,k=2;k<16;t5=make2(AND,t5,reg[0]+k++)) {
+ next_loc[k]=make_xor(reg[0]+k,make2(AND,reg[0],t5));
+ next_next_loc[k]=make_xor(reg[0]+k,t5);
+}
+
+@ @<Create gates for the |result| bits@>=
+jump=make5(AND,op,mod[0],mod[1],mod[2],mod[3]); /* assume |cond=0| */
+for (k=0;k<16;k++) {
+ do5(result[k],OR,@t}\3{-5@>
+ make2(AND,comp(op),log[k]),@t}\3{-5@>
+ make2(AND,jump,next_loc[k]),@t}\3{-5@>
+ make3(AND,op,comp(mod[3]),shift[k]),@t}\3{-5@>
+ make5(AND,op,mod[3],comp(mod[2]),comp(mod[1]),sum[k]),@t}\3{-5@>
+ make5(AND,op,mod[3],comp(mod[2]),mod[1],diff[k]));
+ do2(result[k],OR,@t}\3{-5@>
+ make3(AND,cond,change,source[k]),@t}\3{-5@>
+ make2(AND,comp(cond),result[k]));
+}
+for (k=16;k<18;k++) /* carry and overflow bits of the result */
+ do3(result[k],OR,@t}\3{-5@>
+ make3(AND,op,comp(mod[3]),shift[k]),@t}\3{-5@>
+ make5(AND,op,mod[3],comp(mod[2]),comp(mod[1]),sum[k]),@t}\3{-5@>
+ make5(AND,op,mod[3],comp(mod[2]),mod[1],diff[k]));
+
+@ The program register |prog| and the |extra| bit are needed for
+the case when we must spend an extra cycle to fetch a word from memory.
+On the first cycle, |ind| is true, so a ``result'' is calculated but not
+actually used. On the second cycle, |extra| is true.
+
+A slight optimization has been introduced in order to make the circuit
+a bit more interesting: If a conditional load instruction occurs with
+indirect addressing and a false condition, the extra cycle is not taken.
+(The |next_next_loc| values were computed for this reason.)
+
+@d latchit(u,@!latch)
+ (latch)->alt=make2(AND,u,run_bit) /* |u&run_bit| is new value for |latch| */
+
+@<Create gates for the new values of the program reg...@>=
+for (k=0;k<10;k++)
+ latchit(mem[k+6],prog+k);
+do2(nextra,OR,make2(AND,ind,comp(cond)),make2(AND,ind,change));
+latchit(nextra,extra);
+nzs=make4(OR,mem[0],mem[1],mem[2],mem[3]);
+nzd=make4(OR,dest[0],dest[1],dest[2],dest[3]);
+
+@ @<Local variables for |risc|@>=
+Vertex *jump; /* is this command a \.{JUMP}, assuming |cond| is false? */
+Vertex *nextra; /* must we take an extra cycle? */
+Vertex *nzs; /* is the \.{SRC} field nonzero? */
+Vertex *nzd; /* is the \.{DST} field nonzero? */
+
+@ @<Create gates for the new values of registers 1 to |regs|@>=
+t5=make2(AND,change,comp(ind)); /* should destination register change? */
+for (r=1;r<regs;r++) {
+ t4=make2(AND,t5,dest_match[r]); /* should register |r| change? */
+ for (k=0;k<16;k++) {
+ do2(t3,OR,make2(AND,t4,result[k]),make2(AND,comp(t4),reg[r]+k));
+ latchit(t3,reg[r]+k);
+ }
+}
+
+@ @<Create gates for the new values of \.S, \.N, \.K, and \.V@>=
+do4(t5,OR,@t}\3{-5@>
+ make2(AND,sign,cond),@t}\3{-5@>
+ make2(AND,sign,jump),@t}\3{-5@>
+ make2(AND,sign,ind),@t}\3{-5@>
+ make4(AND,result[15],comp(cond),comp(jump),comp(ind)));
+latchit(t5,sign);
+do4(t5,OR,@t}\3{-5@>
+ make4(OR,result[0],result[1],result[2],result[3]),@t}\3{-5@>
+ make4(OR,result[4],result[5],result[6],result[7]),@t}\3{-5@>
+ make4(OR,result[8],result[9],result[10],result[11]),@t}\3{-5@>
+ make4(OR,result[12],result[13],result[14],@t}\3{-5@>
+@t\hskip5em@>make5(AND,make2(OR,nonzero,sign),op,mod[0],comp(mod[2]),mod[3])));
+do4(t5,OR,@t}\3{-5@>
+ make2(AND,nonzero,cond),@t}\3{-5@>
+ make2(AND,nonzero,jump),@t}\3{-5@>
+ make2(AND,nonzero,ind),@t}\3{-5@>
+ make4(AND,t5,comp(cond),comp(jump),comp(ind)));
+latchit(t5,nonzero);
+do5(t5,OR,@t}\3{-5@>
+ make2(AND,overflow,cond),@t}\3{-5@>
+ make2(AND,overflow,jump),@t}\3{-5@>
+ make2(AND,overflow,comp(op)),@t}\3{-5@>
+ make2(AND,overflow,ind),@t}\3{-5@>
+ make5(AND,result[17],comp(cond),comp(jump),comp(ind),op));
+latchit(t5,overflow);
+do5(t5,OR,@t}\3{-5@>
+ make2(AND,carry,cond),@t}\3{-5@>
+ make2(AND,carry,jump),@t}\3{-5@>
+ make2(AND,carry,comp(op)),@t}\3{-5@>
+ make2(AND,carry,ind),@t}\3{-5@>
+ make5(AND,result[16],comp(cond),comp(jump),comp(ind),op));
+latchit(t5,carry);
+
+@ As usual, we have left the hardest case for last, hoping that we will
+have learned enough tricks to handle it when the time of reckoning
+finally arrives. The most subtle part of the logic here
+is perhaps the case of a \.{JUMP} command with $\.A=3$;
+we want to increase register~0 by~1 during the first cycle of
+such a command, if $\.{SRC}=0$, so that the |result| will be
+correct on the next cycle.
+
+@<Create gates for the new values of register 0...@>=
+skip=make2(AND,cond,comp(change)); /* false conditional? */
+hop=make2(AND,comp(cond),jump); /* \.{JUMP} command? */
+do4(normal,OR,@t}\3{-5@>
+ make2(AND,skip,comp(ind)),@t}\3{-5@>
+ make2(AND,skip,nzs),@t}\3{-5@>
+ make3(AND,comp(skip),ind,comp(nzs)),@t}\3{-5@>
+ make3(AND,comp(skip),comp(hop),nzd));
+special=make3(AND,comp(skip),ind,nzs);
+for (k=0;k<16;k++) {
+ do4(t5,OR,@t}\3{-5@>
+ make2(AND,normal,next_loc[k]),@t}\3{-5@>
+ make4(AND,skip,ind,comp(nzs),next_next_loc[k]),@t}\3{-5@>
+ make3(AND,hop,comp(ind),source[k]),@t}\3{-5@>
+ make5(AND,comp(skip),comp(hop),comp(ind),comp(nzd),result[k]));
+ do2(t4,OR,@t}\3{-5@>
+ make2(AND,special,reg[0]+k),@t}\3{-5@>
+ make2(AND,comp(special),t5));
+ latchit(t4,reg[0]+k);
+ do2(t4,OR,@t}\3{-5@>
+ make2(AND,special,old_src[k]),@t}\3{-5@>
+ make2(AND,comp(special),t5));
+ {@+register Arc *a=gb_virgin_arc();
+ a->tip=make2(AND,t4,run_bit);
+ a->next=new_graph->outs;
+ new_graph->outs=a; /* pointer to memory address bit */
+ }
+} /* arcs for output bits will appear in big-endian order */
+
+@ @<Local variables for |risc|@>=
+Vertex *skip; /* are we skipping a conditional load operation? */
+Vertex *hop; /* are we doing a \.{JUMP}? */
+Vertex *normal; /* is this a case where register 0 is simply incremented? */
+Vertex *special; /* is this a case where register 0 and the memory address
+ register will not coincide? */
+
+@* Serial addition. We haven't yet specified the parts of |risc| that
+deal with addition and subtraction; somehow, those parts wanted to
+be separate from the rest. To complete our mission, we will use
+subroutine calls of the form `|make_adder(n,x,y,z,carry,add)|',
+where |x| and |y| are |n|-bit arrays of input gates and
+|z|~is an |(n+1)|-bit array of output gates. If |add!=0|, the subroutine
+computes |x+y|, otherwise it computes |x-y|. If |carry!=0|, the |carry| gate
+is effectively added to~|y| before the operation.
+
+A simple |n|-stage serial scheme, which reduces the problem of |n|-bit
+addition to |(n-1)|-bit addition, is adequate for our purposes here.
+(A parallel adder, which gains efficiency by reducing the problem size
+from |n| to~$n/\phi$, can be found in the |prod| routine below.)
+
+The handy identity $x-y=\overline{\overline x+y}$ is used to reduce
+subtraction to addition.
+
+@<Internal...@>=
+static make_adder(n,x,y,z,carry,add)
+ unsigned n; /* number of bits */
+ Vertex *x[],*y[]; /* input gates */
+ Vertex *z[]; /* output gates */
+ Vertex *carry; /* add this to |y|, unless it's null */
+ char add; /* should we add or subtract? */
+{@+register int k;
+ Vertex *t1,*t2,*t3,*t4; /* temporary storage used by |do4| */
+ if (!carry) {
+ z[0]=make_xor(x[0],y[0]);
+ carry=make2(AND,signed(add,x[0]),y[0]);
+ k=1;
+ } else k=0;
+ for (;k<n;k++) {
+ comp(x[k]);@+comp(y[k]);@+comp(carry); /* generate inverse gates */
+ do4(z[k],OR,@t}\3{-5@>
+ make3(AND,x[k],comp(y[k]),comp(carry)),@t}\3{-5@>
+ make3(AND,comp(x[k]),y[k],comp(carry)),@t}\3{-5@>
+ make3(AND,comp(x[k]),comp(y[k]),carry),@t}\3{-5@>
+ make3(AND,x[k],y[k],carry));
+ do3(carry,OR,@t}\3{-5@>
+ make2(AND,signed(add,x[k]),y[k]),@t}\3{-5@>
+ make2(AND,signed(add,x[k]),carry),@t}\3{-5@>
+ make2(AND,y[k],carry));
+ }
+ z[n]=carry;
+}
+
+@ OK, now we can add. What good does that do us?
+In the first place, we need a 4-bit adder to compute the least
+significant bits of $|old_dest|+\.{SRC}$. The other 12 bits of that
+sum are simpler.
+
+@<Set |inc_dest| to |old_dest| plus \.{SRC}@>=
+make_adder(4,old_dest,mem,inc_dest,NULL,1);
+up=make2(AND,inc_dest[4],comp(mem[3])); /* remaining bits must increase */
+down=make2(AND,comp(inc_dest[4]),mem[3]); /* remaining bits must decrease */
+for (k=4;;k++) {
+ comp(up);@+comp(down);
+ do3(inc_dest[k],OR,@t}\3{-5@>
+ make2(AND,comp(old_dest[k]),up),@t}\3{-5@>
+ make2(AND,comp(old_dest[k]),down),@t}\3{-5@>
+ make3(AND,old_dest[k],comp(up),comp(down)));
+ if (k<15) {
+ up=make2(AND,up,old_dest[k]);
+ down=make2(AND,down,comp(old_dest[k]));
+ } else break;
+}
+
+@ @<Local variables for |risc|@>=
+Vertex *up,*down; /* gates used when computing |inc_dest| */
+
+@ In the second place, we need a 16-bit adder and a 16-bit subtracter
+for the four addition/subtraction commands.
+
+@<Create gates for the arithmetic operations@>=
+start_prefix("A");
+@<Create gates for the shift operations@>;
+make_adder(16,old_dest,source,sum,make2(AND,carry,mod[0]),1); /* adder */
+make_adder(16,old_dest,source,diff,make2(AND,carry,mod[0]),0); /* subtracter */
+do2(sum[17],OR,@t}\3{-5@>
+ make3(AND,old_dest[15],source[15],comp(sum[15])),@t}\3{-5@>
+ make3(AND,comp(old_dest[15]),comp(source[15]),sum[15])); /* overflow */
+do2(diff[17],OR,@t}\3{-5@>
+ make3(AND,old_dest[15],comp(source[15]),comp(diff[15])),@t}\3{-5@>
+ make3(AND,comp(old_dest[15]),source[15],diff[15])); /* overflow */
+
+@ @<Create gates for the shift operations@>=
+for (k=0;k<16;k++)@/
+ do4(shift[k],OR,@t}\3{-5@>
+ (k==0? make4(AND,source[15],mod[0],comp(mod[1]),comp(mod[2])):@t}\3{-5@>
+ @t\hskip5em@>make3(AND,source[k-1],comp(mod[1]),comp(mod[2]))),@t}\3{-5@>
+ (k<4? make4(AND,source[k+12],mod[0],mod[1],comp(mod[2])):@t}\3{-5@>
+ @t\hskip5em@>make3(AND,source[k-4],mod[1],comp(mod[2]))),@t}\3{-5@>
+ (k==15? make4(AND,source[15],comp(mod[0]),comp(mod[1]),mod[2]):@t}\3{-5@>
+ @t\hskip5em@>make3(AND,source[k+1],comp(mod[1]),mod[2])),@t}\3{-5@>
+ (k>11? make4(AND,source[15],comp(mod[0]),mod[1],mod[2]):@t}\3{-5@>
+ @t\hskip5em@>make3(AND,source[k+4],mod[1],mod[2])));
+do4(shift[16],OR,@t}\3{-5@>
+ make2(AND,comp(mod[2]),source[15]),@t}\3{-5@>
+ make3(AND,comp(mod[2]),mod[1],
+ make3(OR,source[14],source[13],source[12])),@t}\3{-5@>
+ make3(AND,mod[2],comp(mod[1]),source[0]),@t}\3{-5@>
+ make3(AND,mod[2],mod[1],source[3])); /* ``carry'' */
+do3(shift[17],OR,@t}\3{-5@>
+ make3(AND,comp(mod[2]),comp(mod[1]),
+ make_xor(source[15],source[14])),@t}\3{-5@>
+ make4(AND,comp(mod[2]),mod[1],@t}\3{-5@>
+ @t\hskip5em@>make5(OR,source[15],source[14],
+ source[13],source[12],source[11]),@t}\3{-5@>
+ @t\hskip5em@>make5(OR,comp(source[15]),comp(source[14]),
+ comp(source[13]),@t}\3{-5@>
+ @t\hskip10em@>comp(source[12]),comp(source[11]))),@t}\3{-5@>
+ make3(AND,mod[2],mod[1],
+ make3(OR,source[0],source[1],source[2]))); /* ``overflow'' */
+
+@* RISC management. The |run_risc| procedure takes a gate graph output by |risc|
+and simulates its behavior, given the contents of its read-only memory.
+(See the demonstration program |take_risc|, which appears in a module
+by itself, for a typical illustration of how |run_risc| might be used.)
+
+This procedure clears the simulated machine and begins executing the program
+that starts at address~0. It stops when it gets to an address greater
+than the size of read-only memory supplied. One way to stop it
+is therefore to execute a command such as |0x0f00|, which will transfer
+control to location |0xffff|; even better is |0x0f8f|, which transfers
+to location |0xffff| without changing the status of \.S and \.N.
+However, if the given read-only memory
+contains a full set of $2^{16}$ words, |run_risc| will never stop.
+
+When |run_risc| does stop, it returns 0 and puts the final contents of the
+simulated registers into the global array |risc_state|.
+Or, if |g| was not a decent graph, |run_risc| returns a negative value and
+leaves |risc_state| untouched.
+
+@<The |run_risc|...@>=
+int run_risc(g,rom,size,trace_regs)
+ Graph *g; /* graph output by |risc| */
+ unsigned rom[]; /* contents of read-only memory */
+ unsigned size; /* length of |rom| vector */
+ unsigned trace_regs; /* if nonzero, this many registers will be traced */
+{@+register unsigned l; /* memory address */
+ register unsigned m; /* memory or register contents */
+ register Vertex *v; /* the current gate of interest */
+ register Arc *a; /* the current output list element of interest */
+ register int k,r; /* general-purpose indices */
+ int x,s,n,c,o; /* status bits */
+ if (trace_regs) @<Print a headline@>;
+ m=gate_eval(g,"0",NULL); /* reset the RISC by turning off the \.{RUN} bit */
+ if (m<0) return m; /* not a valid gate graph! */
+ g->vertices->val=1; /* turn the \.{RUN} bit on */
+ while (1) {
+ for (a=g->outs,l=0;a;a=a->next) l=2*l+a->tip->val;
+ /* set $l=\null$memory address */
+ if (trace_regs) @<Print register contents@>;
+ if (l>=size) break; /* stop if memory check occurs */
+ for (v=g->vertices+1,m=rom[l];v<=g->vertices+16;v++,m>>=1)
+ v->val=m&1; /* store bits of memory word in the input gates */
+ gate_eval(g,NULL,NULL); /* do another RISC cycle */
+ }
+ if (trace_regs) @<Print a footline@>;
+ @<Dump the register contents into |risc_state|@>;
+ return 0;
+}
+
+@ If tracing is requested, we write on the standard output file.
+
+@<Print a headline@>=
+{
+ for (r=0;r<trace_regs;r++) printf(" r%-2d ",r); /* register names */
+ printf(" P XSNKV MEM\n"); /* |prog|, |extra|, status bits, memory */
+}
+
+@ @<Print a footline@>=
+printf("Execution terminated with memory address %04x.\n",l);
+
+@ Here we peek inside the circuit to see what values are about to
+be latched.
+
+@<Print register contents@>=
+{ for (r=0;r<trace_regs;r++) {
+ v=g->vertices+(16*r+47); /* most significant bit of register |r| */
+ m=0;
+ if (v->typ=='L')
+ for (k=0,m=0;k<16;k++,v--) m=2*m+v->alt->val;
+ printf("%04x ",m);
+ }
+ for (k=0,m=0,v=g->vertices+26;k<10;k++,v--) m=2*m+v->alt->val; /* |prog| */
+ x=(g->vertices+31)->alt->val; /* |extra| */
+ s=(g->vertices+27)->alt->val; /* |sign| */
+ n=(g->vertices+28)->alt->val; /* |nonzero| */
+ c=(g->vertices+29)->alt->val; /* |carry| */
+ o=(g->vertices+30)->alt->val; /* |overflow| */
+ printf("%03x%c%c%c%c%c ",m<<2,
+ x?'X':'.', s?'S':'.', n?'N':'.', c?'K':'.', o?'V':'.');
+ if (l>=size) printf("????\n");
+ else printf("%04x\n",rom[l]);
+}
+
+@ @<Dump...@>=
+for (r=0;r<16;r++) {
+ v=g->vertices+(16*r+47); /* most significant bit of register |r| */
+ m=0;
+ if (v->typ=='L')
+ for (k=0,m=0;k<16;k++,v--) m=2*m+v->alt->val;
+ risc_state[r]=m;
+}
+for (k=0,m=0,v=g->vertices+26;k<10;k++,v--) m=2*m+v->alt->val; /* |prog| */
+m=4*m+(g->vertices+31)->alt->val; /* |extra| */
+m=2*m+(g->vertices+27)->alt->val; /* |sign| */
+m=2*m+(g->vertices+28)->alt->val; /* |nonzero| */
+m=2*m+(g->vertices+29)->alt->val; /* |carry| */
+m=2*m+(g->vertices+30)->alt->val; /* |overflow| */
+risc_state[16]=m; /* program register and status bits go here */
+risc_state[17]=l; /* this is the out-of-range address that caused termination */
+
+@ @<Global variables@>=
+unsigned risc_state[18];
+
+@*Generalized gate graphs. For intermediate computations it is
+convenient to allow two additional types of gates:
+{\advance\parindent 2em
+\smallskip
+\item{|'C'|} denotes a constant gate of value |z.i|.
+
+\smallskip
+\item{|'='|} denotes a copy of a previous gate; utility field |alt|
+points to that previous gate.
+
+\smallskip}\noindent
+Such gates might appear anywhere in the graph, possibly interspersed with
+the inputs and latches.
+
+Here is a simple subroutine that prints a symbolic representation of
+a generalized gate graph on the standard output file:
+
+@d bit z.i /* field containing the constant value of a |'C'| gate */
+
+@<The |print_gates| routine@>=
+static print_gate(v)
+ Vertex *v;
+{@+register int t;
+ register Arc *a;
+ printf("%s = ",v->name);
+ switch(v->typ) {
+ case 'I':printf("input");@+break;
+ case 'L':printf("latch");
+ if (v->alt) printf("ed %s",v->alt->name);
+ break;
+ case '~':printf("~ ");@+break;
+ case 'C':printf("constant %d",v->bit); break;
+ case '=':printf("copy of %s",v->alt->name);
+ }
+ for (a=v->arcs;a;a=a->next) {
+ if (a!=v->arcs) printf(" %c ",v->typ);
+ printf(a->tip->name);
+ }
+ printf("\n");
+}
+@#
+print_gates(g)
+ Graph *g;
+{@+register Vertex *v;
+ register Arc *a;
+ for (v=g->vertices;v<g->vertices+g->n;v++) print_gate(v);
+ for (a=g->outs;a;a=a->next)
+ if (is_boolean(a->tip)) printf("Output %d\n",the_boolean(a->tip));
+ else printf("Output %s\n",a->tip->name);
+}
+
+@ @(gb_gates.h@>=
+#define bit @t\quad@> z.i
+
+@ The |reduce| routine takes a generalized graph |g| and uses the identities
+$$\openup1\jot
+\vbox{\halign{\hfil$x#0=\null$&$#$,\hfil\quad
+ &\hfil$x#1=\null$&$#$,\hfil\quad
+ &\hfil$x#x=\null$&$#$,\hfil\quad
+ &\hfil$x#\overline x=\null$&$#$,\hfil\cr
+\land&0&\land&x&\land&x&\land&0\cr
+\lor&x&\lor&1&\lor&x&\lor&1\cr
+\oplus&x&\oplus&\overline x&\oplus&0&\oplus&1\cr}}$$
+and $\overline{\overline x}=x$ to create an equivalent graph having no
+|'C'| or |'='| or obviously redundant gates. The reduced graph also excludes
+any gates that are not used directly or indirectly in the computation of
+the output values.
+
+@<Internal...@>=
+static Graph* reduce(g)
+ Graph *g;
+{@+register Vertex *u, *v; /* the current vertices of interest */
+ register Arc *a, *b; /* the current arcs of interest */
+ Arc *aa, *bb; /* their predecessors */
+ Vertex *latch_ptr; /* top of the latch list */
+ long n=0; /* the number of marked gates */
+ Graph *new_graph; /* the reduced gate graph */
+ Vertex *next_vert=NULL, *max_next_vert=NULL; /* allocation of new vertices */
+ Arc *avail_arc=NULL; /* list of recycled arcs */
+ Vertex *sentinel; /* end of the vertices */
+ if (g==NULL) panic(missing_operand); /* where is |g|? */
+ sentinel=g->vertices+g->n;
+ while (1) {
+ latch_ptr=NULL;
+ for (v=g->vertices;v<sentinel;v++)
+ @<Reduce gate |v|, if possible, or put it on the latch list@>;
+ @<Check to see if any latch has become constant; if not, |break|@>;
+ }
+ @<Mark all gates that are used in some output@>;
+ @<Copy all marked gates to a new graph@>;
+ gb_recycle(g);
+ return new_graph;
+}
+
+@ We will link latches together via their |v.v| fields.
+
+@<Check to see if any latch has become constant; if not, |break|@>=
+{@+char no_constants_yet=1;
+ for (v=latch_ptr;v;v=v->v.v) {
+ u=v->alt; /* the gate whose value will be latched */
+ if (u->typ=='=')
+ v->alt=u->alt;
+ else if (u->typ=='C') {
+ v->typ='C';@+v->bit=u->bit;@+no_constants_yet=0;
+ }
+ }
+ if (no_constants_yet) break;
+}
+
+@ @d foo x.v /* link field used to find all the gates later */
+
+@<Reduce gate |v|, if possible, or put it on the latch list@>=
+{
+ switch(v->typ) {
+ case 'L': v->v.v=latch_ptr;@+latch_ptr=v;@+break;
+ case 'I': case 'C': break;
+ case '=': u=v->alt;
+ if (u->typ=='=')
+ v->alt=u->alt;
+ else if (u->typ=='C') {
+ v->bit=u->bit;@+goto make_v_constant;
+ }
+ break;
+ case AND:@<Try to reduce an {\sc AND} gate@>;@+goto test_single_arg;
+ case OR:@<Try to reduce an {\sc OR} gate@>;@+goto test_single_arg;
+ case XOR:@<Try to reduce an {\sc EXCLUSIVE-OR} gate@>;
+ @+goto test_single_arg;
+ case NOT:@<Try to reduce an inverter@>;@+break;
+ test_single_arg: if (v->arcs->next) break;
+ v->alt=v->arcs->tip;
+ make_v_eq: v->typ='='; goto make_v_arcless;
+ make_v_1: v->bit=1;@+goto make_v_constant;
+ make_v_0: v->bit=0;
+ make_v_constant: v->typ='C';
+ make_v_arcless: v->arcs=NULL;
+ }
+v->bar=NULL; /* this field will point to the complement, if computed later */
+done: v->foo=v+1; /* this field will link all the vertices together */
+}
+
+@ @<Try to reduce an inverter@>=
+u=v->arcs->tip;
+if (u->typ=='=')
+ u=v->arcs->tip=u->alt;
+if (u->typ=='C') {
+ v->bit=1-u->bit;@+goto make_v_constant;
+} else if (u->bar) { /* this inverse already computed */
+ v->alt=u->bar;@+goto make_v_eq;
+} else {
+ u->bar=v;@+v->bar=u;@+goto done;
+}
+
+@ @<Try to reduce an {\sc AND} gate@>=
+for (a=v->arcs,aa=NULL;a;a=a->next) {
+ u=a->tip;
+ if (u->typ=='=')
+ u=a->tip=u->alt;
+ if (u->typ=='C') {
+ if (u->bit==0) goto make_v_0;
+ goto bypass_arg_of_and;
+ } else for (b=v->arcs;b!=a;b=b->next) {
+ if (b->tip==u) goto bypass_arg_of_and;
+ if (b->tip==u->bar) goto make_v_0;
+ }
+ aa=a;@+continue;
+bypass_arg_of_and: if (aa) aa->next=a->next;
+ else v->arcs=a->next;
+}
+if (v->arcs==NULL) goto make_v_1;
+
+@ @<Try to reduce an {\sc OR} gate@>=
+for (a=v->arcs,aa=NULL;a;a=a->next) {
+ u=a->tip;
+ if (u->typ=='=')
+ u=a->tip=u->alt;
+ if (u->typ=='C') {
+ if (u->bit) goto make_v_1;
+ goto bypass_arg_of_or;
+ } else for (b=v->arcs;b!=a;b=b->next) {
+ if (b->tip==u) goto bypass_arg_of_or;
+ if (b->tip==u->bar) goto make_v_1;
+ }
+ aa=a;@+continue;
+bypass_arg_of_or: if (aa) aa->next=a->next;
+ else v->arcs=a->next;
+}
+if (v->arcs==NULL) goto make_v_0;
+
+@ @<Try to reduce an {\sc EXCLUSIVE-OR} gate@>=
+{@+int cmp=0;
+ for (a=v->arcs,aa=NULL;a;a=a->next) {
+ u=a->tip;
+ if (u->typ=='=')
+ u=a->tip=u->alt;
+ if (u->typ=='C') {
+ if (u->bit) cmp=1-cmp;
+ goto bypass_arg_of_xor;
+ } else for (bb=NULL,b=v->arcs;b!=a;b=b->next) {
+ if (b->tip==u) goto double_bypass;
+ if (b->tip==u->bar) {
+ cmp=1-cmp;
+ goto double_bypass;
+ }
+ bb=b;@+ continue;
+ double_bypass: if (bb) bb->next=b->next;
+ else v->arcs=b->next;
+ goto bypass_arg_of_xor;
+ }
+ aa=a;@+ continue;
+ bypass_arg_of_xor: if (aa) aa->next=a->next;
+ else v->arcs=a->next;
+ a->a.a=avail_arc;
+ avail_arc=a;
+ }
+ if (v->arcs==NULL) {
+ v->bit=cmp;
+ goto make_v_constant;
+ }
+ if (cmp) @<Complement one argument of |v|@>;
+}
+
+@ @<Complement one argument of |v|@>=
+{
+ for (a=v->arcs;;a=a->next) {
+ u=a->tip;
+ if (u->bar) break; /* good, the complement is already known */
+ if (a->next==NULL) { /* oops, this is our last chance */
+ @<Create a new vertex for complement of |u|@>;
+ break;
+ }
+ }
+ a->tip=u->bar;
+}
+
+@ Here we've come to a subtle point: The ``reduced'' graph might
+actually be larger than the original, in the sense of having more
+vertices (although fewer arcs), if there are a lot of |XOR| gates
+involving an input that is set to the constant value~1. Therefore
+we must have the ability to allocate new vertices during the
+reduction phase of |reduce|. At least one arc has been added to
+the |avail_arc| list whenever we reach this portion of the program.
+
+@<Create a new vertex for complement of |u|@>=
+if (next_vert==max_next_vert) {
+ next_vert=gb_alloc_type(7,@[Vertex@],g->aux_data);
+ if (next_vert==NULL) {
+ gb_recycle(g);
+ panic(no_room+1); /* can't get auxiliary storage! */
+ }
+ max_next_vert=next_vert+7;
+}
+next_vert->typ=NOT;
+sprintf(name_buf,"%s~",u->name);
+next_vert->name=gb_save_string(name_buf);
+next_vert->arcs=avail_arc; /* this is known to be non-|NULL| */
+avail_arc->tip=u;
+avail_arc=avail_arc->a.a;
+next_vert->arcs->next=NULL;
+next_vert->bar=u;
+next_vert->foo=u->foo;
+u->foo=u->bar=next_vert++;
+
+@ During the marking phase, we will use the |w.v| field to link the
+list of nodes-to-be-marked. That field will turn out to be non-|NULL|
+only in the marked nodes. (We no longer use its former meaning related
+to complementation, so we call it |lnk| instead of |bar|.)
+
+@d lnk w.v /* stack link for marking */
+
+@<Mark all gates that are used in some output@>=
+{
+ for (v=g->vertices;v!=sentinel;v=v->foo) v->lnk=NULL;
+ for (a=g->outs;a;a=a->next) {
+ v=a->tip;
+ if (is_boolean(v)) continue;
+ if (v->typ=='=')
+ v=a->tip=v->alt;
+ if (v->typ=='C') { /* this output is constant, so make it boolean */
+ a->tip=(Vertex*)v->bit;
+ continue;
+ }
+ @<Mark all gates that are used to compute |v|@>;
+ }
+}
+
+@ @<Mark all gates that are used to compute |v|@>=
+if (v->lnk==NULL) {
+ v->lnk=sentinel; /* |v| will now be the top of stack of nodes to be marked */
+ do {
+ n++;
+ b=v->arcs;
+ if (v->typ=='L') {
+ u=v->alt; /* latch vertices have a ``hidden'' dependency */
+ if (u<v) n++; /* latched input value will get a special gate */
+ if (u->lnk==NULL) {
+ u->lnk=v->lnk;
+ v=u;
+ } else v=v->lnk;
+ } else v=v->lnk;
+ for (;b;b=b->next) {
+ u=b->tip;
+ if (u->lnk==NULL) {
+ u->lnk=v;
+ v=u;
+ }
+ }
+ } while (v!=sentinel);
+}
+
+@ It is easier to copy a directed acyclic graph than to copy a general graph,
+but we do have to contend with the feedback in latches.
+
+@d reverse_arc_list(@!alist)
+ {@+for (aa=alist,b=NULL;aa;b=aa,aa=a) {
+ a=aa->next;
+ aa->next=b;
+ }
+ alist=b;@+}
+
+@<Copy all marked gates to a new graph@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL) {
+ gb_recycle(g);
+ panic(no_room+2); /* out of memory */
+}
+strcpy(new_graph->id,g->id);
+strcpy(new_graph->format,"ZZZIIVZZZZZZZA");
+next_vert=new_graph->vertices;
+for (v=g->vertices,latch_ptr=NULL;v!=sentinel;v=v->foo) {
+ if (v->lnk) { /* yes, |v| is marked */
+ u=v->lnk=next_vert++; /* make note of where we've copied it */
+ @<Make |u| a copy of |v|; put it on the latch list if it's a latch@>;
+ }
+}
+@<Fix up the |alt| fields of the newly copied latches@>;
+reverse_arc_list(g->outs);
+for (a=g->outs;a;a=a->next) {
+ b=gb_virgin_arc();
+ b->tip=is_boolean(a->tip)? a->tip: a->tip->lnk;
+ b->next=new_graph->outs;
+ new_graph->outs=b;
+}
+
+@ @<Make |u| a copy of |v|; put it on the latch list if it's a latch@>=
+u->name=gb_save_string(v->name);
+u->typ=v->typ;
+if (v->typ=='L') {
+ u->alt=latch_ptr;@+latch_ptr=v;
+}
+reverse_arc_list(v->arcs);
+for (a=v->arcs;a;a=a->next)
+ gb_new_arc(u,a->tip->lnk,a->len);
+
+@ @<Fix up the |alt| fields of the newly copied latches@>=
+while (latch_ptr) {
+ u=latch_ptr->lnk; /* the copy of a latch */
+ v=u->alt;
+ u->alt=latch_ptr->alt->lnk;
+ latch_ptr=v;
+ if (u->alt<u) @<Replace |u->alt| by a new gate that copies an input@>;
+}
+
+@ Suppose we had a latch whose value was originally the {\sc AND} of
+two inputs, where one of those inputs has now been set to~1. Then the
+latch should still refer to a subsequent gate, equal to value of the
+other input on the previous cycle. We create such a gate here, making
+it an {\sc OR} of two identical inputs, because we're not supposed to
+leave any |'='| in the result of |reduce|, and because every {\sc OR}
+is supposed to have at least two inputs.
+
+@<Replace |u->alt| by a new gate that copies an input@>=
+{
+ v=u->alt; /* the input gate that should be copied for latching */
+ u->alt=next_vert++;
+ sprintf(name_buf,"%s>%s",v->name,u->name);
+ u=u->alt;
+ u->name=gb_save_string(name_buf);
+ u->typ=OR;
+ gb_new_arc(u,v,DELAY);@+gb_new_arc(u,v,DELAY);
+}
+
+@* Parallel multiplication. Now comes the |prod| routine,
+which constructs a rather different network of gates, based this time
+on a divide-and-conquer paradigm. Let's take a breater before we tackle it.
+
+(Deep breath.)
+
+The subroutine call |prod(m,n)| creates
+a network for the binary multiplication of unsigned
+|m|-bit numbers by |n|-bit numbers, assuming that |m>=2| and |n>=2|.
+There is no upper limit on the sizes of |m| and~|n|, except of course
+the limits imposed by the size of memory in which this routine is run.
+
+The overall strategy used by |prod| is to start with a generalized
+gate graph for multiplication in which many of the gates are
+identically zero or copies of other gates. Then the |reduce| routine
+will perform local optimizations leading to the desired result. Since
+there are no latches, some of the complexities of the general |reduce|
+routine are avoided.
+
+All of the |AND|, |OR|, and |XOR| gates of the network returned by
+|prod| have exactly two inputs. The depth of the circuit (i.e., the
+length of its longest path) is $3\log m/\!\log 1.5 + \log(m+n)/\!\log\phi
++O(1)$, where $\phi=(1+\sqrt5\,)/2$ is the golden ratio. The total number
+of gates is $6mn+5m^2+O\bigl((m+n)\log(m+n)\bigr)$.
+
+There is a demonstration program called |multiply| that uses |prod| to
+compute products of large integers.
+
+@<The |prod| routine@>=
+Graph* prod(m,n)
+ unsigned m,n; /* lengths of the binary numbers to be multiplied */
+{@+@<Local variables for |prod|@>@;
+@#
+ if (m<2) m=2;
+ if (n<2) n=2;
+ @<Allocate space for a temporary graph |g| and for auxiliary tables@>;
+ @<Fill |g| with generalized gates that do parallel multiplication@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(g);@+panic(alloc_fault); /* too big */
+ }
+ g=reduce(g);
+ return g; /* if |g==NULL|, the |panic_code| was set by |reduce| */
+}
+
+@ The divide-and-conquer recurrences used in this network lead to interesting
+patterns. First we use a method for parallel column addition that reduces
+the sum of three numbers to the sum of two numbers; repeated use of this
+reduction makes it possible to reduce the sum of |m| numbers to a sum of
+just two numbers, with a total circuit depth that satisfies the
+recurrence $T(3N)=T(2N)+O(1)$. Secondly, when the result has been reduced
+to a sum of two numbers, we use a parallel addition scheme based on
+recursively ``golden sectioning the data''; in other words, the recursion
+partitions the data into two parts such that the ratio of the larger part
+to the smaller part is approximately $\phi$. This technique proves to be
+slightly better than a binary partition would be, both asymptotically and
+for small values of~$m+n$.
+
+\def\flog{\mathop{\rm flog}\nolimits}
+We define $\flog N$, the Fibonacci logarithm of~$N$, to be the smallest
+nonnegative integer~$k$ such that $N\le F_{k+1}$. Let $N=m+n$. Our parallel
+adder for two numbers of $N$ bits will turn out to have depth at most
+$2+\flog N$. The unreduced graph~|g| in our circuit for multiplication
+will have fewer than $(6m+3\flog N)N$ gates.
+
+@<Allocate space for a temporary graph |g| and for auxiliary tables@>=
+m_plus_n=m+n;@+@<Compute $f=\flog(m+n)$@>;
+g=gb_new_graph((6*m-7+3*f)*m_plus_n);
+if (g==NULL) panic(no_room); /* out of memory before we're even started */
+sprintf(g->id,"prod(%u,%u)",m,n);
+strcpy(g->format,"ZZZIIVZZZZZZZA");
+long_tables=gb_alloc_type(2*m_plus_n+f,@[long@],g->aux_data);
+vert_tables=gb_alloc_type(f*m_plus_n,@[Vertex*@],g->aux_data);
+if (gb_alloc_trouble) {
+ gb_recycle(g);
+ panic(no_room+1); /* out of memory trying to create auxiliary tables */
+}
+
+@ @<Local variables for |prod|@>=
+unsigned m_plus_n; /* guess what this variable holds */
+int f; /* initially $\flog(m+n)$, later flog of other things */
+Graph *g; /* graph of generalized gates, to be reduced eventually */
+long *long_tables; /* beginning of auxiliary array of |long| numbers */
+Vertex **vert_tables; /* beginning of auxiliary array of gate pointers */
+
+@ @<Compute $f=\flog(m+n)$@>=
+f=4;@+j=3;@+k=5; /* $j=F_f$, $k=F_{f+1}$ */
+while (k<m_plus_n) {
+ k=k+j;
+ j=k-j;
+ f++;
+}
+
+@ The well-known formulas for a ``full adder,''
+$$ x+y+z=s+2c,\qquad
+ \hbox{where $s=x\oplus y\oplus z$ and $c=xy\lor yz\lor zx$},$$
+can be applied to each bit of an $N$-bit number, thereby providing us
+with a way to reduce the sum of three numbers to the sum of two.
+
+The input gates of our network will be called $x_0$, $x_1$, \dots,~$x_{m-1}$,
+$y_0$,~$y_1$, \dots,~$y_{n-1}$, and the outputs will be called
+$z_0$, $z_1$, \dots,~$z_{m+n-1}$. The logic of the |prod| network will compute
+$$(z_{m+n-1}\ldots z_1z_0)_2=(x_{m-1}\ldots x_1x_0)_2\cdot
+ (y_{n-1}\ldots y_1y_0)_2\,,$$
+by first considering the product to be the $m$-fold sum
+$A_0+A_1+\cdots+A_{m-1}$, where
+$$A_j=2^jx_j\cdot(y_{n-1}\ldots y_1y_0)_2\,,\qquad 0\le j<m.$$
+Then the three-to-two rule for addition is used to define further
+numbers $A_m$, $A_{m+1}$, \dots,~$A_{3m-5}$ by the scheme
+$$A_{m+2j}+A_{m+2j+1}=A_{3j}+A_{3j+1}+A_{3j+2}\,,\qquad 0\le j\le m-3.$$
+[A similar but slightly less efficient scheme was used by Pratt and
+Stockmeyer in {\sl Journal of Computer and System Sciences \bf12} (1976),
+Proposition~5.3. The recurrence used here is related to the Josephus
+problem with step-size~3; see {\sl Concrete Mathematics},
+{\mathhexbox278}3.3.]
+For this purpose we compute intermediate results $P_j$, $Q_j$, and~$R_j$
+by the rules
+$$\eqalign{P_j&=A_{3j}\oplus A_{3j+1}\,;\cr
+ Q_j&=A_{3j}\land A_{3j+1}\,;\cr
+ A_{m+2j}&=P_j\oplus A_{3j+2}\,;\cr
+ R_j&=P_j\land A_{3j+2}\,;\cr
+ A_{m+2j+1}&=2(Q_j\lor R_j)\,.\cr}$$
+Finally we let
+$$\eqalign{U&=A_{3m-6}\oplus A_{3m-5}\,,\cr
+ V&=A_{3m-6}\land A_{3m-5}\,;\cr}$$
+these are the values that would be $P_{m-2}$ and $Q_{m-2}$ if the previous
+formulas were allowed to run past $j=m-3$. The final result
+$Z=(z_{m+n-1}\ldots z_1z_0)_2$ can now be expressed as
+$$Z=U+2V\,.$$
+
+The gates of the first part of the network are conveniently obtained
+in groups of $N=m+n$, representing the bits of the quantities $A_j$,
+$P_j$, $Q_j$, $R_j$, $U$, and~$V$. We will put the least significant bit
+of $A_j$ in gate position |g->vertices+a(j)*N|, where $a(j)=j+1$ for
+$0\le j<m$ and $a(m+2j+t)=m+5j+3+2t$ for $0\le j\le m-3$, $0\le t\le1$.
+
+@<Fill |g| with generalized gates that do parallel multiplication@>=
+next_vert=g->vertices;
+start_prefix("X");@+x=first_of(m,'I');
+start_prefix("Y");@+y=first_of(n,'I');
+@<Define $A_j$ for $0\le j<m$@>;
+@<Define $P_j$, $Q_j$, $A_{m+2j}$, $R_j$, and $A_{m+2j+1}$
+ for $0\le j\le m-3$@>;
+@<Define $U$ and $V$@>;
+@<Compute the final result $Z$ by parallel addition@>;
+
+@ @<Local variables for |prod|@>=
+register int i,j,k,l; /* all-purpose indices */
+register Vertex *v; /* current vertex of interest */
+Vertex *x,*y; /* least-significant bits of the input gates */
+Vertex *alpha,*beta; /* least-significant bits of arguments */
+
+@ @<Define $A_j$ for $0\le j<m$@>=
+for (j=0; j<m; j++) {
+ numeric_prefix('A',j);
+ for (k=0; k<j; k++) {
+ v=new_vert('C');@+v->bit=0; /* this gate is the constant 0 */
+ }
+ for (k=0; k<n; k++)
+ make2(AND,x+j,y+k);
+ for (k=j+n; k<m_plus_n; k++) {
+ v=new_vert('C');@+v->bit=0; /* this gate is the constant 0 */
+ }
+}
+
+@ Since |m| is |unsigned|, it is necessary to say `|j<m-2|' here instead
+of `|j<=m-3|'.
+
+@d a_pos(j) (j<m? j+1: m+5*((j-m)>>1)+3+(((j-m)&1)<<1))
+
+@<Define $P_j$, $Q_j$, $A_{m+2j}$, $R_j$, and $A_{m+2j+1}$...@>=
+for (j=0; j<m-2; j++) {
+ alpha=g->vertices+(a_pos(3*j)*m_plus_n);
+ beta=g->vertices+(a_pos(3*j+1)*m_plus_n);
+ numeric_prefix('P',j);
+ for (k=0; k<m_plus_n; k++)
+ make2(XOR,alpha+k,beta+k);
+ numeric_prefix('Q',j);
+ for (k=0; k<m_plus_n; k++)
+ make2(AND,alpha+k,beta+k);
+ alpha=next_vert-2*m_plus_n;
+ beta=g->vertices+(a_pos(3*j+2)*m_plus_n);
+ numeric_prefix('A',m+2*j);
+ for (k=0; k<m_plus_n; k++)
+ make2(XOR,alpha+k,beta+k);
+ numeric_prefix('R',j);
+ for (k=0; k<m_plus_n; k++)
+ make2(AND,alpha+k,beta+k);
+ alpha=next_vert-3*m_plus_n;
+ beta=next_vert-m_plus_n;
+ numeric_prefix('A',m+2*j+1);
+ v=new_vert('C');@+v->bit=0; /* another 0, it multiplies $Q\lor R$ by 2 */
+ for (k=0; k<m_plus_n-1; k++)
+ make2(OR,alpha+k,beta+k);
+}
+
+@ Actually $v_{m+n-1}$ will never be used (it has to be zero); but we
+compute it anyway. We don't have to worry about such nitty gritty details
+because |reduce| will get rid of all the obvious redundancy.
+
+@<Define $U$ and $V$@>=
+alpha=g->vertices+(a_pos(3*m-6)*m_plus_n);
+beta=g->vertices+(a_pos(3*m-5)*m_plus_n);
+start_prefix("U");
+for (k=0; k<m_plus_n; k++)
+ make2(XOR,alpha+k,beta+k);
+start_prefix("V");
+for (k=0; k<m_plus_n; k++)
+ make2(AND,alpha+k,beta+k);
+
+@* Parallel addition. It's time now to take a deep breath; we have finished the
+parallel multiplier except for one last step, the design of a parallel
+adder.
+
+The adder is based on the following theory:
+We want to perform the binary addition
+$$\vbox{\halign{\hfil$#$&&\ \hfil$#$\cr
+ u_{N-1}&\ldots&u_2&u_1&u_0\cr
+ v_{N-2}&\ldots&v_1&v_0\cr
+\noalign{\kern2pt\hrule\kern4pt}
+ z_{N-1}&\ldots&z_2&z_1&z_0\cr}}$$
+where we know that $u_k+v_k\le1$ for all~$k$. It follows that $z_k=u_k\oplus
+w_k$, where $w_0=0$ and
+$$ w_k\;=\;v_{k-1}\;\lor\;u_{k-1}v_{k-2}\;\lor\;u_{k-1}u_{k-2}v_{k-3}\;\lor
+ \;\cdots\;\lor\;u_{k-1}\ldots u_1v_0$$
+for $k>0$. The problem has therefore been reduced to the evaluation
+of $w_1$, $w_2$, \dots, $w_{N-1}$.
+
+Let $c_k^{\,j}$ denote the {\sc OR} of the first $j$ terms in the formula
+that defines $w_k$, and let $d_k^{\,j}$ denote the $j$-fold product
+$u_{k-1}u_{k-2}\ldots u_{k-j}$.
+Then $w_k=c_k^k$, and we can use a recursive scheme of the form
+$$c_k^{\,j}=c_k^{\,i}\lor d_k^{\,i}c_{k-i}^{\,j-i}\,,\qquad
+ d_k^{\,j}=d_k^{\,i}d_{k-i}^{\,j-i}\,,\qquad j\ge2,$$
+to do the evaluation.
+
+\def\down{\mathop{\rm down}}
+It turns out that this recursion behaves very nicely if we choose
+$i=\down[j]$, where $\down[j]$ is defined for $j>1$ by the formula
+$$\down[j]\;=\;j-F_{(\flog j)-1}\,.$$
+For example, we have $\flog18=7$ because $F_7=13<18\le21=F_8$,
+hence $\down[18]=18-F_6=10$.
+
+Let us write $j\to\down[j]$, and consider the oriented tree on the set
+of all positive integers that is defined by this relation. One of the
+paths in this tree is, for example, $18\to10\to5\to3\to2\to1$. Our
+recurrence for $w_{18}=c_{18}^{18}$ involves $c_{18}^{10}$, which
+involves $c_{18}^5$, which involves $c_{18}^3$, and so on; in general,
+we will compute $c_k^{\,j}$ for all $j$ with $k\to^*j$, and we will
+compute $d_k^{\,j}$ for all $j$ with $k\to^+j$. It is not difficult to
+prove that $$k\;\to^*\;j\;\to\;i\qquad\hbox{implies}\qquad
+k-i\;\to^*\;j-i\,;$$ therefore the auxiliary factors $c_{k-i}^{\,j-i}$
+and $d_{k-i}^{\,j-i}$ needed in the recurrence scheme will already
+have been evaluated. (Indeed, one can prove more: Let $l=\flog k$. If
+the complete path from $k$ to~$1$ in the tree is $k=k_0\to
+k_1\to\cdots\to k_t=1$, then the differences $k_0-k_1$, $k_1-k_2$,
+\dots, $k_{t-2}-k_{t-1}$ will consist of precisely the Fibonacci
+numbers $F_{l-1}$, $F_{l-2}$, \dots,~$F_2$ except for the numbers that
+appear when $F_{l+1}-k$ is written as a sum of non-consecutive
+Fibonacci numbers.)
+
+It can also be shown that, when $k>1$, we have
+$$\flog k=\min_{0<j<n}\,\max\bigl(1+\flog j,\,2+\flog(k-j)\bigr)\,,$$
+and that $\down[k]$ is the smallest~$j$ such that the minimum is
+achieved in this equation. Therefore the depth of the circuit for
+computing $w_k$ from the $u$'s and~$v$'s is exactly $\flog k$.
+
+In particular, we can be sure that at most $3\flog N$ gates will be
+created when computing $z_k$, and that there will be at most $3N\flog N$
+gates in the parallel addition portion of the circuit.
+
+@<Compute the final result $Z$ by parallel addition@>=
+@<Set up auxiliary tables to handle Fibonacci-based recurrences@>;
+@<Create the gates for $W$, remembering intermediate results that
+ might be reused later@>;
+@<Compute the last gates $Z=U\oplus W$, and record their locations
+ as outputs of the network@>;
+g->n=next_vert-g->vertices; /* reduce to the actual number of gates used */
+
+@ When we have created a gate for $w_k$, we will store its address as
+the value of $w[k]$ in an auxiliary table. When we've created a gate
+for $c_k^{\,i}$ where $i<k$ is a Fibonacci number~$F_{l+1}$ and $l=\flog i\ge2$,
+we will store its address as the value of $c[k+(l-2)N]$; the gate
+$d_k^{\,i}$ will immediately follow this one. Tables of $\flog j$ and $\down[j]$
+will facilitate all these manipulations.
+
+@<Set up auxiliary tables to handle Fibonacci-based recurrences@>=
+w=vert_tables;
+c=w+m_plus_n;
+flog=long_tables;
+down=flog+m_plus_n+1;
+anc=down+m_plus_n;
+flog[1]=0;@+flog[2]=2;
+down[1]=0;@+down[2]=1;
+for (i=3,j=2,k=3,l=3; l<=m_plus_n; l++) {
+ if (l>k) {
+ k=k+j;
+ j=k-j;
+ i++; /* $F_i=j<l\le k=F_{i+1}$ */
+ }
+ flog[l]=i;
+ down[l]=l-k+j;
+}
+
+@ @<Local variables for |prod|@>=
+Vertex *uu, *vv; /* pointer to $u_0$ and $v_0$ */
+Vertex **w; /* table of pointers to $w_k$ */
+Vertex **c; /* table of pointers to potentially
+ important intermediate values $c_k^{\,i}$ */
+Vertex *cc,*dd; /* pointers to $c_k^{\,i}$ and $d_k^{\,i}$ */
+long *flog; /* table of flog values */
+long *down; /* table of down values */
+long *anc; /* table of ancestors of the current $k$ */
+
+@ @<Create the gates for $W$, remembering intermediate results that
+ might be reused later@>=
+vv=next_vert-m_plus_n;@+uu=vv-m_plus_n;
+start_prefix("W");
+v=new_vert('C');@+v->bit=0;@+w[0]=v; /* $w_0=0$ */
+v=new_vert('=');@+v->alt=vv;@+w[1]=v; /* $w_1=v_0$ */
+for (k=2;k<m_plus_n;k++) {
+ @<Set the |anc| table to a list of the ancestors of |k| in decreasing order,
+ stopping with |anc[l]=2|@>;
+ i=1;@+cc=vv+k-1;@+dd=uu+k-1;
+ while (1) {
+ j=anc[l]; /* now $i=\down[j]$ */
+ @#
+ @<Compute the gate $b_k^{\,j}=d_k^{\,i}\land c_{k-i}^{\,j-i}$@>;
+ @<Compute the gate $c_k^{\,j}=c_k^{\,i}\lor b_k^{\,j}$@>;
+ if (flog[j]<flog[j+1]) /* $j$ is a Fibonacci number */
+ c[k+(flog[j]-2)*m_plus_n]=v;
+ if (l==0) break;
+ cc=v;
+ @<Compute the gate $d_k^{\,j}=d_k^{\,i}\land d_{k-i}^{\,j-i}$@>;
+ dd=v;
+ i=j;
+ l--;
+ }
+ w[k]=v;
+}
+
+@ If $k\to j$ we call $j$ an ``ancestor'' of $k$ because we are thinking
+of the tree defined by `$\to$'; this tree is rooted at $2\to1$.
+
+@<Set the |anc| table to a list of the ancestors of |k| in decreasing order,
+ stopping with |anc[l]=2|@>=
+for (l=0,j=k;;l++,j=down[j]) {
+ anc[l]=j;
+ if (j==2) break;
+}
+
+@ @d spec_gate(v,a,k,j,t)
+ v=next_vert++;
+ sprintf(name_buf,"%c%d:%d",a,k,j);
+ v->name=gb_save_string(name_buf);
+ v->typ=t;
+
+@<Compute the gate $b_k^{\,j}=d_k^{\,i}\land c_{k-i}^{\,j-i}$@>=
+spec_gate(v,'B',k,j,AND);
+gb_new_arc(v,dd,DELAY); /* first argument is $d_k^{\,i}$ */
+f=flog[j-i]; /* get ready to compute the second argument, $c_{k-i}^{\,j-i}$ */
+gb_new_arc(v,f>0? c[k-i+(f-2)*m_plus_n]:vv+k-i-1,DELAY);
+
+@ @<Compute the gate $c_k^{\,j}=c_k^{\,i}\lor b_k^{\,j}$@>=
+if (l) {
+ spec_gate(v,'C',k,j,OR);
+} else v=new_vert(OR); /* if $l$ is zero, this gate is $c_k^k=w_k$ */
+gb_new_arc(v,cc,DELAY); /* first argument is $c_k^{\,i}$ */
+gb_new_arc(v,next_vert-2); /* second argument is $b_k^{\,j}$ */
+
+@ Here we reuse the value $f=\flog(j-i)$ computed a minute ago.
+
+@<Compute the gate $d_k^{\,j}=d_k^{\,i}\land d_{k-i}^{\,j-i}$@>=
+spec_gate(v,'D',k,j,AND);
+gb_new_arc(v,dd,DELAY); /* first argument is $d_k^{\,i}$ */
+gb_new_arc(v,f>0? c[k-i+(f-2)*m_plus_n]+1:uu+k-i-1,DELAY);
+ /* $d_{k-i}^{\,j-i}$ */
+
+@ The output list will contain the gates in ``big-endian order''
+$z_{m+n-1}$ \dots, $z_1$, $z_0$, because we insert them into the
+|outs| list in little-endian order.
+
+@<Compute the last gates $Z=U\oplus W$...@>=
+start_prefix("Z");
+for (k=0;k<m_plus_n;k++) {@+register Arc *a=gb_virgin_arc();
+ a->tip=make2(XOR,uu+k,w[k]);
+ a->next=g->outs;
+ g->outs=a;
+}
+
+@* Partial evaluation. The subroutine call |partial_gates(g,r,prob,seed,buf)|
+creates a new gate graph from a given gate graph~|g| by ``partial evaluation,''
+i.e., by setting some of the inputs to constant values and simplifying the
+result. The new graph is usually smaller than |g|; it may, in fact, be a great
+deal smaller. Graph~|g| is destroyed in the process.
+
+The first |r| inputs of |g| are retained; each remaining input is
+retained with probability |prob/65536|, and if not retained it is assigned
+a random constant value. For example, about half of the inputs will become
+constant if |prob=32768|.
+The |seed| parameter defines a machine-independent source of random
+numbers, and it may be given any value between $0$ and $2^{31}-1$.
+
+If the |buf| parameter is non-null, it should be the address of a string.
+In such a case, |partial_gates| will put a record of its partial evaluation
+into that string; |buf| will contain one character for each input gate
+after the first |r|, namely |'*'| if the input was
+retained, |'0'| if it was set to~$0$, or |'1'| if it was set to~$1$.
+
+The new graph will contain only gates that contribute to the computation
+of at least one output value. Therefore some input gates may disappear
+even though they were supposedly ``retained,'' i.e., even though their
+value has not been set constant. The |name| field of a vertex can be
+used to determine exactly which input gates have survived.
+
+If graph |g| was created by |risc|, users will probably want to make
+|r>=1|, since the whole RISC circuit collapses to zero whenever its
+first input `\.{RUN}' is set to 0.
+
+An interesting class of graphs is produced by
+the function call |partial_gates(prod(m,n),m,0,seed,NULL)|, which
+creates a graph corresponding to a circuit that multiplies a given |m|-bit
+number by a fixed (but randomly selected) |n|-bit constant. If the constant
+is not zero, all |m| of the ``retained'' input gates necessarily survive.
+The demo program called |multiply| illustrates such circuits.
+
+The graph |g| might be a generalized network; i.e., it might
+have the |'C'| or |'='| gates described earlier. Notice that if |r| is
+sufficiently large, |partial_gates| becomes equivalent to the |reduce|
+routine. Therefore we need not make that private routine public.
+
+As usual, the result will be |NULL|, and |panic_code| will be set,
+if |partial_gates| is unable to complete its task.
+
+@<The |partial_gates| routine@>=
+Graph *partial_gates(g,r,prob,seed,buf)
+ Graph *g; /* generalized gate graph */
+ unsigned r; /* the number of initial gates to leave untouched */
+ unsigned long prob; /* scaled probability of touching subsequent input gates */
+ long seed; /* seed value for random number generation */
+ char *buf; /* optional parameter for information about partial assignment */
+{@+register Vertex *v; /* the current gate of interest */
+ if (g==NULL) panic(missing_operand); /* where is |g|? */
+ gb_init_rand(seed); /* get them random numbers rolling */
+ for (v=g->vertices+r;v<g->vertices+g->n;v++)
+ switch (v->typ) {
+ case 'C': case '=': continue; /* input gates may still follow */
+ case 'I': if ((gb_next_rand()>>15)>=prob) {
+ v->typ='C';@+v->bit=gb_next_rand()>>30;
+ if (buf) *buf++=v->bit+'0';
+ } else if (buf) *buf++='*';
+ break;
+ default: goto done; /* no more input gates can follow */
+ }
+done:if (buf) *buf=0; /* terminate the string */
+ g=reduce(g);
+ @<Give the reduced graph a suitable |id|@>;
+ return g; /* if |(g==NULL)|, a |panic_code| has been set by |reduce| */
+}
+
+@ The |buf| parameter is not recorded in the graph's |id| field, since it
+has no effect on the graph itself.
+
+@<Give the reduced graph a suitable |id|@>=
+if (g) {
+ strcpy(name_buf,g->id);
+ if (strlen(name_buf)>54) strcpy(name_buf+51,"...");
+ sprintf(g->id,"partial_gates(%s,%u,%lu,%ld)",name_buf,r,prob,seed);
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_graph.w b/support/graphbase/gb_graph.w
new file mode 100644
index 0000000000..1f047b1064
--- /dev/null
+++ b/support/graphbase/gb_graph.w
@@ -0,0 +1,887 @@
+% This file is part of the St588anford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace GRAPH}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+@* Introduction. This is |gb_graph|, the data-structure module used by all
+GraphBase routines to allocate memory. The basic data types for graph
+representation are also defined here.
+
+Many examples of how to use these conventions appear in other GraphBase
+modules. The best introduction to such examples can probably be found
+in |gb_basic|, which contains subroutines for generating and transforming
+various classical graphs.
+
+@ The code below is believed to be system-independent; it should
+produce equivalent results on all systems, assuming that the standard
+|calloc| and |cfree| functions of \Cee\ are available.
+
+However, a test program helps build confidence that everything does in fact
+work as it should. To make such a test, simply compile and run |test_graph|.
+This particular test is fairly rudimentary, but it should be passed before
+more elaborate routines are tested.
+
+@(test_graph.c@>=
+#include "gb_graph.h" /* all users of |gb_graph| should do this */
+@<Declarations of test variables@>@;
+@#
+main()
+{
+ @<Create a small graph@>;
+ @<Test some intentional errors@>;
+ @<Check that the small graph is still there@>;
+ printf("OK, the gb_graph routines seem to work!\n");
+}
+
+@ The \Cee\ code for |gb_graph| doesn't have a main routine; it's just a
+bunch of subroutines to be incorporated into programs at a higher level,
+via the system loading routine. Here is the general outline of \.{gb\_graph.c}:
+
+@p
+#include <stdio.h>
+#ifdef SYSV
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+@<Type declarations@>@;
+@<Private declarations@>@;
+@<External declarations@>@;
+@<External functions@>
+
+@ The type declarations of |gb_graph| appear also in the header file
+\.{gb\_graph.h}. For convenience, that header file also incorporates the
+standard system headers for input/output and string manipulation.
+
+@(gb_graph.h@>=
+#include <stdio.h>
+#ifdef SYSV
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+@<Type declarations@>@;
+
+@ GraphBase programs often have a ``verbose'' option, which needs to
+be enabled by the setting of an external variable. They also tend to have
+a variable called |panic_code|, which helps identify unusual errors.
+We might as well declare those variables here.
+
+@<External d...@>=
+int verbose=0; /* nonzero if ``verbose'' output is desired */
+int panic_code=0; /* set nonzero if graph generator returns null pointer */
+
+@ Every external variable should be declared twice in this \.{CWEB} file;
+once for |gb_graph| itself (the ``real'' declaration for storage allocation
+purposes), and once in \.{gb\_graph.h} (for cross-references by
+|gb_graph| users).
+
+@(gb_graph.h@>=
+extern int verbose; /* nonzero if ``verbose'' output is desired */
+extern int panic_code; /* set nonzero if graph generator panics */
+
+@ When |panic_code| is assigned a nonzero value, one of the symbolic
+names defined here is used to help pinpoint the problem.
+Small values indicate memory limitations; values in the 10s and 20s
+indicate input/output anomalies; values in the 30s and 40s indicate
+errors in the parameters to a subroutine. Some panic codes
+stand for cases the author doesn't think will ever arise, although
+the program checks for them just to be extra safe. Multiple instances
+of the same type of error within a single subroutine are distinguished
+by adding an integer; for example, `|syntax_error+1|' and `|syntax_error+2|'
+identify two different kinds of syntax error, as an aid in trouble-shooting.
+The |early_data_fault| and |late_data_fault| codes are explained further
+by the value of |io_errors|.
+
+@(gb_graph.h@>=
+#define alloc_fault -1 /* a previous memory request failed */
+#define no_room 1 /* the current memory request failed */
+#define early_data_fault 10 /* error detected at beginning of \.{.dat} file */
+#define late_data_fault 11 /* error detected at end of \.{.dat} file */
+#define syntax_error 20 /* error detected while reading \.{.dat} file */
+#define bad_specs 30 /* parameter out of range or otherwise disallowed */
+#define very_bad_specs 40 /* parameter far out of range or otherwise stupid */
+#define missing_operand 50 /* graph parameter is |NULL| */
+#define invalid_operand 60 /* graph parameter doesn't obey assumptions */
+#define impossible 666 /* ``this can't happen'' */
+
+@* Representation of graphs. The GraphBase programs employ a simple and flexible
+set of data structures to represent and manipulate graphs in computer memory.
+Vertices appear in a sequential array of \&{Vertex} records, and the arcs
+emanating from each vertex appear in a linked list of \&{Arc} records. There
+is also a \&{Graph} record, to provide information about the graph as a whole.
+
+The structure layouts for \&{Vertex}, \&{Arc}, and \&{Graph} records
+include a number of utility fields that can be used for any purpose by
+algorithms that manipulate the graphs. Each utility field is a union
+type that can be either a pointer of various kinds or a (long) integer.
+
+Let's begin the formal definition of these data structures by declaring the
+union type \&{util}. The suffixes .|v|, .|a|, .|g|, and .|s| on the name
+of a utility variable will mean that it is a pointer to a vertex, arc,
+graph, or string, respectively; the suffix .|i| will mean that it is
+an integer. (We use one-character names because such names are easy to type
+when debugging.)
+
+@<Type dec...@>=
+typedef union {
+ struct vertex_struct *v; /* pointer to \&{Vertex} */
+ struct arc_struct *a; /* pointer to \&{Arc} */
+ struct graph_struct *g; /* pointer to \&{Graph} */
+ char *s; /* pointer to string */
+ long i; /* integer */
+} util;
+
+@ Each \&{Vertex} has two standard fields and six utility fields; hence it
+occupies 32 bytes on most systems, not counting the memory needed for
+supplementary string data. The standard fields are
+$$\vcenter{\halign{#,\ \ \hfil&#\hfil\cr
+|arcs|&a pointer to an \&{Arc};\cr
+|name|&a pointer to a string of characters.\cr}}$$
+If |v| points to a \&{Vertex} and |v->arcs| is |NULL|, there are no arcs
+emanating from~|v|. But if |v->arcs| is non-|NULL|, it points to an \&{Arc}
+record representing an arc from~|v|, and that record has a |next| field that
+points in the same way to the representations of all other arcs from~|v|.
+
+The utility fields are called |u|, |v|, |w|, |x|, |y|, |z|. Macros can
+be used to give them syntactic sugar in particular applications. They are
+typically used to record such things as the in-degree or out-degree, or
+whether a vertex is `marked'; or they link the vertex to other vertices in
+one or more lists.
+
+@<Type dec...@>=
+typedef struct vertex_struct {
+ struct arc_struct *arcs; /* linked list of arcs coming out of this vertex */
+ char *name; /* string identifying this vertex symbolically */
+ util u,v,w,x,y,z; /* multipurpose fields */
+} Vertex;
+
+@ Each \&{Arc} has three standard fields and two utility fields. Thus it
+occupies 20~bytes on most computer systems. The standard fields are
+$$\vcenter{\halign{#,\ \ \hfil&#\hfil\cr
+|tip|&a pointer to a |Vertex|;\cr
+|next|&a pointer to an \&{Arc};\cr
+|len|&a (long) integer.\cr}}$$
+If |a| points to an \&{Arc} in the list of arcs from vertex~|v|, it represents
+an arc of length |a->len| from |v| to |a->tip|, and the next arc from |v|
+in the list is represented by |a->next|.
+
+The utility fields are called |a| and |b|.
+
+@<Type dec...@>=
+typedef struct arc_struct {
+ struct vertex_struct *tip; /* the arc points to this vertex */
+ struct arc_struct *next; /* another arc pointing from the same vertex */
+ long len; /* length of this arc */
+ util a,b; /* multipurpose fields */
+} Arc;
+
+@* Storage allocation. Memory space must be set aside dynamically for
+vertices, arcs, and their attributes. The GraphBase routines provided by
+|gb_graph| accomplish this task with reasonable ease and efficiency
+by using the concept of memory ``areas.'' The user should first declare an
+\&{Area} variable by saying, for example,
+$$\hbox{\&{Area} |s|;}$$
+and if this variable isn't static or otherwise known to be zero, it must be
+cleared initially by saying `|init_area(s)|'. Then any number of subroutine
+calls of the form `|gb_alloc(n,s)|' can be given; |gb_alloc|
+will return a pointer to a block of |n| consecutive bytes, all cleared to zero.
+Finally, the user can issue the statement
+$$\hbox{|gb_free(s)|;}$$
+this will return all memory blocks currently allocated to area~|s|, making them
+available for future allocation.
+
+The number of bytes |n| specified to |gb_alloc| must be positive, and
+it should usually be 1000 or more, since this will reduce the number
+of system calls. Other routines are provided below to allocate smaller
+amounts of memory, such as the space needed for a single new \&{Arc}.
+
+If no memory of the requested size is presently available, |gb_alloc|
+returns the null pointer |NULL|. In such cases |gb_alloc| also sets
+the external variable |gb_alloc_trouble| to a nonzero value. The user
+can therefore discover whether any one of an arbitrarily long series
+of allocation requests has failed by making a single test, `|if
+(gb_alloc_trouble)|'. The value of |gb_alloc_trouble| should be cleared to zero
+by every graph generation subroutine; therefore it need not be
+initialized to zero.
+
+A special macro |gb_alloc_type(n,t,s)| makes it convenient to allocate
+the space for |n| items of type~|t| in area~|s|.
+
+@d gb_alloc_type(n,t,s) @[(t*)@]gb_alloc((n)*@[sizeof@](t),s)
+
+@ The implementation of this scheme is almost ridiculously easy. The
+value of~|n| is increased by twice the number of bytes in a pointer,
+and the resulting number is rounded upwards if necessary so that it's
+a multiple of 256. Then memory is allocated using |calloc|. The extra
+bytes will contain two pointers, one to the beginning of the block and
+one to the next block associated with the same area variable.
+
+The \&{Area} type is defined to be an array of length 1. This makes it possible
+for users to say just `|s|' instead of `|&s|' when using an area
+variable as a parameter.
+
+@<Type...@>=
+#define init_area(s) @t\quad@> @[*s=NULL@]
+struct area_pointers {
+ char *first; /* address of the beginning of this block */
+ struct area_pointers *next; /* address of area pointers in previously
+ allocated block */
+};
+
+typedef struct area_pointers *Area[1];
+
+@ First we round |n| up, if necessary, so that it's a multiple of the
+size of a pointer variable. Then we know we can put |area_pointers| into
+memory at a position |n| after any address returned by |calloc|. (This
+logic should work whenever the number of bytes in a pointer variable
+is a divisor of~256.)
+
+The upper limit on |n| here is governed by old \Cee\ conventions in
+which the first parameter to |calloc| must be less than~$2^{16}$.
+Users who need graphs with more than half a million vertices might
+want to raise this limit on their systems, but they would probably
+be better off representing large graphs in a more compact way.
+@^system dependencies@>
+
+@<External fun...@>=
+char *gb_alloc(n,s)
+ long n; /* number of consecutive bytes desired */
+ Area s; /* storage area that will contain the new block */
+{@+int m=sizeof(char *); /* |m| is the size of a pointer variable */
+ Area t; /* a temporary pointer */
+ char *loc; /* the block address */
+ if (n<=0 || n>0xffff00 -2*m) {
+ gb_alloc_trouble|=2; /* illegal request */
+ return NULL;
+ }
+ n=((n+m-1)/m)*m; /* round up to multiple of |m| */
+ loc=(char*)calloc((unsigned)((n+2*m+255)/256),256);
+ if (loc) {
+ *t=(struct area_pointers*)(loc+n);
+ (*t)->first=loc;
+ (*t)->next=*s;
+ *s=*t;
+ } else gb_alloc_trouble|=1;
+ return loc;
+}
+
+@ @<External d...@>=
+int gb_alloc_trouble=0; /* did |gb_alloc| return |NULL|? */
+
+@ @(gb_graph.h@>=
+extern int gb_alloc_trouble; /* anomalies noted by |gb_alloc| */
+
+@ Notice that |gb_free(s)| can be called twice in a row, because the list
+of blocks is cleared out of the area variable~|s|.
+
+@<External fun...@>=
+void gb_free(s)
+ Area s;
+{@+Area t;
+ while (*s) {
+ *t=(*s)->next;
+ cfree((*s)->first);
+ *s=*t;
+ }
+}
+
+@ The two external procedures we've defined above should be mentioned in
+the header file, so let's do that before we forget.
+
+@(gb_graph.h@>=
+extern char *gb_alloc(); /* allocate another block for an area */
+#define gb_alloc_type(n,t,s) @[@t\quad@>@[(t*)@]gb_alloc((n)*@[sizeof@](t),s)@]
+extern void gb_free(); /* deallocate all blocks for an area */
+
+@ Here we try to allocate 10 million bytes of memory. If we succeed,
+fine; if not, we verify that the error was properly reported.
+
+(An early draft of this program attempted to allocate memory until
+it was exhausted. That tactic provided a more thorough test, but it
+was a bad idea because it brought certain large systems to their
+knees; it was terribly unfriendly to other users who were innocently
+trying to do their own work on the same machine.)
+
+@<Test some intentional errors@>=
+if (gb_alloc(0,s)!=NULL || gb_alloc_trouble!=2) {
+ fprintf(stderr,"Allocation error 2 wasn't reported properly!\n");
+ return -2;
+}
+for (;g->v.i<100;g->v.i++) if (gb_alloc(100000,s)) g->u.i++;
+if (g->u.i<100 && gb_alloc_trouble!=3) {
+ fprintf(stderr,"Allocation error 1 wasn't reported properly!\n");
+ return -1;
+}
+gb_free(s); /* we've exhausted memory, let's put some back */
+printf("Hey, I allocated %d00000 bytes successfully. Terrific...\n",g->u.i);
+
+gb_alloc_trouble=0;
+
+@ @<Decl...@>=
+Area s; /* temporary allocations in the test routine */
+
+@*Growing a graph. Now we're ready to look at the \&{Graph} type. This is
+a data structure that can be passed to an algorithm that operates on
+graphs---to find minimum spanning trees, or strong components, or whatever.
+
+A \&{Graph} record has seven standard fields and six utility fields. The
+standard fields are
+$$\vcenter{\halign{#,\ \ \hfil&#\hfil\cr
+|vertices|&a pointer to an array of |Vertex| records;\cr
+|n|&the total number of vertices;\cr
+|m|&the total number of arcs;\cr
+|id|&a symbolic identification giving parameters of the GraphBase procedure\cr
+\omit& that generated this graph;\cr
+|format|&a symbolic representation of the data types in utility fields;\cr
+|data|&an |Area| used for |Arc| storage and string storage;\cr
+|aux_data|&an |Area| used for auxiliary information that some users may\cr
+\omit &wish to discard.\cr}}$$
+The utility fields are called |u|, |v|, |w|, |x|, |y|, and |z|.
+
+As a consequence of these conventions, we can visit all arcs of a
+graph~|g| by using the following program:
+$$\vcenter{\halign{#\hfil\cr
+|Vertex *v;|\cr
+|Arc *a;|\cr
+|for (v=g->vertices; v<g->vertices+g->n; v++)|\cr
+\quad|for (a=v->arcs; a; a=a->next)|\cr
+\qquad\\{visit}|(v,a)|;\cr}}$$
+
+@<Type...@>=
+#define ID_FIELD_SIZE 161
+typedef struct graph_struct {
+ Vertex *vertices; /* beginning of the vertex array */
+ long n; /* total number of vertices */
+ long m; /* total number of arcs */
+ char id[ID_FIELD_SIZE]; /* GraphBase identification */
+ char format[15]; /* usage of utility fields */
+ Area data; /* the main data blocks */
+ Area aux_data; /* subsidiary data blocks */
+ util u,v,w,x,y,z; /* multipurpose fields */
+} Graph;
+
+@ The |format| field should always hold a string of length 14, followed
+as usual by a null character to terminate that string. The first six
+characters of |format| specify the usage of utility fields |u|, |v|,
+|w|, |x|, |y|, and~|z| in |Vertex| records; the next two characters give the
+format of the utility fields in |Arc| records; the last six give the
+format of the utility fields in |Graph| records. Each character
+should be either \.I (denoting a |long| integer),
+\.S (denoting a pointer to a string),
+\.V (denoting a pointer to a |Vertex|), \.A (denoting a pointer to an
+|Arc|), \.G (denoting a pointer to a |Graph|), or \.Z (denoting an
+unused field that remains zero). The default |format| is
+|"ZZZZZZZZZZZZZZ"|, when none of the utility fields is being used.
+
+For example, suppose that a bipartite graph |g| is using field |g->u.i|
+to specify the size of its first part; suppose further that it has a
+string in utility field |a| of each |Arc|, and that it uses
+utility field |w| of |Vertex| records to point to an |Arc|. If |g|
+leaves all other utility fields untouched, its |format| should be
+|"ZZAZZZSZIZZZZZ"|.
+
+The |format| string is presently examined only by the |save_graph| and
+|restore_graph| routines, which convert GraphBase graphs from internal
+data structures to symbolic external files and vice versa. Therefore
+users need not update the |format| when they write algorithms to
+manipulate graphs, unless they are going to use |save_graph| to output
+a graph in symbolic form, or unless they are using some other
+GraphBase-related software that might rely on the |format|
+conventions. (Such software is not part of the ``official'' Stanford
+GraphBase, but it may conceivably exist some day.)
+
+@ Some applications of bipartite graphs require all vertices of the first
+part to appear at the beginning of the |vertices| array. In such cases,
+utility field |u.i| is traditionally given the symbolic name |n_1|, and
+it is set equal to the size of that first part. The size of the other
+part is then |g->n - g->n_1|.
+@^bipartite graph@>
+
+@d n_1 u.i /* utility field |u| may denote size of bipartite first part */
+
+@(gb_graph.h@>=
+#define n_1 @t\quad@> u.i
+#define mark_bipartite(g,n1) @[g->n_1=n1,g->format[8]='I'@]
+
+@ A new graph is created by calling |gb_new_graph(n)|, which returns a
+pointer to a |Graph| record for a graph with |n| vertices and no arcs.
+This function also initalizes several private variables that are used
+by the |gb_new_arc|, |gb_new_edge|, |gb_virgin_arc|, and |gb_save_string|
+procedures below.
+
+We actually reserve space for |n+extra_n| vertices, although claiming only~$n$,
+because several graph manipulation algorithms like to add a special vertex
+or two to the graphs they deal with.
+
+@<External f...@>=
+Graph *gb_new_graph(n)
+ long n; /* desired number of vertices */
+{
+ cur_graph=(Graph*)calloc(1,sizeof(Graph));
+ if (cur_graph) {
+ cur_graph->vertices=gb_alloc_type(n+extra_n,@[Vertex@],cur_graph->data);
+ if (cur_graph->vertices) {Vertex *p;
+ cur_graph->n=n;
+ for (p=cur_graph->vertices+n+extra_n-1; p>=cur_graph->vertices; p--)
+ p->name=null_string;
+ sprintf(cur_graph->id,"gb_new_graph(%ld)",n);
+ strcpy(cur_graph->format,"ZZZZZZZZZZZZZZ");
+ } else {
+ cfree(cur_graph);
+ cur_graph=NULL;
+ }
+ }
+ next_arc=bad_arc=NULL;
+ next_string=bad_string=NULL;
+ gb_alloc_trouble=0;
+ return cur_graph;
+}
+
+@ The value of |extra_n| is ordinarily~4, and it should probably always be at
+least~4.
+
+@<External d...@>=
+int extra_n=4; /* the number of shadow vertices allocated by |gb_new_graph| */
+char null_string[1]; /* a null string constant */
+
+@ @(gb_graph.h@>=
+extern int extra_n;
+ /* the number of shadow vertices allocated by |gb_new_graph| */
+extern char null_string[]; /* a null string constant */
+extern make_compound_id(); /* routine to set one |id| field from another */
+extern make_double_compound_id(); /* ditto, but from two others */
+
+@ The |id| field of a graph is sometimes manufactured from the |id| field
+of another graph. The following routine does this without allowing the
+string to get too long after repeated copying.
+
+@ @<External f...@>=
+make_compound_id(g,s1,gg,s2) /* |sprintf(g->id,"%s%s%s",s1,gg->id,s2)| */
+ Graph *g; /* graph whose |id| is to be set */
+ char *s1; /* string for the beginning of the new |id| */
+ Graph *gg; /* graph whose |id| is to be copied */
+ char *s2; /* string for the end of the new |id| */
+{@+int avail=ID_FIELD_SIZE-strlen(s1)-strlen(s2);
+ char tmp[ID_FIELD_SIZE];
+ strcpy(tmp,gg->id);
+ if (strlen(tmp)<avail) sprintf(g->id,"%s%s%s",s1,tmp,s2);
+ else sprintf(g->id,"%s%.*s...)%s",s1,avail-5,tmp,s2);
+}
+@#
+make_double_compound_id(g,s1,gg,s2,ggg,s3)
+ /* |sprintf(g->id,"%s%s%s%s%s",s1,gg->id,s2,ggg->id,s3)| */
+ Graph *g; /* graph whose |id| is to be set */
+ char *s1; /* string for the beginning of the new |id| */
+ Graph *gg; /* first graph whose |id| is to be copied */
+ char *s2; /* string for the middle of the new |id| */
+ Graph *ggg; /* second graph whose |id| is to be copied */
+ char *s3; /* string for the end of the new |id| */
+{@+int avail=ID_FIELD_SIZE-strlen(s1)-strlen(s2)-strlen(s3);
+ if (strlen(gg->id)+strlen(ggg->id)<avail)
+ sprintf(g->id,"%s%s%s%s%s",s1,gg->id,s2,ggg->id,s3);
+ else sprintf(g->id,"%s%.*s...)%s%.*s...)%s",s1,avail/2-5,gg->id,
+ s2,(avail-9)/2,ggg->id,s3);
+}
+
+@ But how do the arcs get there? That's where the private variables in
+|gb_new_graph| come in. If |next_arc| is unequal to |bad_arc|, it points to
+an unused |Arc| record in a previously allocated block of |Arc| records.
+Similarly, |next_string| and |bad_string| are addresses used to
+place strings into a block of memory allocated for that purpose.
+
+@<Private...@>=
+static Arc *next_arc; /* the next |Arc| available for allocation */
+static Arc *bad_arc; /* but if |next_arc=bad_arc|, that |Arc| isn't there */
+static char *next_string; /* the next byte available for storing a string */
+static char *bad_string; /* but if |next_string=bad_string|, don't byte */
+static Arc dummy_arc[2]; /* an |Arc| record to point to in an emergency */
+static Graph dummy_graph; /* a |Graph| record that's normally unused */
+static Graph *cur_graph=&dummy_graph; /* the |Graph| most recently created */
+
+@ All new |Arc| records that are created by the automatic |next_arc|/|bad_arc|
+scheme originate in a procedure called |gb_virgin_arc|, which returns the
+address of a new record having type |Arc|.
+
+When a new block of |Arc| records is needed, we create 102 of them at once;
+this strategy causes exactly 2048 bytes to be allocated on most
+computer systems---a nice round number. The routine will work, however,
+if 102 is replaced by any positive even number. The new block goes into
+the |data| area of |cur_graph|.
+
+Graph-building programs do not usually call |gb_virgin_arc| directly;
+they generally invoke one of the higher-level routines |gb_new_arc|
+or |gb_new_edge| described below.
+
+If memory space has been exhausted, |gb_virgin_arc| will return a
+pointer to |dummy_arc|, so that the calling procedure can safely
+refer to fields of the result even though |gb_alloc_trouble| is nonzero.
+
+@d arcs_per_block 102
+
+@<External f...@>=
+Arc *gb_virgin_arc()
+{@+register Arc *cur_arc=next_arc;
+ if (cur_arc==bad_arc) {
+ cur_arc=gb_alloc_type(arcs_per_block,@[Arc@],cur_graph->data);
+ if (cur_arc==NULL)
+ cur_arc=dummy_arc;
+ else {
+ next_arc = cur_arc+1;
+ bad_arc = cur_arc+arcs_per_block;
+ }
+ }
+ else next_arc++;
+ return cur_arc;
+}
+
+@ The routine |gb_new_arc(u,v,len)| creates a new arc of length |len|
+from vertex~|u| to vertex~|v|. The arc becomes part of the graph that
+was most recently created by |gb_new_graph|, i.e., of the graph
+pointed to by the private variable |cur_graph|. This routine assumes
+that |u| and |v| are both vertices in that graph.
+
+The new arc will be pointed to by |u->arcs|, immediately after
+|gb_new_arc(u,v,len)| has acted. If there is no room for the new arc,
+|gb_alloc_trouble| is set nonzero, but |u->arcs| will point to the non-|NULL|
+record |dummy_arc|
+so that additional information can safely be stored in its utility fields
+without risking system crashes before |gb_alloc_trouble| is tested.
+However, the linking structure of arcs is apt to be fouled up in such
+cases; programs should make sure that |gb_alloc_trouble==0| before doing any
+extensive computation on a graph.
+
+@<External f...@>=
+void gb_new_arc(u,v,len)
+ Vertex *u, *v; /* a newly created arc will go from |u| to |v| */
+ long len; /* its length */
+{@+register Arc *cur_arc=gb_virgin_arc();
+ cur_arc->tip=v; @+cur_arc->next=u->arcs; @+cur_arc->len=len;
+ u->arcs=cur_arc;
+ cur_graph->m++;
+}
+
+@ An undirected graph has ``edges'' instead of arcs. We represent an edge
+by two arcs, one going each way.
+@^undirected graph@>
+
+The fact that |arcs_per_block| is even means that the |gb_new_edge| routine
+needs to call |gb_virgin_arc| only once instead of twice.
+
+Caveats: This routine, like |gb_new_arc|, should be used only after
+|gb_new_graph| has caused the private variable |cur_graph| to point to
+the graph containing the new edge. The routine |gb_new_edge| must
+not be used together with |gb_new_arc| or |gb_virgin_arc| when
+building a graph, unless |gb_new_arc| and |gb_virgin_arc| have been
+called an even number of times before |gb_new_edge| is invoked.
+
+The new edge will be pointed to by |u->arcs| and by |v->arcs| immediately
+after |gb_new_edge| has created it, assuming that |u!=v|. The two arcs
+appear next to each other in memory; indeed, |gb_new_edge| rigs things so
+that |v->arcs| is |u->arcs+1| when |u<v|.
+
+On many computers it turns out that the first |Arc| record of every such
+pair of arcs will have an address that is a multiple of~8, and the
+second |Arc| record will have an address that is not a multiple of~8 (because
+the first |Arc| will be 20 bytes long, and because |calloc| always returns
+a multiple of~8). However, it is not safe to assume this when writing
+portable code. Algorithms for undirected graphs can still make good use of
+the fact that arcs for edges are paired, without needing any mod~8 assumptions,
+if all edges have been created and linked into the graph by |gb_new_edge|:
+The inverse of an arc~|a| from |u| to~|v| will be arc |a+1| if and only if
+|u<v| or |a->next=a+1|; it will be arc |a-1| if and only if |u>=v| and
+|a->next!=a+1|. The condition |a->next=a+1| can hold only if |u=v|.
+
+@<External f...@>=
+void gb_new_edge(u,v,len)
+ Vertex *u, *v; /* new arcs will go from |u| to |v| and from |v| to |u| */
+ long len; /* their length */
+{@+register Arc *cur_arc=gb_virgin_arc();
+ if (cur_arc!=dummy_arc) next_arc++;
+ if (u<v) {
+ cur_arc->tip=v; @+cur_arc->next=u->arcs;
+ (cur_arc+1)->tip=u; @+(cur_arc+1)->next=v->arcs;
+ u->arcs=cur_arc; v->arcs=cur_arc+1;
+ } else {
+ (cur_arc+1)->tip=v; @+(cur_arc+1)->next=u->arcs;
+ u->arcs=cur_arc+1; /* do this now in case |u==v| */
+ cur_arc->tip=u; @+cur_arc->next=v->arcs;
+ v->arcs=cur_arc;
+ }
+ cur_arc->len=(cur_arc+1)->len=len;
+ cur_graph->m+=2;
+}
+
+@ Sometimes (let us hope rarely) we may need to use a dirty trick
+hinted at in the previous discussion. On most computers, the mate to
+arc~|a| will be |a-1| if and only if |edge_trick&(unsigned long)a|
+is nonzero.
+@^system dependencies@>
+@^pointer hacks@>
+
+@<External d...@>=
+unsigned long edge_trick=sizeof(Arc)-(sizeof(Arc)&(sizeof(Arc)-1));
+
+@ @(gb_graph.h@>=
+extern unsigned long edge_trick; /* least significant 1 bit in |sizeof(Arc)| */
+
+@ Vertices generally have a symbolic name, and we need a place to put
+such names. The |gb_save_string| function is a convenient utility
+for this purpose:
+Given a null-terminated string of any length, |gb_save_string| stashes
+it away in a safe place and returns a pointer to that place. Memory is
+conserved by combining strings from the current graph into largish blocks
+of a convenient size.
+
+Note that |gb_save_string| should be used only after |gb_new_graph| has provided
+suitable initialization, because the private variable |cur_graph| must
+point to the graph for which storage is currently being allocated, and
+the private variables |next_string| and |bad_string| must also have
+suitable values.
+
+@d string_block_size 1016 /* $1024-8$ is usually efficient */
+
+@<External f...@>=
+char *gb_save_string(s)
+ register char *s; /* the string to be copied */
+{@+register char *p=s;
+ register long len; /* length of the string and following null character */
+ while (*p++) ; /* advance to end of string */
+ len=p-s;
+ p=next_string;
+ if (p+len>bad_string) { /* not enough room in current block */
+ long size=string_block_size;
+ if (len>size)
+ size=len;
+ p=gb_alloc(size,cur_graph->data);
+ if (p==NULL)
+ return null_string; /* return a pointer to |""| if memory ran out */
+ bad_string=p+size;
+ }
+ while (*s) *p++=*s++; /* copy the non-null bytes of the string */
+ *p++='\0'; /* and append a null character */
+ next_string=p;
+ return p-len;
+}
+
+@ The test routine illustrates some of these basic maneuvers.
+
+@<Create a small graph@>=
+g=gb_new_graph(2);
+if (g==NULL) {
+ fprintf(stderr,"Oops, I couldn't even create a trivial graph!\n");
+ return -3;
+}
+u=g->vertices;@+ v=u+1;
+u->name=gb_save_string("vertex 0");
+v->name=gb_save_string("vertex 1");
+
+@ @<Decl...@>=
+Graph *g;
+Vertex *u,*v;
+
+@ If the ``edge trick'' fails, the standard GraphBase routines are
+unaffected except for the demonstration program |miles_span|. (And
+that program uses |edge_trick| only when printing verbose comments.)
+@^edge trick failure@>
+
+@<Check that the small graph is still there@>=
+if (strncmp(u->name,v->name,7)) {
+ fprintf(stderr,"Something is fouled up in the string storage machinery!\n");
+ return -4;
+}
+gb_new_edge(v,u,-1);
+gb_new_edge(u,u,1);
+gb_new_arc(v,u,-1);
+if ((edge_trick&(unsigned long)(u->arcs))||
+ (edge_trick&(unsigned long)(u->arcs->next->next))||
+ !(edge_trick&(unsigned long)(v->arcs->next)))
+ printf("Warning: The \"edge trick\" failed!\n");
+if (v->name[7]+g->n!=v->arcs->next->tip->name[7]+g->m-2) {
+ /* |'1'+2!='0'+5-2| */
+ fprintf(stderr,"Sorry, the graph data structures aren't working yet.\n");
+ return -5;
+}
+
+@ Some applications may need to add arcs to several graphs at a time,
+violating the assumptions stated above about |cur_graph| and the other
+private variables. The |switch_to_graph| function gets around that
+restriction, by using the utility slots |w|, |x|, |y|, and
+|z| of |Graph| records to save and restore the private variables.
+
+Just say |switch_to_graph(g)| in order to make |cur_graph| be~|g| and
+to restore the other private variables that are needed by
+|gb_new_arc|, |gb_virgin_arc|, |gb_new_edge|, and |gb_save_string|.
+Restriction: The graph |g| being switched to must have previously been
+switched from; i.e., it must have been |cur_graph| when |switch_to_graph|
+was called previously. Otherwise its private allocation variables will
+not have been saved. To meet this restriction, you should say
+|switch_to_graph(NULL)| just before calling |gb_new_graph|, if you
+intend to switch back to the current graph later.
+
+(The swap-in-swap-out nature of these conventions may seem inelegant, but
+convenience and efficiency are more important than elegance when most
+applications do not need the ability to switch between graphs.)
+
+@<External f...@>=
+void switch_to_graph(g)
+ Graph *g;
+{
+ cur_graph->w.a=next_arc; @+cur_graph->x.a=bad_arc;
+ cur_graph->y.s=next_string; @+cur_graph->z.s=bad_string;
+ cur_graph=(g? g: &dummy_graph);
+ next_arc=cur_graph->w.a; @+bad_arc=cur_graph->x.a;
+ next_string=cur_graph->y.s; @+bad_string=cur_graph->z.s;
+ cur_graph->w.a=NULL;
+ cur_graph->x.a=NULL;
+ cur_graph->y.s=NULL;
+ cur_graph->z.s=NULL;
+}
+
+@ Finally,
+here's a routine that obliterates an entire graph when it is no longer needed:
+
+@<External fun...@>=
+void gb_recycle(g)
+ Graph *g;
+{
+ if (g) {
+ gb_free(g->data);
+ gb_free(g->aux_data);
+ cfree(g); /* the user must not refer to |g| again */
+ }
+}
+
+@ @(gb_graph.h@>=
+extern Graph*gb_new_graph(); /* create a new graph structure */
+extern void gb_new_arc(); /* append an arc to the current graph */
+extern Arc*gb_virgin_arc(); /* allocate a new |Arc| record */
+extern void gb_new_edge(); /* append an edge (two arcs) to the current graph */
+extern char*gb_save_string(); /* store a string in the current graph */
+extern void switch_to_graph(); /* save allocation variables, swap in others */
+extern void gb_recycle(); /* delete a graph structure */
+
+@* Searching for vertices. We sometimes want to be able to find a vertex, given
+its name, and it is nice to do this in a standard way. The following simple
+subroutines can be used:
+
+{\narrower
+\smallskip|hash_in(v)| puts the name of vertex |v| into the hash table;
+\smallskip|hash_out(s)| finds a vertex named |s|, if present in the hash table;
+\smallskip|hash_setup(g)| prepares a hash table for all vertices of graph~|g|;
+\smallskip|hash_lookup(s,g)| looks up the name |s| in the hash table of |g|.
+\smallskip}
+
+\noindent Routines |hash_in| and |hash_out| apply to the current graph being
+created, while |hash_setup| and |hash_lookup| apply to arbitrary graphs.
+
+Important: Utility fields |u| and |v| of each vertex are reserved for use by
+the search routine when hashing is active. You can crash the system
+if you try to fool around with these values yourself, or if you use any
+subroutines that change those fields. The first two characters in the
+current graph's |format| field should be \.{VV} if the hash table information
+is to be saved by |gb_save|.
+
+Warning: Users of this hash scheme must preserve the number of
+vertices |g->n| in the current graph~|g|. If |g->n| is changed,
+the hash table will be worthless, unless |hash_setup| is used to
+rehash everything.
+
+@<gb_graph.h@>=
+extern void hash_in(); /* input a name to the hash table of current graph */
+extern Vertex* hash_out(); /* find a name in hash table of current graph */
+extern void hash_setup(); /* create a hash table for a given graph */
+extern Vertex* hash_lookup(); /* find a name in a given graph */
+
+@ The lookup scheme is quite simple: We compute a more-or-less random
+value |h| based on the vertex name, where |0<=h<n|, assuming that
+the graph has |n|~vertices. There is a list of all vertices whose hash
+address is~|h|, starting at |(g->vertices+h)->hash_head| and linked
+together in the |hash_link| fields, where |hash_head| and |hash_link| are
+utility fields |u.v| and |v.v|.
+
+@d hash_link u.v
+@d hash_head v.v
+
+@ @<External fun...@>=
+void hash_in(v)
+ Vertex *v;
+{@+ register char *t=v->name;
+ register Vertex *u;
+ @<Find vertex |u|, whose location is the hash code for string |t|@>;
+ v->hash_link=u->hash_head;
+ u->hash_head=v;
+}
+
+@ The hash code for a string $c_1c_2\ldots c_l$ of length $l$ is
+a nonlinear function of the characters that appears to produce reasonably
+random results between 0 and the number of vertices in the current graph.
+
+Caution: This hash coding scheme is system-dependent, because it
+uses the system's character codes. If you create a graph on
+a machine with ASCII code and save it with |gb_save|, and if you ship the
+resulting text file to some friend whose machine does not use ASCII code,
+your friend will have to rebuild the hash structure with |hash_setup|
+before being able to use |hash_lookup| successfully.
+@^character-set dependencies@>
+
+@d HASH_MULT 314159 /* random multiplier */
+@d HASH_PRIME 516595003 /* the 27182818th prime; it's less than $2^{29}$ */
+
+@<Find vertex |u|...@>=
+{@+register int h;
+ for (h=0;*t;t++) {
+ h+=(h^(h>>1))+HASH_MULT*(unsigned char)*t;
+ while (h>=HASH_PRIME) h-=HASH_PRIME;
+ }
+ u=cur_graph->vertices+(h % cur_graph->n);
+}
+
+@ If the hash function were truly random, the average number of
+string comparisons made would be less than $(e^2+7)/8\approx 1.80$ on
+a successful search, and less than $(e^2+1)/4\approx2.10$ on an
+unsuccessful search [{\sl Sorting and Searching}, Section 6.4,
+Eqs.~(15) and~(16)].
+
+@<External fun...@>=
+Vertex* hash_out(s)
+ char* s;
+{@+register char *t=s;
+ register Vertex *u;
+ @<Find vertex |u|...@>;
+ for (u=u->hash_head;u;u=u->hash_link)
+ if (strcmp(s,u->name)==0) return u;
+ return NULL; /* not found */
+}
+
+@ @<External fun...@>=
+void hash_setup(g)
+ Graph *g;
+{@+Graph *save_cur_graph;
+ if (g && g->n>0) {@+register Vertex *v;
+ save_cur_graph=cur_graph;
+ cur_graph=g;
+ for (v=g->vertices;v<g->vertices+g->n;v++) v->hash_head=NULL;
+ for (v=g->vertices;v<g->vertices+g->n;v++) hash_in(v);
+ *(g->format)=*(g->format+1)='V';
+ /* indicate usage of |hash_head| and |hash_link| */
+ cur_graph=save_cur_graph;
+ }
+}
+
+@ @<External fun...@>=
+Vertex* hash_lookup(s,g)
+ char *s;
+ Graph *g;
+{@+Graph *save_cur_graph;
+ if (g && g->n>0) {@+register Vertex *v;
+ save_cur_graph=cur_graph;
+ cur_graph=g;
+ v=hash_out(s);
+ cur_graph=save_cur_graph;
+ return v;
+ }
+ else return NULL;
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_io.w b/support/graphbase/gb_io.w
new file mode 100644
index 0000000000..8788b2c96c
--- /dev/null
+++ b/support/graphbase/gb_io.w
@@ -0,0 +1,574 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace IO}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+@* Introduction. This is |gb_io|, the input/output module used by all GraphBase
+routines to access data~files. It doesn't actually do any output; but somehow
+`input/output' sounds like a more useful title than just `input'.
+
+All files of GraphBase data are designed to produce identical results on
+almost all existing computers and operating systems. Each line of each file
+contains at most 79 characters. Each character is either a blank or a
+digit or an uppercase letter or a lowercase letter or a standard punctuation
+mark. Blank characters at the end of each line are ``invisible''; they
+have no perceivable effect, hence identical results will be obtained on
+record-oriented systems that pad every line with blanks.
+
+The data is carefully sum-checked so that defective input files have little
+chance of being accepted.
+
+@ Changes might be needed when these routines are ported to different
+systems. Sections of the program that are most likely to require such changes
+are listed under `system dependencies' in the index.
+
+A validation program is provided so that installers can tell if |gb_io|
+is working properly. To make the test, simply run |test_io|.
+
+@(test_io.c@>=
+#include <stdio.h>
+#ifdef SYSV
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "gb_io.h" /* all users of |gb_io| should include this header file */
+#define exit_test(m) /* we invoke this macro if something goes wrong */@+@=\@>
+ {@+fprintf(stderr,"%s!\n(Error code = %ld)\n",m,io_errors);@+return -1;@+}
+@t\2@>@/
+main()
+{
+ @<Test the |gb_open| routine; exit if there's trouble@>;
+ @<Test the sample data lines; exit if there's trouble@>;
+ @<Test the |gb_close| routine; exit if there's trouble@>;
+ printf("OK, the gb_io routines seem to work!\n");
+}
+
+@ The external variable |io_errors| mentioned in the previous section
+will be set nonzero if any anomalies are detected. Errors won't occur
+in normal use of GraphBase programs, so no attempt has been made to
+provide a user-friendly way to decode the nonzero values that
+|io_errors| may assume. Information is simply gathered in binary
+form; system wizards who may need to do a bit of troubleshooting
+should be able to decode |io_errors| without great pain.
+
+@d cant_open_file 0x1 /* bit set in |io_errors| if |fopen| fails */
+@d cant_close_file 0x2 /* bit set if |fclose| fails */
+@d bad_first_line 0x4 /* bit set if the data file's first line isn't legit */
+@d bad_second_line 0x8 /* bit set if the second line doesn't pass muster */
+@d bad_third_line 0x10 /* bit set if the third line is awry */
+@d bad_fourth_line 0x20 /* guess when this bit is set */
+@d file_ended_prematurely 0x40 /* bit set if |fgets| fails */
+@d missing_newline 0x80 /* bit set if line is too long or |'\n'| is missing */
+@d wrong_number_of_lines 0x100 /* bit set if the line count is wrong */
+@d wrong_checksum 0x200 /* bit set if the check sum is wrong */
+@d no_file_open 0x400 /* bit set if user tries to close an unopened file */
+@d bad_last_line 0x800 /* bit set if final line has incorrect form */
+
+@ The \Cee\ code for |gb_io| doesn't have a main routine; it's just a
+bunch of subroutines to be incorporated into programs at a higher level,
+via the system loading routine. Here is the general outline of \.{gb\_io.c}:
+
+@p
+@<Header files to include@>@;
+@<External declarations@>@;
+@<Private declarations@>@;
+@<Internal functions@>@;
+@<External functions@>
+
+@ Every external variable is declared twice in this \.{CWEB} file:
+once for |gb_io| itself (the ``real'' declaration for storage allocation
+purposes), and once in \.{gb\_io.h} (for cross-references by |gb_io| users).
+
+@<External declarations@>=
+long io_errors; /* record of anomalies noted by |gb_io| routines */
+
+@ @(gb_io.h@>=
+extern long io_errors; /* record of anomalies noted by |gb_io| routines */
+
+@ We will stick to standard \Cee-type input conventions. We'll also have
+occasion to use some of the standard string operations.
+
+@<Header...@>=
+#include <stdio.h>
+#ifdef SYSV
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+@* Inputting a line. The |gb_io| routines get their input from an array called
+|buffer|. This array is internal to |gb_io|---its contents are hidden from
+user programs. We make it 81 characters long, since the data is supposed to have
+at most 79 characters per line, followed by newline and null.
+
+@<Private...@>=
+static char buffer[81]; /* the current line of input */
+static char *cur_pos=buffer; /* the current character of interest */
+static FILE *cur_file; /* current file, or |NULL| is none is open */
+
+@ Here's a basic subroutine to fill the |buffer|. The main feature of interest
+is the removal of trailing blanks. We assume that |cur_file| is open.
+
+Notice that a line of 79 characters (followed by |'\n'|) will just fit into
+the buffer, and will cause no errors. A line of 80 characters will also
+fit; but it will be split into two lines and the |missing_newline|
+message will occur, because of the way |fgets| is defined. A |missing_newline|
+error will also occur if the file ends in the middle of a line, or if
+a null character (|'\0'|) occurs within a line.
+
+@<Internal...@>=
+static fill_buf()
+{@+register char *p;
+ if (!fgets(buffer,81,cur_file)) {
+ io_errors |= file_ended_prematurely; buffer[0]=more_data=0;
+ }
+ for (p=buffer; *p; p++) ; /* advance to first null character */
+ if (p--==buffer || *p!='\n') {
+ io_errors |= missing_newline; p++;
+ }
+ while (--p>=buffer && *p==' ') ; /* move back over trailing blanks */
+ *++p='\n'; *++p=0; /* newline and null are always present at end of line */
+ cur_pos=buffer; /* get ready to read |buffer[0]| */
+}
+
+@* Checksums. Each data file has a ``magic number,'' which is defined to be
+$$\biggl(\sum_l 2^l c_l\biggr) \bmod p\,;$$
+here $p$ is a large prime number, and $c_l$ denotes the internal code
+corresponding to the $l$th-from-last
+data character read (including newlines but not nulls).
+
+The ``internal codes'' $c_l$ are computed in a system-independent way:
+Each character |c| in the actual encoding scheme being used has a
+corresponding |icode| which is the same on all systems. For example,
+the |icode| of |'0'| is zero, regardless of whether |'0'| is actually
+represented in ASCII or EBCDIC or some other scheme. (We assume that
+every modern computer system is capable of printing at least 95
+different characters, including a blank space.)
+
+We will accept a data file as error-free if it has the correct number of
+lines and ends with the proper magic number.
+
+@<Private...@>=
+static char icode[256]; /* mapping of characters to internal codes */
+static long checksum_prime=(1<<30)-83;
+ /* large prime such that $2p+100$ won't overflow */
+static long magic; /* current checksum value */
+static int line_no; /* current line number in file */
+static long final_magic; /* desired final magic number */
+static long tot_lines; /* total number of data lines */
+static char more_data; /* is there data still waiting to be read? */
+
+@ The |icode| mapping is defined by a single string, |imap|, such that
+character |imap[k]| has |icode| value~|k|. There are 96 characters
+in |imap|, namely the 94 standard visible ASCII codes plus space
+and newline. If EBCDIC code is used instead of ASCII, the
+cents sign \rlap{\.{\kern.05em/}}\.c should take the place of single-left-quote
+\.{\char`\`}, and \.{\char5}~should take the place of\/~\.{\char`\~}.
+
+Characters that do not appear in |imap| all are given the same |icode|
+value, called |unexpected_char|. Such characters should be avoided in
+GraphBase files whenever possible. (If they do appear, they can still
+get into a user's data, but we don't distinguish them from each other
+for checksumming purposes.)
+
+The |icode| table actually plays a dual role, because we've rigged it so that
+codes 0--15 come from the characters |"0123456789ABCDEF"|. This facilitates
+conversion of decimal and hexadecimal data, and we can also use it for
+radices higher than 16.
+
+@d unexpected_char 100 /* default |icode| value */
+
+@<Private...@>=
+static char *imap="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+abcdefghijklmnopqrstuvwxyz_^~&@@,;.:?!%#$+-*/|\\<=>()[]{}`'\" \n";
+
+@ Users of |gb_io| can look at the |imap|, but they can't change it.
+
+@<External fun...@>=
+char imap_chr(d)
+ int d;
+{
+ return d<0 || d>strlen(imap)? '\0': imap[d];
+}
+@#
+int imap_ord(c)
+ char c;
+{
+ @<Make sure that |icode| has been initialized@>;
+ return icode[c];
+}
+
+@ @(gb_io.h@>=
+#define unexpected_char @t\quad@> 100
+extern char imap_chr(); /* the character that maps to |d| */
+extern int imap_ord(); /* the ordinal number of a given character */
+
+@ @<Make sure that |icode| has been initialized@>=
+if (!icode['1']) icode_setup();
+
+@ @<Internal...@>=
+static icode_setup()
+{@+register int k;
+ register char *p;
+ for (k=0;k<256;k++) icode[k]=unexpected_char;
+ for (p=imap,k=0; *p; p++,k++) icode[*p]=k;
+}
+
+@ Now we're ready to specify the first external subroutine for |gb_io| users.
+Calling |gb_newline()| will read the next line of data into |buffer| and
+update the magic number accordingly.
+
+@(gb_io.h@>=
+extern void gb_newline(); /* advance to next line of the data file */
+extern long new_checksum(); /* compute change in magic number */
+
+@ The magic checksum is not affected by lines that begin with \.*.
+
+@<External f...@>=
+gb_newline()
+{
+ if (++line_no>tot_lines) more_data=0;
+ if (more_data) {
+ fill_buf();
+ if (buffer[0]!='*')
+ magic=new_checksum(buffer,magic);
+ }
+}
+
+@ Users can compute checksums like |gb_newline| does, but they can't
+change the (private) value of |magic|.
+
+@<External f...@>=
+long new_checksum(s,old_checksum)
+ char *s; /* a string */
+ long old_checksum;
+{@+register long a=old_checksum;
+ register char*p;
+ for (p=s; *p; p++)
+ a=(a+a+icode[*p]) % checksum_prime;
+ return a;
+}
+
+@ Another simple routine allows a user to read (but not write) the
+variable |more_data|.
+
+@(gb_io.h@>=
+extern int gb_eof(); /* has the data all been read? */
+
+@ @<External f...@>=
+int gb_eof() { return !more_data; }
+
+@* Parsing a line. The user can input characters from the buffer in several
+ways. First, there's a basic |gb_char()| routine, which returns
+a single character. The character is |'\n'| if the last character on the
+line has already been read (and it continues to be |'\n'| until the user calls
+|gb_newline|).
+
+The current position in the line, |cur_pos|, always advances when |gb_char|
+is called, unless |cur_pos| was already at the end of the line.
+There's also a |gb_backup()| routine, which moves |cur_pos| one place
+to the left unless it was already at the beginning.
+
+@(gb_io.h@>=
+extern char gb_char(); /* get next character of current line, or |'\n'| */
+extern void gb_backup(); /* move back ready to scan a character again */
+
+@ @<External f...@>=
+char gb_char()
+{
+ if (*cur_pos) return (*cur_pos++);
+ return '\n';
+}
+@#
+gb_backup()
+{
+ if (cur_pos>buffer)
+ cur_pos--;
+}
+
+@ There are two ways to read numerical data. The first, |gb_digit(d)|,
+expects to read a single character in radix~|d|, using |icode| values
+to specify digits greater than~9. (Thus, for example, |'A'| represents
+the digit 10.) If the next character is a valid |d|-git,
+|cur_pos| moves to the next character and the numerical value is returned.
+Otherwise |cur_pos| stays in the same place and $-1$ is returned.
+
+The second routine, |gb_number(d)|, reads characters and forms an
+unsigned radix-|d| number until the first non-digit is encountered.
+The resulting number is returned; it is zero if no digits were found.
+No errors are possible with this routine, because it uses
+|unsigned long| arithmetic.
+
+@(gb_io.h@>=
+extern int gb_digit(); /* |gb_digit(d)| reads a digit between 0 and |d-1| */
+extern unsigned long gb_number(); /* |gb_number(d)| reads a radix-|d| number */
+
+@ The value of |d| should be at most 127, if users want their programs to be
+portable, because \Cee\ does not treat larger |char| values in a
+well-defined manner. In most applications, |d| is of course either 10 or 16.
+
+@<External f...@>=
+int gb_digit(d)
+ char d;
+{
+ if (icode[*cur_pos]<d) return icode[*cur_pos++];
+ return -1;
+}
+@#
+unsigned long gb_number(d)
+ char d;
+{@+register unsigned long a=0;
+ icode[0]=d; /* make sure |'\0'| is a nondigit */
+ while (icode[*cur_pos]<d)
+ a=a*d+icode[*cur_pos++];
+ return a;
+}
+
+@ The final subroutine for fetching data is |gb_string(p,c)|, which
+stores a null-terminated string into locations starting at~|p|.
+The string starts at |cur_pos| and ends just before the first appearance
+of character |c|. If |c=='\n'|, the string will stop at the end of the line.
+If |c| doesn't appear in the buffer at or after |cur_pos|, the last character
+of the string will be the |'\n'| that is always inserted at the end
+of a line, unless the entire line has already been read. (If the entire
+line has previously been read, the empty string is always returned.)
+After the string has been copied, |cur_pos| advances past it.
+
+In order to use this routine safely, the user should first check that
+there is room to store up to 81 characters beginning at location~|p|.
+A suitable place to put the result, called |str_buf|, is provided
+for the user's convenience.
+
+The location following the stored string is returned. Thus, if the
+stored string has length~|l| (not counting the null character that is
+stored at the end), the value returned will be |p+l+1|.
+
+@(gb_io.h@>=
+#define STR_BUF_LENGTH 160
+extern char str_buf[]; /* safe place to receive output of |gb_string| */
+extern char *gb_string(); /* |gb_string(p,c)| reads a string delimited by |c|
+ into bytes starting at |p| */
+
+@ @d STR_BUF_LENGTH 160
+
+@<External f...@>=
+char str_buf[STR_BUF_LENGTH]; /* users can put strings here if they wish */
+char *gb_string(p,c)
+ char *p; /* where to put the result */
+ char c; /* character following the string */
+{
+ while (*cur_pos && *cur_pos!=c)
+ *p++=*cur_pos++;
+ *p++=0;
+ return p;
+}
+
+@ Here's how we test those routines in |io_test|: The first line of test
+data consists of 79 characters, beginning with 64 zeroes and ending with
+`\.{123456789ABCDEF}'. The second line is completely blank. The third
+and final line says `\.{Oops:(intentional mistake)}'.
+
+@<Test the sample data lines...@>=
+if (gb_number(10)!=123456789)
+ io_errors |= 1<<20; /* decimal number not working */
+if (gb_digit(16)!=10)
+ io_errors |= 1<<21; /* we missed the \.A following the decimal number */
+gb_backup();@+ gb_backup(); /* get set to read `\.{9A}' again */
+if (gb_number(16)!=0x9ABCDEF)
+ io_errors |= 1<<22; /* hexadecimal number not working */
+gb_newline(); /* now we should be scanning a blank line */
+if (gb_char()!='\n')
+ io_errors |= 1<<23; /* newline not inserted at end */
+if (gb_char()!='\n')
+ io_errors |= 1<<24; /* newline not implied after end */
+if (gb_number(60)!=0)
+ io_errors |= 1<<25; /* number should stop at null character */
+{@+char temp[100];
+ if (gb_string(temp,'\n')!=temp+1)
+ io_errors |= 1<<26; /* string should be null after end of line */
+ gb_newline();
+ if (gb_string(temp,':')!=temp+5 || strcmp(temp,"Oops"))
+ io_errors |= 1<<27; /* string not read properly */
+}
+if (io_errors)
+ exit_test("Sorry, it failed. Look at the error code for clues");
+if (gb_digit(10)!=-1) exit_test("Digit error not detected");
+if (gb_char()!=':')
+ io_errors |= 1<<28; /* lost synch after |gb_string| and |gb_digit| */
+if (gb_eof())
+ io_errors |= 1<<29; /* premature end-of-file indication */
+gb_newline();
+if (!gb_eof())
+ io_errors |= 1<<30; /* postmature end-of-file indication */
+
+@* Opening a file. The call |gb_weak_open("foo")| will open file |"foo"| and
+initialize the checksumming process. If the file cannot be opened,
+|io_errors| will be set to |cant_open_file|, otherwise
+|io_errors| will be initialized to zero.
+
+The call |gb_open("foo")| is a stronger version of |gb_weak_open|, which
+is used for standard GraphBase data files like |"words.dat"| to make
+doubly sure that they have not been corrupted. It returns the current value
+of |io_errors|, which will be nonzero if any problems were detected
+at the beginning of the file.
+
+@<Test the |gb_open| routine...@>=
+if (gb_open("test.dat")!=0)
+ exit_test("Can't open test.dat");
+
+@ @(gb_io.h@>=
+extern void gb_weak_open(); /* open a file for GraphBase input */
+extern int gb_open(); /* open a GraphBase data file; return 0 if OK */
+
+@ @<External f...@>=
+void gb_weak_open(f)
+ char *f;
+{
+ @<Make sure that |icode|...@>;
+ @<Try to open |f|@>;
+ if (cur_file) {
+ io_errors=0;
+ more_data=1;
+ line_no=magic=0;
+ tot_lines=0x7fffffff; /* allow ``infinitely many'' lines */
+ fill_buf();
+ } else io_errors=cant_open_file;
+}
+
+@ Here's a possibly system-dependent part of the code: We try first to
+open the data file by using the file name itself as the path name;
+failing that, we try to prefix the file name with the name of the
+standard directory for GraphBase data, found in
+the header file \.{localdefs.h}.
+@^system dependencies@>
+
+@<Header...@>=
+#include "localdefs.h"
+
+@ @<Try to open |f|@>=
+cur_file=fopen(f,"r");
+@^system dependencies@>
+if (!cur_file && (strlen(DATA_DIRECTORY)+strlen(f)<STR_BUF_LENGTH)) {
+ sprintf(str_buf,"%s%s",DATA_DIRECTORY,f);
+ cur_file=fopen(str_buf,"r");
+}
+
+@ @<External f...@>=
+int gb_open(f)
+ char *f;
+{
+ strncpy(file_name,f,19); /* save the name for use by |gb_close| */
+ gb_weak_open(f);
+ if (cur_file) {
+ @<Check the first line; return if unsuccessful@>;
+ @<Check the second line; return if unsuccessful@>;
+ @<Check the third line; return if unsuccessful@>;
+ @<Check the fourth line; return if unsuccessful@>;
+ gb_newline(); /* the first line of real data is now in the buffer */
+ }
+ return io_errors;
+}
+
+@ @<Private...@>=
+static char file_name[20]; /* name of the data file, without a prefix */
+
+@ The first four lines of a typical data file should look something like this:
+$$\halign{\hskip5em\.{#}\hfill\cr
+ * File "words.dat" from the Stanford GraphBase (C) 1992 Stanford University\cr
+ * A database of English 5-letter words\cr
+ * This file may be freely copied but please do not change it in any way!\cr
+ * (Checksum parameters 5678,78934448)\cr}$$
+We actually verify only that the first four lines of a data file named |"foo"|
+begin with the characters
+$$\halign{\hskip5em\.{#}\hfill\cr
+ * File "foo"\cr
+ *\cr
+ *\cr
+ * (Checksum parameters $l,m$)\cr}$$
+respectively, where $l$ and $m$ are decimal numbers. The values of $l$ and~$m$
+are stored away as |tot_lines| and |final_magic|, to be matched at the
+end of the file.
+
+@<Check the first line...@>=
+sprintf(str_buf,"* File \"%s\"",f);
+if (strncmp(buffer,str_buf,strlen(str_buf)))
+ return (io_errors |= bad_first_line);
+
+@ @<Check the second line...@>=
+fill_buf();
+if (*buffer!='*') return (io_errors |= bad_second_line);
+
+@ @<Check the third line...@>=
+fill_buf();
+if (*buffer!='*') return (io_errors |= bad_third_line);
+
+@ @<Check the fourth line; return if unsuccessful@>=
+fill_buf();
+if (strncmp(buffer,"* (Checksum parameters ",23))
+ return (io_errors |= bad_fourth_line);
+cur_pos +=23;
+tot_lines=gb_number(10);
+if (gb_char()!=',')
+ return (io_errors |= bad_fourth_line);
+final_magic=gb_number(10);
+if (gb_char()!=')')
+ return (io_errors |= bad_fourth_line);
+
+@* Closing a file. At the end, we check that the file was open
+and that it had the correct number of lines, the correct magic number,
+and a correct final line.
+The subroutine |gb_close|, like |gb_open|, returns the value of
+|io_errors|, which will be nonzero if at least one problem was noticed.
+
+@<Test the |gb_close| routine; exit if there's trouble@>=
+if (gb_close()!=0)
+ exit_test("Bad checksum, or difficulty closing the file");
+
+@ @<External f...@>=
+int gb_close()
+{
+ if (!cur_file)
+ return (io_errors |= no_file_open);
+ fill_buf();
+ sprintf(str_buf,"* End of file \"%s\"",file_name);
+ if (strncmp(buffer,str_buf,strlen(str_buf)))
+ io_errors |= bad_last_line;
+ more_data=buffer[0]=0;
+ /* now the |gb_io| routines are effectively shut down */
+ /* we have |cur_pos=buffer| */
+ if (fclose(cur_file)!=0)
+ return (io_errors |= cant_close_file);
+ cur_file=NULL;
+ if (line_no!=tot_lines+1)
+ return (io_errors |= wrong_number_of_lines);
+ if (magic!=final_magic)
+ return (io_errors |= wrong_checksum);
+ return io_errors;
+}
+
+@ There is also a less paranoid routine, |gb_weak_close|, that
+closes user-generated files. It simply closes the current file, if any,
+and returns the value of the |magic| checksum.
+
+Example: The |restore_graph| subroutine in module |gb_save| uses
+|gb_weak_open| and |gb_weak_close| to provide system-independent input
+that is almost as foolproof as the reading of standard GraphBase data.
+
+@ @(gb_io.h@>=
+extern int gb_close(); /* close a GraphBase data file; return 0 if OK */
+extern long gb_weak_close(); /* close file and return the checksum */
+
+@ @<External f...@>=
+long gb_weak_close()
+{
+ if (cur_file) {
+ fclose(cur_file);
+ more_data=buffer[0]=0;
+ cur_pos=buffer;
+ cur_file=NULL;
+ }
+ return magic;
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_miles.w b/support/graphbase/gb_miles.w
new file mode 100644
index 0000000000..4e6f9d8e03
--- /dev/null
+++ b/support/graphbase/gb_miles.w
@@ -0,0 +1,404 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace MILES}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the |miles| subroutine,
+which creates a family of undirected graphs based on highway mileage data
+between North American cities. Examples of the use of this procedure can be
+found in the demo programs |miles_span| and |gb_plane|.
+
+@(gb_miles.h@>=
+extern Graph *miles();
+
+@ The subroutine call {\advance\thinmuskip 0mu plus 2mu
+`|miles(n,north_weight,west_weight,pop_weight,max_distance,max_degree,seed)|'}
+constructs a graph based on the information in \.{miles.dat}.
+Each vertex of the graph corresponds to one of the 128 cities whose
+name is alphabetically greater than or equal to `Ravenna, Ohio' in
+the 1949 edition of Rand McNally {\char`\&} Company's {\sl Standard Highway
+Mileage Guide}. Edges between vertices are assigned lengths representing
+distances between cities in miles. In most cases these mileages come
+from the Rand McNally Guide, but several dozen entries needed to be changed
+drastically because they were obviously too large or too small; in such cases
+an educated guess was made. Furthermore, about 5\% of the entries were
+adjusted slightly in order to
+ensure that all distances satisfy the ``triangle inequality'': The
+graph generated by |miles| has the property that the
+distance from |u| to~|v| plus the distance from |v| to~|w| always exceeds
+or equals the distance from |u| to~|w|.
+
+The constructed graph will have $\min(n,128)$ vertices; the default value
+|n=128| is substituted if |n=0|. If |n| is less
+than 128, the |n| cities will be selected by assigning a weight to
+each city and choosing the |n| with largest weight, using random
+numbers to break ties in case of equal weights. Weights are computed
+by the formula
+$$ |north_weight|\cdot|lat|+|west_weight|\cdot|lon|+|pop_weight|\cdot|pop|, $$
+where |lat| is latitude north of the equator, |lon| is longitude
+west of Greenwich, and |pop| is the population in 1980. Both |lat| and |lon|
+are given in ``decidegrees,'' hundredths of degrees. For example,
+San Francisco has |lat=3778|, |lon=12242|, and |pop=678974|;
+this means that, before the recent earthquake, it was located at
+$37.78^\circ$ north latitude and $122.42^\circ$ west longitude, and that it had
+678,974 residents in the 1980 census. The weight parameters must satisfy
+$$ \vert|north_weight|\vert\le100{,}000,\quad
+ \vert|west_weight|\vert\le100{,}000,\quad
+ \vert|pop_weight|\vert\le100.$$
+
+The constructed graph will be ``complete''---that is, it will have
+edges between every pair of vertices---unless special values are given to
+the parameters
+|max_distance| or |max_degree|. If |max_distance!=0|, edges with more
+than |max_distance| miles will not appear; if |max_degree!=0|, each
+vertex will be limited to at most |max_degree| of its shortest edges.
+
+Vertices of the graph will appear in order of decreasing weight.
+The |seed| parameter defines the pseudo-random numbers used wherever
+a ``random'' choice between equal-weight vertices or equal-length edges
+needs to be made.
+
+@d MAX_N 128
+
+@(gb_miles.h@>=
+#define MAX_N 128 /* maximum and default number of cities */
+
+@ Examples: The call |miles(100,0,0,1,0,0,0)| will construct a complete graph on
+100 vertices, representing the 100 most populous cities in the database.
+It turns out that San Diego, with a population of 875,538, is the winning city
+by this criterion, followed by San Antonio (population 786,023),
+San Francisco (678,974), and Washington D.C. (638,432).
+
+To get |n| cities in the western United States and Canada, you can say
+$|miles|(n,0,1,0,\ldots\,)$; to get |n| cities in the Northeast, use a
+call like $|miles|(n,1,-1,0,\ldots\,)$. A parameter setting like
+$(50,-500,0,1,\ldots\,)$ produces mostly Southern cities, except for a
+few large metropolises in the north.
+
+If you ask for |miles(n,a,b,c,0,1,0)|, you get an edge between cities if
+and only if each city is the nearest to the other, among the |n| cities
+selected. (The graph is always undirected: There is an arc from |u| to~|v|
+if and only if there's an arc of the same length from |v| to~|u|.)
+
+A random selection of cities can be obtained by calling |miles(n,0,0,0,m,d,s)|.
+Different choices of the seed number |s| will produce different selections,
+in a system-independent manner; identical results will be obtained on
+all computers when identical parameters have been specified. Equivalent
+experiments on algorithms for graph manipulation can therefore be performed
+by researchers in different parts of the world. Any value of |s| between
+0 and $2^{31}-1$ is permissible.
+
+@ If the |miles| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |miles| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in |gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@ The \Cee\ file \.{gb\_miles.c} has the following overall shape:
+
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_flip.h" /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+#include "gb_sort.h" /* and the linksort routine */
+@#
+@<Type declarations@>@;
+@<Private variables@>@;
+@#
+Graph *miles(n,north_weight,west_weight,pop_weight,
+ max_distance,max_degree,seed)
+ unsigned n; /* number of vertices desired */
+ long north_weight; /* coefficient of latitude in the weight function */
+ long west_weight; /* coefficient of longitude in the weight function */
+ int pop_weight; /* coefficient of population in the weight function */
+ unsigned max_distance; /* maximum distance in an edge, if nonzero */
+ unsigned max_degree; /* maximum number of edges per vertex, if nonzero */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+ gb_init_rand(seed);
+ @<Check that the parameters are valid@>;
+ @<Set up a graph with |n| vertices@>;
+ @<Read the data file \.{miles.dat} and compute city weights@>;
+ @<Determine the |n| cities to use in the graph@>;
+ @<Put the appropriate edges into the graph@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |miles| */
+register int j,k; /* all-purpose indices */
+
+@ @<Check that the parameters are valid@>=
+if (n==0 || n>MAX_N) n=MAX_N;
+if (north_weight>100000 || north_weight<-100000 @|
+ || west_weight>100000 || west_weight<-100000 @|
+ || pop_weight>100 || pop_weight<-100)
+ panic(bad_specs); /* the magnitude of at least one weight is too big */
+
+@ @<Set up a graph with |n| vertices@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"miles(%u,%ld,%ld,%d,%u,%u,%ld)",
+ n,north_weight,west_weight,pop_weight,max_distance,max_degree,seed);
+strcpy(new_graph->format,"ZZIIIIZZZZZZZZ");
+
+@* Vertices. As we read in the data, we construct a list of nodes,
+each of which contains a city's name, latitude, longitude, population,
+and weight. These nodes conform to the specifications stipulated in
+the |gb_sort| module. After the list has been sorted by weight, the
+top |n| entries will be the vertices of the new graph.
+
+@<Type decl...@>=
+typedef struct node_struct { /* records to be sorted by |gb_linksort| */
+ long key; /* the nonnegative sort key (weight plus $2^{30}$) */
+ struct node_struct *link; /* pointer to next record */
+ int kk; /* index of city in the original database */
+ long lat,lon,pop; /* latitude, longitude, population */
+ char name[30]; /* |"City Name, ST"| */
+} node;
+
+@ The constants defined here are taken from the specific data in \.{miles.dat},
+because this routine is not intended to be perfectly general.
+
+@<Private...@>=
+int min_lat=2672, max_lat=5042, min_lon=7180, max_lon=12312,
+ min_pop=2521, max_pop=875538; /* tight bounds on data entries */
+node *node_block; /* array of nodes holding city info */
+int *distance; /* array of distances */
+
+@ The data in \.{miles.dat} appears in 128 groups of lines, one for each
+city, in reverse alphabetical order. These groups have the general form
+$$\vcenter{\halign{\tt#\hfil\cr
+City Name, ST[lat,lon]pop\cr
+d1 d2 d3 d4 d5 d6 ... (possibly several lines' worth)\cr
+}}$$
+where \.{City Name} is the name of the city (possibly including spaces);
+\.{ST} is the two-letter state code; \.{lat} and \.{lon} are latitude
+and longitude in hundredths of degrees; \.{pop} is the population; and
+the remaining numbers \.{d1}, \.{d2}, \dots\ are
+distances to the previously named cities in reverse order, each separated
+from the previous item by either a blank space or a newline character.
+For example, the line
+$$\hbox{\tt San Francisco, CA[3778,12242]678974}$$
+specifies the data about San Francisco that was mentioned earlier.
+From the first few groups
+$$\vcenter{\halign{\tt#\hfil\cr
+Youngstown, OH[4110,8065]115436\cr
+Yankton, SD[4288,9739]12011\cr
+966\cr
+Yakima, WA[4660,12051]49826\cr
+1513 2410\cr
+Worcester, MA[4227,7180]161799\cr
+2964 1520 604\cr
+}}$$
+we learn that the distance from Worcester, Massachusetts, to Yakima, Washington,
+is 2964 miles; from Worcester to Youngstown it is 604 miles.
+
+The following two-letter ``state codes'' are used for Canadian provinces:
+$\.{BC}=\null$British Columbia,
+$\.{MB}=\null$Manitoba,
+$\.{ON}=\null$Ontario,
+$\.{SA}=\null$Saskatchewan. (Please don't ask what code would have been used to
+distinguish New Brunswick from Nebraska if the need had arisen.)
+
+@<Read the data file \.{miles.dat} and compute city weights@>=
+node_block=gb_alloc_type(MAX_N,@[node@],new_graph->aux_data);
+distance=gb_alloc_type(MAX_N*MAX_N,@[int@],new_graph->aux_data);
+if (gb_alloc_trouble) {
+ gb_free(new_graph->aux_data);
+ panic(no_room+1); /* no room to copy the data */
+}
+if (gb_open("miles.dat")!=0)
+ panic(early_data_fault);
+ /* couldn't open |"miles.dat"| using GraphBase conventions;
+ |io_errors| tells why */
+for (k=MAX_N-1; k>=0; k--) @<Read and store data for city |k|@>;
+if (gb_close()!=0)
+ panic(late_data_fault);
+ /* something's wrong with |"miles.dat"|; see |io_errors| */
+
+@ The bounds we've imposed on |north_weight|, |west_weight|, and |pop_weight|
+guarantee that the key value computed here will be between 0 and~$2^{31}$.
+
+@<Read and store...@>=
+{@+register node *p;
+ p=node_block+k;
+ p->kk=k;
+ if (k) p->link=p-1;
+ gb_string(p->name,'[');
+ if (gb_char()!='[') panic(syntax_error); /* out of sync in \.{miles.dat} */
+ p->lat=gb_number(10);
+ if (p->lat<min_lat || p->lat>max_lat || gb_char()!=',')
+ panic(syntax_error+1); /* latitude data was clobbered */
+ p->lon=gb_number(10);
+ if (p->lon<min_lon || p->lon>max_lon || gb_char()!=']')
+ panic(syntax_error+2); /* longitude data was clobbered */
+ p->pop=gb_number(10);
+ if (p->pop<min_pop || p->pop>max_pop)
+ panic(syntax_error+3); /* population data was clobbered */
+ p->key=north_weight*(p->lat-min_lat)
+ +west_weight*(p->lon-min_lon)
+ +pop_weight*(p->pop-min_pop)+0x40000000;
+ @<Read the mileage data for city |k|@>;
+ gb_newline();
+}
+
+@ @d d(j,k) *(distance+(MAX_N*j+k))
+
+@<Read the mileage...@>=
+{@+register int j; /* number of the other city */
+ for (j=k+1; j<MAX_N; j++) {
+ if (gb_char()!=' ')
+ gb_newline();
+ d(j,k)=d(k,j)=gb_number(10);
+ }
+}
+
+@ Once all the nodes have been set up, we can use the |gb_linksort| routine
+to sort them into the desired order. This routine, which is part of
+the \\{gb\_graph} module, builds 128 lists from which the desired nodes
+are readily accessed in decreasing order of weight, using random numbers
+to break ties.
+
+We set the population to zero in every city that isn't chosen; then
+that city will be excluded when edges are examined below.
+
+@<Determine the |n| cities to use in the graph@>=
+{@+register node *p; /* the current node being considered */
+ register Vertex *v=new_graph->vertices; /* the first unfilled vertex */
+ gb_linksort(node_block+MAX_N-1);
+ for (j=127; j>=0; j--)
+ for (p=(node*)gb_sorted[j]; p; p=p->link) {
+ if (v<new_graph->vertices+n) @<Add city |p->kk| to the graph@>@;
+ else p->pop=0; /* this city is not being used */
+ }
+}
+
+@ Utility fields |x| and |y| for each vertex are set to coordinates that
+can be used in geometric computations; these coordinates are obtained by
+simple linear transformations of latitude and longitude (not by any
+kind of sophisticated polyconic projection). We will have
+$$0\le x\le5132, \qquad 0\le y\le 3555.$$
+Utility field~|z| is set to the city's index number (0 to 127) in the
+original database. Utility field~|w| is set to the city's population.
+
+The coordinates computed here are compatible with those in the \TeX\ file
+\.{cities.texmap}. Users may wish to incorporate edited copies of that file
+into documents that display results obtained with |miles| graphs.
+@.cities.texmap@>
+
+@d x_coord x.i
+@d y_coord y.i
+@d index_no z.i
+@d people w.i
+
+@<Add city |p->kk| to the graph@>=
+{
+ v->x_coord=max_lon-p->lon; /* |x| coordinate is complement of longitude */
+ v->y_coord=p->lat-min_lat;
+ v->y_coord+=(v->y_coord)>>1; /* |y| coordinate is 1.5 times latitude */
+ v->index_no=p->kk;
+ v->people=p->pop;
+ v->name=gb_save_string(p->name);
+ v++;
+}
+
+@ @(gb_miles.h@>=
+#define x_coord @t\quad@> x.i
+ /* utility field definitions for the header file */
+#define y_coord @t\quad@> y.i
+#define index_no @t\quad@> z.i
+#define people @t\quad@> w.i
+
+@* Arcs. We make the distance negative in the matrix entry for an arc
+that is not to be included. Nothing needs to be done in this regard
+unless the user has specified a maximum degree or a maximum edge length.
+
+@<Put the approp...@>=
+if (max_distance>0 || max_degree>0)
+ @<Prune unwanted edges by negating their distances@>;
+{@+register Vertex *u,*v;
+ for (u=new_graph->vertices;u<new_graph->vertices+n;u++) {
+ j=u->z.i;
+ for (v=u+1;v<new_graph->vertices+n;v++) {
+ k=v->z.i;
+ if (d(j,k)>0 && d(k,j)>0)
+ gb_new_edge(u,v,d(j,k));
+ }
+ }
+}
+
+@ @<Prune...@>=
+{@+register node *p;
+ if (max_degree==0) max_degree=MAX_N;
+ if (max_distance==0) max_distance=30000;
+ for (p=node_block; p<node_block+MAX_N; p++)
+ if (p->pop) { /* this city not deleted */
+ k=p->kk;
+ @<Blank out all undesired edges from city |k|@>;
+ }
+}
+
+@ Here we reuse the key fields of the nodes, storing complementary distances
+there instead of weights; we also let the sorting routine change the
+link fields. But the other fields (especially |pop|)
+remain unchanged. Yes, the author knows this is a wee bit tricky,
+but why not?
+
+@<Blank...@>=
+{@+register node *q;
+ register node*s=NULL; /* list of nodes containing edges from city |k| */
+ for (q=node_block; q<node_block+MAX_N; q++)
+ if (q->pop && q!=p) { /* another city not deleted */
+ j=d(k,q->kk); /* distance from |p| to |q| */
+ if (j>max_distance)
+ d(k,q->kk)=-j;
+ else {
+ q->key=max_distance-j;
+ q->link=s;
+ s=q;
+ }
+ }
+ gb_linksort(s);
+ /* now all the surviving edges from |p| are in the list |gb_sorted[0]| */
+ j=0; /* |j| counts how many edges have been accepted */
+ for (q=(node*)gb_sorted[0]; q; q=q->link)
+ if (++j>max_degree)
+ d(k,q->kk)=-d(k,q->kk);
+}
+
+@ Random access to the distance matrix is provided to users via
+the external function |miles_distance|. Caution: This function may be
+used only on the graph most recently made by |miles|, and only when
+the graph's |aux_data| has not been recycled, and only when the
+|z| utility fields have not been used for another purpose.
+
+The result may be negative when an edge has been suppressed. We can in fact
+have |miles_distance(u,v)<0| when |miles_distance(v,u)>0|, if the
+distance in question was suppressed by the |max_degree| constraint on~|u|
+but not on~|v|.
+
+@p int miles_distance(u,v)
+ Vertex *u,*v;
+{
+ return d(u->z.i,v->z.i);
+}
+
+@ @(gb_miles.h@>=
+extern int miles_distance();
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_miles} are defined and used.
diff --git a/support/graphbase/gb_mona.w b/support/graphbase/gb_mona.w
new file mode 100644
index 0000000000..67f8915bef
--- /dev/null
+++ b/support/graphbase/gb_mona.w
@@ -0,0 +1,633 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace MONA}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the |mona| subroutine,
+which creates rectangular matrices of data based on Leonardo da Vinci's
+{\sl Gioconda\/} (aka Mona Lisa). It also contains the |plane_mona|
+subroutine, which constructs undirected planar graphs based on |mona|,
+and the |bi_mona| subroutine, which constructs undirected bipartite graphs.
+Another example of the use of |mona| can be
+found in the demo program |assign_mona|.
+
+@(gb_mona.h@>=
+extern long* mona();
+extern Graph *plane_mona();
+extern Graph *bi_mona();
+
+@ The subroutine call `|mona(m,n,d,m0,m1,n0,n1,d0,d1,area)|'
+constructs an $m\times n$ matrix of integers in the range
+$[0\,.\,.\,d\mskip1mu]$,
+based on the information in \.{mona.dat}. Storage space for the matrix is
+allocated in the memory area called |area|, using the normal GraphBase
+conventions explained in |gb_graph|.
+The entries of the matrix can be regarded as pixel data, with
+0~representing black and $d$~representing white, and with intermediate
+values representing shades of gray.
+
+The data in \.{mona.dat} has 360 rows and 250 columns; the rows are numbered
+0 to 359 from top to bottom, and the columns are numbered 0 to 249 from left
+to right. The output of |mona| is generated from a rectangular section
+of the picture consisting of |m1-m0| rows and |n1-n0| columns; more
+precisely, |mona| uses the data in positions $(k,l)$ for
+|m0<=k<m1| and |n0<=l<n1|.
+
+One way to understand the process of mapping |M=m1-m0| rows and |N=n1-n0|
+columns of input into |m|~rows and |n|~columns of output is to imagine
+a giant matrix of $mM$ rows and $nN$ columns in which the original input
+data has been replicated as an $M\times N$ array of submatrices of
+size $m\times n$; each of the submatrices contains $mn$ identical pixel
+values. We can also regard the giant matrix as an $m\times n$ array of
+submatrices of size $M\times N$. The pixel values to be output are obtained
+by averaging the $M_{}N$ pixel values in the submatrices of this second
+interpretation.
+
+More precisely, the output pixel value in a given row and column is obtained
+in two steps. First we sum the $M_{}N$ entries in the corresponding submatrix
+of the giant matrix, obtaining a value $D$ between 0 and~$255M_{}N$. Then we
+scale the value~$D$ linearly into the desired final range
+$[0\,.\,.\,d\mskip1mu]$ by
+setting the result to~0 if |D<d0|, to~$d$ if |D>=d1|, and to
+$\lfloor d(D-|d0|)/(|d1|-|d0|)\rfloor$ if |d0<=D<d1|.
+
+@d MAX_M 360 /* the total number of rows of input data */
+@d MAX_N 250 /* the total number of columns of input data */
+@d MAX_D 255 /* maximum pixel value in the input data */
+
+@ Default parameter values are automically substituted when |m|, |n|, |d|,
+|m1|, |n1|, and/or |d1| are given as~0: If |m1=0| or |m1>360|,
+|m1|~is changed to 360; if |n1=0| or |n1>250|, |n1|~is
+changed to~250; then if |m| is zero, it is changed
+to~|m1-m0|; if |n| is zero, it is changed to~|n1-n0|.
+If |d| is zero, it is changed to~255;
+ if |d1| is zero, it is changed to |255(m1-m0)(n1-n0)|.
+After these substitutions have been made, the parameters must satisfy
+$$\hbox{|m0<m1|, \qquad|n0<n1|, \qquad and |d0<d1|.}$$
+
+Examples: The call |mona_pix=mona(0,0,0,0,0,0,0,0,0,area)| is equivalent to
+the call |mona_pix=mona(360,250,255,0,360,0,250,0,255*360*250,area)|;
+this special case delivers the original \.{mona.dat} data as a
+$360\times250$ array of integers in the range $[0\,.\,.\,255]$. You
+can access the pixel in row~$k$ and column~$l$ by writing
+$$\hbox{|*(mona_pix+n*k+l)|}\,,$$
+where |n| in this case is 250. A square array extracted from the top part
+of the picture, leaving out Mona's hands at the bottom, can be obtained by
+calling |mona(250,250,255,0,250,0,250,0,0,area)|.
+
+The call |mona(36,25,25500,0,0,0,0,0,0,area)| gives a $36\times25$ array
+of pixel values in the range $[0\,.\,.\,25500]$, obtained by summing
+$10\times10$ subsquares of the original data.
+
+The call |mona(100,100,100,0,0,0,0,0,0,area)| gives a $100\times100$ array
+of pixel values in the range $[0\,.\,.\,100]$; in this case the original
+data is effectively broken into subpixels and averaged appropriately.
+Notice that each output pixel in this example comes from 3.6 input
+rows and 2.5 input columns; therefore the image is being distorted
+(compressed vertically). However, our GraphBase applications are generally
+interested more in combinatorial test data, not in images per~se.
+If |(m1-m0)/m=(n1-n0)/n|, the output of |mona| will represent ``square
+pixels,'' but if |(m1-m0)/m<(n1-n0)/n|, a halftone generated from the
+output will be compressed in the horizontal dimension; if
+|(m1-m0)/m>(n1-n0)/n|, it will be compressed in the vertical dimension.
+
+If you want to reduce the original image to binary data, with the value~0
+wherever the original pixels are less than some threshold value~|t|
+and the value~1 whenever they are |t| or more, call
+|mona(m,n,1,m0,m1,n0,n1,@t}\penalty0{@>0,t*(m1-m0)*(n1-n0),area)|.
+
+The subroutine call |mona(1000,1000,255,0,250,0,250,0,0,area)| produces a
+million pixels from the upper part of the original image. This matrix
+contains more entries than the original data in \.{mona.dat}, but of course
+it is not any more accurate; it has simply been obtained by linear
+interpolation.
+
+Mona Lisa's famous smile appears in the $16\times32$ subarray defined by
+|m0=104|, |m1=120|, |n0=101|, |n1=133|.
+
+A string |mona_id| is constructed, showing the actual parameter values
+used by |mona| after defaults have been supplied.
+
+@<gb_mona.h@>=
+#define smile @t\quad@> m0=104,m1=120,n0=101,n1=133
+extern char mona_id[];
+
+@ @<Global variables@>=
+char mona_id[]="mona(360,250,9999999999,359,360,249,250,9999999999,9999999999)";
+
+@ If the |mona| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a nonzero number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |mona| returns a pointer to the newly created array. (The
+external variable |@!panic_code| is defined in |gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@ The \Cee\ file \.{gb\_mona.c} begins as follows. (Other subroutines
+come later.)
+
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+@#
+@<Global variables@>@;
+@<Private variables@>@;
+@<Private subroutines@>@;
+@#
+long *mona(m,n,d,m0,m1,n0,n1,d0,d1,area)
+ unsigned m,n; /* number of rows and columns desired */
+ unsigned long d; /* maximum pixel value desired */
+ unsigned m0,m1; /* input will be from rows $[|m0|\,.\,.\,|m1|)$ */
+ unsigned n0,n1; /* and from columns $[|n0|\,.\,.\,|n1|)$ */
+ unsigned long d0,d1; /* lower and upper threshold of raw pixel scores */
+ Area area; /* where to allocate the matrix that will be output */
+{@+@<Local variables for |mona|@>@;
+ @<Check the parameters and adjust them for defaults@>;
+ @<Allocate the matrix@>;
+ @<Read \.{mona.dat} and map it to the desired output form@>;
+ return matx;
+}
+
+@ @<Local variables for |mona|@>=
+long *matx=NULL; /* the matrix constructed by |mona| */
+register int k,l; /* the current row and column of output */
+register int i,j; /* all-purpose indices */
+int cap_M,cap_N; /* |m1-m0| and |n1-n0|, dimensions of the input */
+int cap_D; /* |d1-d0|, scale factor */
+
+@ @<Check the param...@>=
+if (m1==0 || m1>MAX_M) m1=MAX_M;
+if (m1<=m0) panic(bad_specs+1); /* |m0| must be less than |m1| */
+if (n1==0 || n1>MAX_N) n1=MAX_N;
+if (n1<=n0) panic(bad_specs+2); /* |n0| must be less than |n1| */
+cap_M=m1-m0;@+cap_N=n1-n0;
+if (m==0) m=cap_M;
+if (n==0) n=cap_N;
+if (d==0) d=MAX_D;
+if (d1==0) d1=MAX_D*cap_M*cap_N;
+if (d1<=d0) panic(bad_specs+3); /* |d0| must be less than |d1| */
+if (d1>=0x80000000) panic(bad_specs+4); /* |d1| must be less than $2^{31}$ */
+cap_D=d1-d0;
+sprintf(mona_id,"mona(%u,%u,%lu,%u,%u,%u,%u,%lu,%lu)",m,n,d,m0,m1,n0,n1,d0,d1);
+
+@ @<Allocate the matrix@>=
+matx=gb_alloc_type(m*n,@[long@],area);
+if (gb_alloc_trouble) panic(no_room+1); /* no room for the output data */
+
+@ @<Read \.{mona.dat} and map it to the desired output form@>=
+@<Open the data file, skipping unwanted rows at the beginning@>;
+@<Generate the $m$ rows of output@>;
+@<Close the data file, skipping unwanted rows at the end@>;
+
+@* Elementary image processing.
+As mentioned in the introduction, we can envisage the input as a giant
+$mM\times nN$ matrix, into which an $M\times N$ image is placed by replication
+of pixel values, and from which an $m\times n$ image is derived by summation
+of pixel values and subsequent scaling. Here |M=m1-m0| and |N=n1-n0|.
+
+Let $(\kappa,\lambda)$ be a position in the giant matrix, where $0\le\kappa<mM$
+and $0\le\lambda<nN$. The corresponding indices of the input image are
+then $\bigl(|m0|+\lfloor\kappa/m\rfloor, |n0|+\lfloor\lambda/n\rfloor\bigr)$,
+and the corresponding indices of the output image are
+$\bigl(\lfloor\kappa/M\rfloor,\lfloor\lambda/N\rfloor\bigr)$. Our main job
+is to compute the sum of all pixel values that lie in each given row~|k|
+and column~|l| of the output image. Many elements are repeated in
+the sum, so we want to use multiplication instead of simple addition whenever
+possible.
+
+For example, let's consider the inner loop first, the loop on $l$ and $\lambda$.
+Suppose $n=3$, and suppose the input pixels in the current row of interest
+are $\langle a_0,\ldots,a_{N-1}\rangle$. Then if $N=3$ we want to
+compute the output pixels $\langle3a_0,3a_1,3a_2\rangle$; if $N=4$, we
+want to compute $\langle3a_0+a_1,2a_1+2a_2,a_2+3a_3\rangle$; if $N=2$, we
+want to compute $\langle2a_1,a_0+a_1,2a_1\rangle$. The logic for doing this
+computation with the proper timing can be expressed conveniently in terms
+of four local variables:
+
+@<Local variables for |mona|@>=
+int *cur_pix; /* current position within |in_row| */
+int lambda; /* right boundary in giant for the input pixel in |cur_pix| */
+int lam; /* the first giant column not yet used in the current row */
+int next_lam; /* right boundary in giant for the output pixel in column~|l| */
+
+@ @<Process one row of pixel sums, multiplying them by~|f|@>=
+lambda=n;@+cur_pix=in_row+n0;
+for (l=lam=0; l<n; l++) {@+register int sum=0;
+ next_lam=lam+cap_N;
+ do {@+register int nl; /* giant column where something new might happen */
+ if (lam>=lambda) cur_pix++,lambda+=n;
+ if (lambda<next_lam) nl=lambda;
+ else nl=next_lam;
+ sum+=(nl-lam)*(*cur_pix);
+ lam=nl;
+ }@+while (lam<next_lam);
+ *(out_row+l)+=f*sum;
+}
+
+@ The outer loop (on $k$ and $\kappa$) is similar, but slightly more
+complicated because it deals with a vector of sums instead of a single
+sum, and because it must invoke the input routine when we're done
+with a row of input data.
+
+%Generate them rows...
+@<Generate the $m$ rows of output@>=
+kappa=0;
+out_row=matx;
+for (k=kap=0; k<m;k++) {
+ for (l=0;l<n;l++) *(out_row+l)=0; /* clear the vector of sums */
+ next_kap=kap+cap_M;
+ do {@+register int nk; /* giant row where something new might happen */
+ if (kap>=kappa) {
+ @<Read a row of input into |in_row|@>;
+ kappa+=m;
+ }
+ if (kappa<next_kap) nk=kappa;
+ else nk=next_kap;
+ f=nk-kap;
+ @<Process one...@>;
+ kap=nk;
+ }@+while (kap<next_kap);
+ for (l=0; l<n; l++,out_row++) /* note that |out_row| will advance by~|n| */
+ @<Scale the sum found in |*out_row|@>;
+}
+
+@ @<Local variables for |mona|@>=
+int kappa; /* bottom boundary in giant for the input pixels in |in_row| */
+int kap; /* the first giant row not yet used */
+int next_kap; /* bottom boundary in giant for the output pixel in row~|k| */
+int f; /* factor by which current input sums should be replicated */
+int *out_row; /* current position in |matx| */
+
+@* Integer scaling.
+Here's a general-purpose routine to compute $\lfloor na/b\rfloor$ exactly
+without risking integer overflow, given integers $n\ge0$ and $0<a\le b$.
+The idea is to solve the problem first for $n/2$, if $n$ is too large.
+
+We are careful to precompute values so that integer overflow cannot
+occur when $b$ is very large.
+
+@d el_gordo 0x7fffffff /* $2^{31}-1$, the largest single-precision integer */
+
+@<Private sub...@>=
+static int na_over_b(n,a,b)
+ int n,a,b;
+{@+int nmax=el_gordo/a; /* the largest $n$ such that $na$ doesn't overflow */
+ register int r,k,q,br;
+ int a_thresh, b_thresh;
+ if (n<=nmax) return (n*a)/b;
+ a_thresh=b-a;
+ b_thresh=(b+1)>>1; /* $\lceil b/2\rceil$ */
+ k=0;
+ do {@+bit[k]=n&1; /* save the least significant bit of $n$ */
+ n>>=1; /* and shift it out */
+ k++;
+ }@+while (n>nmax);
+ r=n*a;@+ q=r/b;@+ r=r-q*b;
+ @<Maintain quotient |q| and remainder |r| while increasing $n$
+ back to its original value $2^kn+(|bit|[k-1]\ldots |bit|[0])_2$@>;
+ return q;
+}
+
+@ @<Private var...@>=
+static int bit[30]; /* bits shifted out of |n| */
+
+@ @<Maintain quotient...@>=
+do {@+k--;@+ q<<=1;
+ if (r<b_thresh) r<<=1;
+ else q++,br=(b-r)<<1,r=b-br;
+ if (bit[k]) {
+ if (r<a_thresh) r+=a;
+ else q++,r-=a_thresh;
+ }
+}@+while (k);
+
+@ @<Scale the sum found in |*out_row|@>=
+if (*out_row<=d0) *out_row=0;
+else if (*out_row>=d1) *out_row=d;
+else *out_row=na_over_b(d,*out_row-d0,cap_D);
+
+@* Input data format.
+The file \.{mona.dat} contains 360 rows of pixel data. Each row
+appears on 10 consecutive lines of the file; each line contains
+the data for 25 pixels; each pixel is represented by two hexadecimal
+digits. The tenth and final line of each row is followed by a period.
+
+@<Open the data file, skipping unwanted rows at the beginning@>=
+if (gb_open("mona.dat")!=0)
+ panic(early_data_fault); /* couldn't open the file; |io_errors| tells why */
+for (i=0;i<m0;i++)
+ for (j=0;j<10;j++) gb_newline(); /* ignore one row of data */
+
+@ @<Close the data file, skipping unwanted rows at the end@>=
+for (i=m1;i<MAX_M;i++)
+ for (j=0;j<10;j++) gb_newline(); /* ignore one row of data */
+if (gb_close()!=0)
+ panic(late_data_fault);
+ /* check sum or other failure in data file; see |io_errors| */
+
+@ @<Read a row of input into |in_row|@>=
+for (j=0,cur_pix=&in_row[0];;j++,cur_pix++) {@+register int dd;
+ dd=gb_digit(16);
+ *cur_pix=16*dd+gb_digit(16);
+ if (j%25==24) {
+ if (j<MAX_N-1) gb_newline();
+ else {
+ if (gb_char()!='.') panic(syntax_error); /* out of sync in input file */
+ gb_newline();
+ break;
+ }
+ }
+}
+
+@ @<Private var...@>=
+static int in_row[MAX_N];
+
+@* Planar graphs. We can obtain a large family of planar graphs based on
+digitizations of Mona Lisa by the following simple scheme: Each matrix
+of pixels defines a set of connected regions containing pixels of the same
+value. (Two pixels are considered adjacent if they share an edge.)
+These connected regions are taken to be vertices of an undirected graph;
+two vertices are adjacent if the corresponding regions have at least
+one pixel edge in common.
+
+We can also state the construction another way. If we take any planar graph and collapse two
+adjacent vertices, we obtain another planar graph. Suppose we start
+with the planar graph having $mn$ vertices $[k,l]$ for $0\le k<m$ and
+$0\le l<n$, where $[k,l]$ is adjacent to $[k,l-1]$ when $l>0$ and
+to $[k-1,l]$ when $k>0$. Then we can attach pixel values to each vertex,
+after which we can repeatedly collapse adjacent vertices whose pixel values
+are equal. The resulting planar graph is the same as the graph of
+connected regions that was described in the previous paragraph.
+
+The subroutine call |plane_mona(m,n,d,m0,m1,n0,n1,d0,d1)| constructs
+the planar graph associated with the digitization produced by |mona|.
+The description of |mona|, given earlier, explains the significance of
+parameters |m|, |n|, |d|, |m0|, |m1|, |n0|, |n1|, |d0|, and |d1|. There will
+be at most $mn$ vertices, and the graph will be simply an $m\times n$
+grid unless |d| is small enough to permit adjacent pixels to have
+equal values. The graph will also become rather trivial if |d| is
+too small.
+
+Utility fields |first_pixel| and |last_pixel| give, for each vertex,
+numbers of the form $k*n+l$, identifying the topmost/leftmost
+and bottommost/rightmost positions $[k,l]$ in the region corresponding
+to that vertex. Utility fields |internal_rows| and |internal_cols| in
+the |Graph| record contain the values of |m| and~|n|; thus, in particular,
+the value of |n| needed to decompose |first_pixel| and |last_pixel| into
+individual coordinates can be found in |g->internal_cols|.
+
+The original pixel value of a vertex is placed into its |pixel_value|
+utility field.
+
+@d pixel_value x.i
+@d first_pixel y.i
+@d last_pixel z.i
+@d internal_rows u.i
+@d internal_cols v.i
+
+@p Graph *plane_mona(m,n,d,m0,m1,n0,n1,d0,d1)
+ unsigned m,n; /* number of rows and columns desired */
+ unsigned long d; /* maximum value desired */
+ unsigned m0,m1; /* input will be from rows $[|m0|\,.\,.\,|m1|)$ */
+ unsigned n0,n1; /* and from columns $[|n0|\,.\,.\,|n1|)$ */
+ unsigned long d0,d1; /* lower and upper threshold of raw pixel scores */
+{@+@<Local variables for |plane_mona|@>@;
+ init_area(working_storage);
+ @<Figure out the number of connected regions, |regs|@>;
+ @<Set up a graph with |regs| vertices@>;
+ @<Put the appropriate edges into the graph@>;
+trouble: gb_free(working_storage);
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local variables for |plane_mona|@>=
+Graph *new_graph; /* the graph constructed by |plane_mona| */
+register int j,k,l; /* all-purpose indices */
+Area working_storage; /* tables needed while |plane_mona| does its thinking */
+long *a; /* the matrix constructed by |mona| */
+int regs=0; /* number of vertices generated so far */
+
+@ @<gb_mona.h@>=
+#define pixel_value @t\quad@> x.i /* definitions for the header file */
+#define first_pixel @t\quad@> y.i
+#define last_pixel @t\quad@> z.i
+#define internal_rows @t\quad@> u.i
+#define internal_cols @t\quad@> v.i
+
+@ The following algorithm for counting the connected regions considers
+the array elements |a[k,l]| to be linearly ordered as they appear
+in memory. Thus, we can speak of the $n$ elements preceding a given
+element |a[k,l]|, if $k>0$; these are the elements |a[k,l-1]|, \dots,
+|a[k,0]|, |a[k-1,n-1]|, \dots, |a[k-1,l]|. These $n$ elements appear
+in $n$ different columns.
+
+During the algorithm, we will go through the array from bottom right
+to top left, maintaining an auxiliary table $\langle f[0],\ldots,f[n-1]
+\rangle$ with the following significance: Whenever two of the
+$n$ elements preceding our current position $[k,l]$ are connected to
+each other by a sequence of pixels with equal value, where the connecting
+links do not involve pixels more than $n$ steps before our current
+position, those elements will be linked together in the $f$ array.
+More precisely, we will have $f[c_1]=c_2$, \dots, $f[c_{j-1}]=c_j$,
+and $f[c_j]=c_j$, when there are $j$ equivalent elements in columns
+$c_1$, \dots,~$c_j$. Here $c_1$ will be the ``last'' column and
+$c_j$ the ``first,'' in wraparound order; each element with $f[c]\ne c$
+points to an earlier element.
+
+The main function of the |f| table is to identify the topmost/leftmost
+pixel of a region. If we are at position |[k,l]| and if we find $f[l]=l$
+while $a[k-1,l]\ne a[k,l]$, there is no way to connect |[k,l]| to
+earlier positions, so we create a new vertex for it.
+
+We also change the |a| matrix, so as to facilitate another algorithm
+below. If position |[k,l]| is the topmost/leftmost pixel of a region,
+we set |a[k,l]=-1|; otherwise we set |a[k,l]=f[l]|, the column of
+a preceding element belonging to the same region.
+
+@<Figure out the number...@>=
+a=mona(m,n,d,m0,m1,n0,n1,d0,d1,working_storage);
+if (a==NULL) return NULL; /* |panic_code| has been set by |mona| */
+sscanf(mona_id,"mona(%u,%u,",&m,&n); /* adjust for defaults */
+f=gb_alloc_type(n,@[unsigned long@],working_storage);
+if (f==NULL) {
+ gb_free(working_storage); /* recycle the |a| matrix */
+ panic(no_room+2); /* there's no room for the |f| vector */
+}
+@<Pass over the |a| matrix from bottom right to top left, looking
+ for the beginnings of connected regions@>;
+
+@ @<Local variables for |plane_mona|@>=
+unsigned long *f; /* beginning of array |f|;
+ $f[j]$ is the column of an equivalent element */
+long *apos; /* the location of |a[k,l]| */
+
+@ We maintain a pointer |apos| equal to |&a[k,l]|, so that
+|*(apos-1)=a[k,l-1]| and |*(apos-n)=a[k-1,l]| when $l>0$ and $k>0$.
+
+The loop that replaces $f[j]$ by $j$ can cause this algorithm to
+take time $mn^2$. We could improve the worst case by using path
+compression, but the extra complication is rarely worth the trouble.
+
+@<Pass over the |a| matrix from bottom right to top left, looking
+ for the beginnings of connected regions@>=
+for (k=m, apos=a+n*(m+1)-1; k>=0; k--)
+ for (l=n-1; l>=0; l--,apos--) {
+ if (k<m) {
+ if (k>0&&*(apos-n)==*apos) {
+ for (j=l; f[j]!=j; j=f[j]) ; /* find the first element */
+ f[j]=l; /* link it to the new first element */
+ *apos=l;
+ } else if (f[l]==l) *apos=-1-*apos,regs++; /* new region found */
+ else *apos=f[l];
+ }
+ if (k>0&&l<n-1&&*(apos-n)==*(apos-n+1)) f[l+1]=l;
+ f[l]=l;
+ }
+
+@ @<Set up a graph with |regs| vertices@>=
+new_graph=gb_new_graph(regs);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"plane_%s",mona_id);
+strcpy(new_graph->format,"ZZZIIIZZIIZZZZ");
+new_graph->internal_rows=m;
+new_graph->internal_cols=n;
+
+@ Now we make another pass over the matrix, this time from top left
+to bottom right. An auxiliary vector of length |n| is once again
+sufficient to tell us when one region is adjacent to a previous one.
+In this case the vector is called |u|, and it contains pointers to
+the vertices in the $n$ positions before our current position.
+We assume that a pointer to a |Vertex| takes the same amount of
+memory as an |unsigned long|, hence |u| can share the space formerly
+occupied by~|f|; if this is not the case, a system-dependent
+change should be made here.
+@^system dependencies@>
+
+The vertex names are simply integers, starting with 0.
+
+@<Put the appropriate edges into the graph@>=
+regs=0;
+u=(Vertex**)f;
+for (l=0;l<n;l++) u[l]=NULL;
+for (k=0,apos=a,aloc=0;k<m;k++)
+ for (l=0;l<n;l++,apos++,aloc++) {
+ w=u[l];
+ if (*apos<0) {
+ sprintf(str_buf,"%d",regs);
+ v=new_graph->vertices+regs;
+ v->name=gb_save_string(str_buf);
+ v->pixel_value=-*apos-1;
+ v->first_pixel=aloc;
+ regs++;
+ } else v=u[*apos];
+ u[l]=v;
+ v->last_pixel=aloc;
+ if (gb_alloc_trouble) goto trouble;
+ if (k>0 && v!=w) adjac(v,w);
+ if (l>0 && v!=u[l-1]) adjac(v,u[l-1]);
+ }
+
+@ @<Local variables for |pl...@>=
+Vertex **u; /* table of vertices for previous $n$ pixels */
+Vertex *v; /* vertex corresponding to position |[k,l]| */
+Vertex *w; /* vertex corresponding to position |[k-1,l]| */
+long aloc; /* $k*n+l$ */
+
+@ The |adjac| routine makes two vertices adjacent, if they aren't already.
+A faster way to recognize duplicates would probably speed things up.
+
+@<Private sub...@>=
+adjac(u,v)
+ Vertex *u,*v;
+{@+Arc *a;
+ for (a=u->arcs;a;a=a->next)
+ if (a->tip==v) return;
+ gb_new_edge(u,v,1);
+}
+
+@* Bipartite graphs. An even simpler class of Mona-Lisa-based graphs
+is obtained by considering the |m| rows and |n| columns to be individual
+vertices, with a row adjacent to a column if the associated pixel value
+is sufficiently large or sufficiently small. All edges have length~1.
+
+The subroutine call |bi_mona(m,n,m0,m1,n0,n1,thresh,c)| constructs
+the bipartite graph corresponding to the $m\times n$
+digitization produced by |mona|, using parameters |(m0,m1,n0,n1)| to
+define a rectangular subpicture as described earlier.
+The threshold parameter |thresh| should be between 0 and~65535.
+If the pixel value in row |k| and column |l| is at least |thresh/65536| of
+its maximum, vertices |k| and~|l| will be adjacent.
+If |c!=0|, however, the convention is reversed; vertices are then
+adjacent when the corresponding pixel value is {\it smaller\/} than
+|thresh/65536|. Thus, adjacencies come from ``light'' areas of
+da Vinci's painting when |c=0| and from ``dark'' areas when |c!=0|. There
+are |m+n| vertices and up to $m\times n$ edges.
+
+@p Graph *bi_mona(m,n,m0,m1,n0,n1,thresh,c)
+ unsigned m,n; /* number of rows and columns desired */
+ unsigned m0,m1; /* input will be from rows $[|m0|\,.\,.\,|m1|)$ */
+ unsigned n0,n1; /* and from columns $[|n0|\,.\,.\,|n1|)$ */
+ unsigned thresh; /* threshold defining adjacency */
+ int c; /* should we prefer dark pixels to light pixels? */
+{@+@<Local variables for |bi_mona|@>@;
+ init_area(working_storage);
+ @<Set up a bipartite graph with |m+n| vertices@>;
+ @<Put the appropriate edges into the bigraph@>;
+ gb_free(working_storage);
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local variables for |bi_mona|@>=
+Graph *new_graph; /* the graph constructed by |bi_mona| */
+register int k,l; /* all-purpose indices */
+Area working_storage; /* tables needed while |bi_mona| does its thinking */
+long *a; /* the matrix constructed by |mona| */
+long *apos; /* the location of |a[k,l]| */
+register Vertex *u,*v; /* current vertices of interest */
+
+@ @<Set up a bipartite graph...@>=
+a=mona(m,n,65535,m0,m1,n0,n1,0,0,working_storage);
+if (a==NULL) return NULL; /* |panic_code| has been set by |mona| */
+sscanf(mona_id,"mona(%u,%u,65535,%u,%u,%u,%u",&m,&n,&m0,&m1,&n0,&n1);
+new_graph=gb_new_graph(m+n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"bi_mona(%u,%u,%u,%u,%u,%u,%u,%c)",
+ m,n,m0,m1,n0,n1,thresh,c?'1':'0');
+mark_bipartite(new_graph,m);
+for (k=0,v=new_graph->vertices;k<m;k++,v++) {
+ sprintf(str_buf,"r%d",k); /* row vertices are called |"r0"|, |"r1"|, etc. */
+ v->name=gb_save_string(str_buf);
+}
+for (l=0;l<n;l++,v++) {
+ sprintf(str_buf,"c%d",l); /* column vertices are called |"c0"|,
+ |"c1"|, etc. */
+ v->name=gb_save_string(str_buf);
+}
+
+@ Since we've called |mona| with |d=65535|, the determination of
+adjacency is simple.
+
+@<Put the appropriate edges into the bigraph@>=
+for (u=new_graph->vertices,apos=a;u<new_graph->vertices+m;u++)
+ for (v=new_graph->vertices+m;v<new_graph->vertices+m+n;apos++,v++) {
+ if (c?*apos<thresh:*apos>=thresh)
+ gb_new_edge(u,v,1);
+ }
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_mona} are defined and used.
+
diff --git a/support/graphbase/gb_plane.w b/support/graphbase/gb_plane.w
new file mode 100644
index 0000000000..9e53e581e9
--- /dev/null
+++ b/support/graphbase/gb_plane.w
@@ -0,0 +1,986 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace PLANE}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace MILES}
+@* Introduction. This GraphBase module contains the |plane| subroutine,
+which constructs undirected planar graphs from vertices located randomly
+in a rectangle,
+as well as the |plane_miles| routine, which constructs planar graphs
+based on the mileage and coordinate data in \.{miles.dat}. Both of these
+routines make use of a general-purpose |delaunay| subroutine,
+which computes the Delaunay triangulation of a given set of points.
+
+@(gb_plane.h@>=
+extern Graph *plane();
+extern Graph *plane_miles();
+extern Graph *delaunay();
+
+@ The subroutine call `|plane(n,x_range,y_range,extend,prob,seed)|' constructs
+a planar graph whose vertices have integer coordinates
+uniformly distributed in the rectangle
+$$\{\,(x,y)\;\mid\;0\le x<|x_range|, \;0\le y<|y_range|\,\}\,.$$
+The values of |x_range| and |y_range| must be at most $2^{14}=16384$; the
+latter value is the default, which is substituted if |x_range| or |y_range|
+is given as zero. If |extend==0|, the graph will have |n| vertices; otherwise
+it will have |n+1| vertices, where the |(n+1)|st is assigned the coordinates
+$(-1,-1)$ and may be regarded as a point at~$\infty$.
+Some of the |n|~finite vertices might have identical coordinates, particularly
+if the point density |n/(x_range*y_range)| is not very small.
+
+The subroutine works by first constructing the Delaunay triangulation
+of the points, then discarding
+each edge of the resulting graph with probability |prob/65536|. Thus,
+for example, if |prob| is zero the full Delaunay triangulation will be
+returned; if |prob==32768|, about half of the Delaunay edges will remain.
+Each finite edge is assigned a length equal to the Euclidean distance between
+points, multiplied by $2^{10}$ and
+rounded to the nearest integer. If |extend!=0|, the
+Delaunay triangulation will also contain edges between $\infty$ and
+all points of the convex hull; such edges, if not discarded, are
+assigned length $2^{28}$, otherwise known as |INFTY|.
+
+If |extend!=0| and |prob==0|, the graph will have $n+1$ vertices and
+$3(n-1)$ edges; this is the maximum number of edges that a planar graph
+on $n+1$ vertices can have. In such a case the average degree of a vertex will
+be $6(n-1)/(n+1)$, slightly less than~6; hence, if |prob==32768|,
+the average degree of a vertex will usually be near~3.
+
+As with all other GraphBase routines that rely on random numbers,
+different values of |seed| will produce different graphs, in a
+machine-independent fashion that is reproducible on many different
+computers. Any |seed| value between 0 and $2^{31}-1$ is permissible.
+
+@d INFTY 0x10000000 /* ``infinite'' length */
+
+@(gb_plane.h@>=
+#define INFTY @t\quad@> 0x10000000
+
+@ If the |plane| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |plane| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in |gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@ Here is the overall shape of the \Cee\ file \.{gb\_plane.c}\kern.2em:
+
+@p
+#include "gb_flip.h" /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+#include "gb_miles.h" /* and we might use |gb_miles| for mileage data */
+#include "gb_io.h" /* and |gb_miles| uses |gb_io|, which has |str_buf| */
+@#
+@<Type declarations@>@;
+@<Global variables@>@;
+@<Subroutines for arithmetic@>@;
+@<Other subroutines@>@;
+@<The |delaunay| routine@>@;
+@<The |plane| routine@>@;
+@<The |plane_miles| routine@>@;
+
+@ @<The |plane| routine@>=
+Graph *plane(n,x_range,y_range,extend,prob,seed)
+ unsigned n; /* number of vertices desired */
+ unsigned x_range,y_range; /* upper bounds on rectangular coordinates */
+ unsigned extend; /* should a point at infinity be included? */
+ unsigned long prob; /* probability of rejecting a Delaunay edge */
+ long seed; /* random number seed */
+{@+Graph *new_graph; /* the graph constructed by |plane| */
+ register Vertex *v; /* the current vertex of interest */
+ register int k; /* the canonical all-purpose index */
+ gb_init_rand(seed);
+ if (x_range>16384 || y_range>16384) panic(bad_specs); /* range too large */
+ if (n<2) panic(very_bad_specs); /* don't make |n| so small, you fool */
+ if (x_range==0) x_range=16384; /* default */
+ if (y_range==0) y_range=16384; /* default */
+ @<Set up a graph with |n| uniformly distributed vertices@>;
+ @<Compute the Delaunay triangulation and
+ run through the Delaunay edges; reject them with probability
+ |prob/65536|, otherwise append them with their Euclidean length@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ if (extend) new_graph->n++; /* make the ``infinite'' vertex legitimate */
+ return new_graph;
+}
+
+@ The coordinates are placed into utility fields |x_coord| and |y_coord|.
+A random ID number is also stored in utility field~|z_coord|; this number is
+used by the |delaunay| subroutine to break ties when points are equal or
+collinear or cocircular. No two vertices have the same ID number.
+(The header file \.{gb\_miles.h} defines |x_coord|, |y_coord|, and
+|index_no| to be |x.i|, |y.i|, and |z.i| respectively.)
+
+@d z_coord z.i
+
+@<Set up a graph with |n| uniform...@>=
+if (extend) extra_n++; /* allocate one more vertex than usual */
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"plane(%u,%u,%u,%u,%lu,%ld)",
+ n,x_range,y_range,extend,prob,seed);
+strcpy(new_graph->format,"ZZZIIIZZZZZZZZ");
+for (k=0,v=new_graph->vertices; k<n; k++,v++) {
+ v->x_coord=gb_unif_rand(x_range);
+ v->y_coord=gb_unif_rand(y_range);
+ v->z_coord=((long)(gb_next_rand()/n))*n+k;
+ sprintf(str_buf,"%d",k);@+v->name=gb_save_string(str_buf);
+}
+if (extend) {
+ v->name=gb_save_string("INF");
+ v->x_coord=v->y_coord=v->z_coord=-1;
+ extra_n--;
+}
+
+@ @(gb_plane.h@>=
+#define x_coord @t\quad@> x.i
+#define y_coord @t\quad@> y.i
+#define z_coord @t\quad@> z.i
+
+@* Delaunay triangulation. The Delaunay triangulation of a set of
+vertices in the plane consists of all line segments $uv$ such that
+there exists a circle passing through $u$ and~$v$ containing no other
+vertices. Equivalently, $uv$ is a Delaunay edge if and only if the
+Voronoi regions for $u$ and $v$ are adjacent; the Voronoi region of a
+vertex~$u$ is the polygon with the property that all points inside it
+are closer to $u$ than to any other vertex. In this sense we can say
+that Delaunay edges connect vertices with their ``neighbors.''
+
+The definitions in the previous paragraph assume that no two vertices are
+equal, that no three vertices lie on a straight line, and that no four vertices
+lie on a circle. If those nondegeneracy conditions aren't satisfied, we can
+perturb the points very slightly so that the assumptions do in fact hold.
+
+Another way to characterize the Delaunay triangulation is to consider
+what happens when we map a given set of
+points onto the unit sphere via stereographic projection: Point $(x,y)$ is
+mapped to
+$$(2x/(r^2+1),2y/(r^2+1),(r^2-1)/(r^2+1)\,,$$ where $r^2=x^2+y^2$.
+If we now extend the configuration by adding $(0,0,1)$,
+which is the limiting point on the sphere when $r$ approaches infinity,
+the Delaunay edges of the original points
+turn out to be edges of the polytope defined by the mapped
+points. This polytope, which is the 3-dimensional convex hull of $n+1$ points
+on the sphere, also has edges from $(0,0,1)$ to the mapped points
+that correspond to the 2-dimensional convex hull of the original points. Under
+our assumption of nondegeneracy, the faces of this polytope are all
+triangles; hence its edges are said to form a triangulation.
+
+A self-contained presentation of all the relevant theory, together with
+an exposition and proof of correctness of the algorithm below, can be found
+in the author's monograph {\sl Axioms and Hulls}, Lecture Notes in
+Computer Science {\bf606} (Springer-Verlag, 1992).
+@^Axioms and Hulls@>
+
+@ The |delaunay| procedure, which finds the Delaunay triangulation of
+a given set of vertices, is the key ingredient in \\{gb\_plane}'s algorithms for
+generating planar graphs. The given vertices should appear in a GraphBase
+graph~|g| whose edges, if any, are ignored by |delaunay|. The coordinates
+of each vertex appear in utility fields |x_coord| and~|y_coord|, which must be
+nonnegative and less than $2^{14}=16384$. The utility fields~|z_coord| must
+contain unique ID numbers, distinct for every vertex, so that the
+algorithm can break ties in cases of degeneracy. (Note: These assumptions
+about the input data are the responsibility of the calling procedure; |delaunay|
+does not double-check them. If they are violated, catastrophic
+failure is possible.)
+
+Instead of returning the Delaunay triangulation as a graph, |delaunay|
+communicates its answer implicitly by performing the procedure call
+|f(u,v)| on every pair of vertices |u| and~|v| joined by a Delaunay edge.
+Here |f|~is a procedure supplied as a parameter; |u| and~|v| are either
+pointers to vertices or |NULL| (i.e., \.{NULL}), where |NULL| denotes the
+vertex ``$\infty$.'' As remarked above, edges run between $\infty$ and all
+vertices on the convex hull of the given points. The graph of all edges,
+including the infinite edges, is planar.
+
+For example, if the vertex at infinity is being ignored, the user can
+declare
+$$\vcenter{\halign{#\hfil\cr
+|void ins_finite(u,v)|\cr
+\qquad|Vertex *u,*v;|\cr
+|{@+if (u&&v)@+gb_new_edge(u,v,1);@+}|\cr}}$$
+Then the procedure call |delaunay(g,ins_finite)| will add all the finite
+Delaunay edges to the current graph~|g|, giving them all length~1.
+
+If |delaunay| is unable to allocate enough storage to do its work, it
+will set |gb_alloc_trouble| nonzero and there will be no edges in
+the triangulation.
+
+@<The |delaunay| routine@>=
+void delaunay(g,f)
+ Graph *g; /* vertices in the plane */
+ void (*f)(); /* procedure that absorbs the triangulated edges */
+{@+@<Local variables for |delaunay|@>;@#
+ @<Find the Delaunay triangulation of |g|, or return with |gb_alloc_trouble|
+ nonzero if out of memory@>;
+ @<Call |f(u,v)| for each Delaunay edge |uv|@>;
+ gb_free(working_storage);
+}
+
+@ The procedure passed to |delaunay| will communicate with |plane| via
+global variables called |gprob| and |inf_vertex|.
+
+@<Glob...@>=
+static unsigned gprob; /* copy of the |prob| parameter */
+static Vertex *inf_vertex; /* pointer to the vertex $\infty$, or |NULL| */
+
+@ @<Compute the Delaunay triangulation and
+ run through the Delaunay edges; reject them with probability
+ |prob/65536|, otherwise append them with their Euclidean length@>=
+gprob=prob;
+if (extend) inf_vertex=new_graph->vertices+n;
+else inf_vertex=NULL;
+delaunay(new_graph,new_euclid_edge);
+
+@ @<Other...@>=
+void new_euclid_edge(u,v)
+ Vertex *u,*v;
+{@+register long dx,dy;
+ if ((gb_next_rand()>>15)>=gprob) {
+ if (u) {
+ if (v) {
+ dx=u->x_coord-v->x_coord;
+ dy=u->y_coord-v->y_coord;
+ gb_new_edge(u,v,int_sqrt(dx*dx+dy*dy));
+ } else if (inf_vertex) gb_new_edge(u,inf_vertex,INFTY);
+ } else if (inf_vertex) gb_new_edge(inf_vertex,v,INFTY);
+ }
+}
+
+@* Arithmetic. Before we lunge into the world of geometric algorithms,
+let's build up some confidence by polishing off some subroutines that
+will be needed to ensure correct results. We assume that |long| integers
+are less than $2^{31}$.
+
+First is a routine to calculate $s=\lfloor2^{10}\sqrt x+{1\over2}\rfloor$,
+the nearest integer to $2^{10}$ times the square root of a given nonnegative
+integer~|x|. If |x>0|, this
+is the unique integer such that $2^{20}x-s\le s^2<2^{20}x+s$.
+
+The following routine appears to work by magic, but the mystery goes
+away when one considers the invariant relations
+$$ m=\lfloor 2^{2k-21}\rfloor,\qquad
+ 0<y=\lfloor 2^{20-2k}x\rfloor-s^2+s\le q=2s.$$
+(Exception: We might actually have $y=0$ for a short time when |q=2|.)
+
+@<Subroutines for arith...@>=
+long int_sqrt(x)
+ long x;
+{@+register long y, m, q=2; int k;
+ if (x<=0) return 0;
+ for (k=25,m=0x20000000;x<m;k--,m>>=2) ; /* find the range */
+ if (x>=m+m) y=1;
+ else y=0;
+ do @<Decrease |k| by 1, maintaining the invariant relations
+ between |x|, |y|, |m|, and |q|@>@;
+ while (k);
+ return q>>1;
+}
+
+@ @<Decrease |k| by 1, maintaining the invariant relations...@>=
+{
+ if (x&m) y+=y+1;
+ else y+=y;
+ m>>=1;
+ if (x&m) y+=y-q+1;
+ else y+=y-q;
+ q+=q;
+ if (y>q)
+ y-=q,q+=2;
+ else if (y<=0)
+ q-=2,y+=q;
+ m>>=1;
+ k--;
+}
+
+@ We are going to need multiple-precision arithmetic in order to
+calculate certain geometric predicates properly, but it turns out
+that we do not need to implement a general-purpose set of
+subroutines for bignums. It suffices to have a single special-purpose
+routine called |sign_test(x1,x2,x3,y1,y2,y3)|, which computes a
+single-precision integer having the same sign as the dot product
+$$\hbox{|x1*y1+x2*y2+x3*y3|}$$
+when we have $-2^{29}<|x1|,|x2|,|x3|<2^{29}$ and $0\le|y1|,|y2|,|y3|<2^{29}$.
+
+@<Subroutines for arith...@>=
+long sign_test(x1,x2,x3,y1,y2,y3)
+ long x1,x2,x3,y1,y2,y3;
+{@+int s1,s2,s3; /* signs of individual terms */
+ long a,b,c; /* components of a redundant representation of the dot product */
+ register long t; /* temporary register for swapping */
+ @<Determine the signs of the terms@>;
+ @<If the answer is obvious, return it without further ado; otherwise,
+ arrange things so that |x3*y3| has the opposite sign to |x1*y1+x2*y2|@>;
+ @<Compute a redundant representation of |x1*y1+x2*y2+x3*y3|@>;
+ @<Return the sign of the redundant representation@>;
+}
+
+@ @<Determine the signs of the terms@>=
+if (x1==0 || y1==0) s1=0;
+else {
+ if (x1>0) s1=1;
+ else x1=-x1,s1=-1;
+}
+if (x2==0 || y2==0) s2=0;
+else {
+ if (x2>0) s2=1;
+ else x2=-x2,s2=-1;
+}
+if (x3==0 || y3==0) s3=0;
+else {
+ if (x3>0) s3=1;
+ else x3=-x3,s3=-1;
+}
+
+@ The answer is obvious unless one of the terms is positive and one
+of the terms is negative.
+
+@<If the answer is obvious, return it without further ado; otherwise,
+ arrange things so that |x3*y3| has the opposite sign to |x1*y1+x2*y2|@>=
+if ((s1>=0 && s2>=0 && s3>=0) || (s1<=0 && s2<=0 && s3<=0))
+ return (s1+s2+s3);
+if (s3==0 || s3==s1) {
+ t=s3;@+s3=s2;@+s2=t;
+ t=x3;@+x3=x2;@+x2=t;
+ t=y3;@+y3=y2;@+y2=t;
+} else if (s3==s2) {
+ t=s3;@+s3=s1;@+s1=t;
+ t=x3;@+x3=x1;@+x1=t;
+ t=y3;@+y3=y1;@+y1=t;
+}
+
+@ We make use of a redundant representation $2^{28}a+2^{14}b+c$, which
+can be computed by brute force. (Everything is understood to be multiplied
+by |-s3|.)
+
+@<Compute a redundant...@>=
+{@+register int lx,rx,ly,ry;
+ lx=x1/0x4000;@+rx=x1%0x4000; /* split off the least significant 14 bits */
+ ly=y1/0x4000;@+ry=y1%0x4000;
+ a=lx*ly;@+b=lx*ry+ly*rx;@+c=rx*ry;
+ lx=x2/0x4000;@+rx=x2%0x4000;
+ ly=y2/0x4000;@+ry=y2%0x4000;
+ a+=lx*ly;@+b+=lx*ry+ly*rx;@+c+=rx*ry;
+ lx=x3/0x4000;@+rx=x3%0x4000;
+ ly=y3/0x4000;@+ry=y3%0x4000;
+ a-=lx*ly;@+b-=lx*ry+ly*rx;@+c-=rx*ry;
+}
+
+@ Here we use the fact that $\vert c\vert<2^{29}$.
+
+@<Return the sign...@>=
+if (a==0) goto ez;
+if (a<0)
+ a=-a,b=-b,c=-c,s3=-s3;
+while (c<0) {
+ a--;@+c+=0x10000000;
+ if (a==0) goto ez;
+}
+if (b>=0) return -s3; /* the answer is clear when |a>0 && b>=0 && c>=0| */
+b=-b;
+a-=b/0x4000;
+if (a>0) return -s3;
+if (a<=-2) return s3;
+return -s3*((a*0x4000-b%0x4000)*0x4000+c);
+ez:@+ if (b>=0x8000) return -s3;
+if (b<=-0x8000) return s3;
+return -s3*(b*0x4000+c);
+
+@*Determinants. The |delaunay| routine bases all of its decisions on
+two geometric predicates, which depend on whether certain determinants
+are positive or negative.
+
+The first predicate, |ccw(u,v,w)|, is true if and only if the three points
+$(u,v,w)$ have a counterclockwise orientation. This means that if we draw the
+unique circle through those points, and if we travel along that circle
+in the counterclockwise direction starting at~|u|, we will encounter
+|v| before~|w|.
+
+It turns out that that |ccw(u,v,w)| holds if and only if the determinant
+$$\left\vert\matrix{x_u&y_u&1\cr x_v&y_v&1\cr x_w&y_w&1\cr}
+ \right\vert=\left\vert\matrix{x_u-x_w&y_u-y_w\cr x_v-x_w&y_v-y_w\cr}
+ \right\vert$$
+is positive. The evaluation must be exact; if the answer is zero a special
+tie-breaking rule must be used, because the three points were collinear.
+The tie-breaking rule is tricky (and necessarily so, according to the
+theory in {\sl Axioms and Hulls\/}).
+
+Integer evaluation of that determinant will not cause |long| integer
+overflow, because we have assumed that all |x| and |y| coordinates lie
+between 0 and~$2^{14}-1$, inclusive. In fact, we could go up to
+$2^{15}-1$ without risking overflow; but the limitation to 14 bits will
+be helpful when we consider a more complicated determinant below.
+
+@<Other...@>=
+int ccw(u,v,w)
+ Vertex *u,*v,*w;
+{@+register long wx=w->x_coord, wy=w->y_coord; /* $x_w$, $y_w$ */
+ register long det=(u->x_coord-wx)*(v->y_coord-wy)
+ -(u->y_coord-wy)*(v->x_coord-wx);
+ Vertex *t;
+ if (det==0) {
+ det=1;
+ if (u->z_coord>v->z_coord) {
+ t=u;@+u=v;@+v=t;@+det=-det;
+ }
+ if (v->z_coord>w->z_coord) {
+ t=v;@+v=w;@+w=t;@+det=-det;
+ }
+ if (u->z_coord>v->z_coord) {
+ t=u;@+u=v;@+v=t;@+det=-det;
+ }
+ if (u->x_coord>v->x_coord || (u->x_coord==v->x_coord &&@|
+ (u->y_coord>v->y_coord || (u->y_coord==v->y_coord &&@|
+ (w->x_coord>u->x_coord ||
+ (w->x_coord==u->x_coord && w->y_coord>=u->y_coord))))))
+ det=-det;
+ }
+ return (det>0);
+}
+
+@ The other geometric predicate, |incircle(t,u,v,w)|, is true if and only
+if point t lies outside the circle passing through |u|, |v|, and~|w|,
+when |ccw(u,v,w)| holds. This predicate makes us work harder, because it
+is equivalent to the sign of a $4\times4$ determinant that requires
+twice as much precision:
+$$\left\vert\matrix{x_t&y_t&x_t^2+y_t^2&1\cr
+ x_u&y_u&x_u^2+y_u^2&1\cr
+ x_v&y_v&x_v^2+y_v^2&1\cr
+ x_w&y_w&x_w^2+y_w^2&1\cr}\right\vert=
+\left\vert\matrix{x_t-x_w&y_t-y_w&(x_t-x_w)^2+(y_t-y_w)^2\cr
+ x_u-x_w&y_u-y_w&(x_u-x_w)^2+(y_u-y_w)^2\cr
+ x_v-x_w&y_v-y_w&(x_v-x_w)^2+(y_v-y_w)^2\cr}
+ \right\vert\,.$$
+This sign can, however, be deduced by the |sign_test| subroutine we had
+the foresight to provide earlier.
+
+@<Other...@>=
+int incircle(t,u,v,w)
+ Vertex *t,*u,*v,*w;
+{@+register long wx=w->x_coord, wy=w->y_coord; /* $x_w$, $y_w$ */
+ long tx=t->x_coord-wx, ty=t->y_coord-wy; /* $x_t-x_w$, $y_t-y_w$ */
+ long ux=u->x_coord-wx, uy=u->y_coord-wy; /* $x_u-x_w$, $y_u-y_w$ */
+ long vx=v->x_coord-wx, vy=v->y_coord-wy; /* $x_v-x_w$, $y_v-y_w$ */
+ register long det=sign_test(tx*uy-ty*ux,ux*vy-uy*vx,vx*ty-vy*tx,@|
+ vx*vx+vy*vy,tx*tx+ty*ty,ux*ux+uy*uy);
+ Vertex *s;
+ if (det==0) {
+ @<Sort |(t,u,v,w)| by ID number@>;
+ @<Remove incircle degeneracy@>;
+ }
+ return (det>0);
+}
+
+@ @<Sort...@>=
+det=1;
+if (t->z_coord>u->z_coord) {
+ s=t;@+t=u;@+u=s;@+det=-det;
+}
+if (v->z_coord>w->z_coord) {
+ s=v;@+v=w;@+w=s;@+det=-det;
+}
+if (t->z_coord>v->z_coord) {
+ s=t;@+t=v;@+v=s;@+det=-det;
+}
+if (u->z_coord>w->z_coord) {
+ s=u;@+u=w;@+w=s;@+det=-det;
+}
+if (u->z_coord>v->z_coord) {
+ s=u;@+u=v;@+v=s;@+det=-det;
+}
+
+@ By slightly perturbing the points, we can always make them nondegenerate,
+although the details are complicated. A sequence of 12 steps, involving
+up to four auxiliary functions
+$$\openup3\jot
+\eqalign{f(t,u,v,w)&=\left\vert
+ \matrix{x_t-x_v&(x_t-x_w)^2+(y_t-y_w)^2-(x_v-x_w)^2-(y_v-y_w)^2\cr
+ x_u-x_v&(x_u-x_w)^2+(y_u-y_w)^2-(x_v-x_w)^2-(y_v-y_w)^2\cr}
+ \right\vert\,,\cr
+g(t,u,v,w)&=\left\vert
+ \matrix{y_t-y_v&(x_t-x_w)^2+(y_t-y_w)^2-(x_v-x_w)^2-(y_v-y_w)^2\cr
+ y_u-y_v&(x_u-x_w)^2+(y_u-y_w)^2-(x_v-x_w)^2-(y_v-y_w)^2\cr}
+ \right\vert\,,\cr
+h(t,u,v,w)&=(x_u-x_t)(y_v-y_w)\,,\cr
+j(t,u,v,w)&=(x_u-x_v)^2+(y_u-y_w)^2-(x_t-x_v)^2-(y_t-y_w)^2\,,\cr}
+$$
+does the trick, as explained in {\sl Axioms and Hulls}.
+
+@<Remove incircle degeneracy@>=
+{@+int dd;
+ if ((dd=ff(t,u,v,w))<0 || (dd==0 &&@|
+ ((dd=gg(t,u,v,w))<0 || (dd==0 &&@|
+ ((dd=ff(u,t,w,v))<0 || (dd==0 &&@|
+ ((dd=gg(u,t,w,v))<0 || (dd==0 &&@|
+ ((dd=ff(v,w,t,u))<0 || (dd==0 &&@|
+ ((dd=gg(v,w,t,u))<0 || (dd==0 &&@|
+ ((dd=hh(t,u,v,w))<0 || (dd==0 &&@|
+ ((dd=jj(t,u,v,w))<0 || (dd==0 &&@|
+ ((dd=hh(v,t,u,w))<0 || (dd==0 &&@|
+ ((dd=jj(v,t,u,w))<0 || (dd==0 &&
+ jj(t,w,u,v)<0))))))))))))))))))))
+ det=-det;
+}
+
+@ @<Subroutines for arith...@>=
+long ff(t,u,v,w)
+ Vertex *t,*u,*v,*w;
+{@+register long wx=w->x_coord, wy=w->y_coord; /* $x_w$, $y_w$ */
+ long tx=t->x_coord-wx, ty=t->y_coord-wy; /* $x_t-x_w$, $y_t-y_w$ */
+ long ux=u->x_coord-wx, uy=u->y_coord-wy; /* $x_u-x_w$, $y_u-y_w$ */
+ long vx=v->x_coord-wx, vy=v->y_coord-wy; /* $x_v-x_w$, $y_v-y_w$ */
+ return sign_test(ux-tx,vx-ux,tx-vx,vx*vx+vy*vy,tx*tx+ty*ty,ux*ux+uy*uy);
+}
+long gg(t,u,v,w)
+ Vertex *t,*u,*v,*w;
+{@+register long wx=w->x_coord, wy=w->y_coord; /* $x_w$, $y_w$ */
+ long tx=t->x_coord-wx, ty=t->y_coord-wy; /* $x_t-x_w$, $y_t-y_w$ */
+ long ux=u->x_coord-wx, uy=u->y_coord-wy; /* $x_u-x_w$, $y_u-y_w$ */
+ long vx=v->x_coord-wx, vy=v->y_coord-wy; /* $x_v-x_w$, $y_v-y_w$ */
+ return sign_test(uy-ty,vy-uy,ty-vy,vx*vx+vy*vy,tx*tx+ty*ty,ux*ux+uy*uy);
+}
+long hh(t,u,v,w)
+ Vertex *t,*u,*v,*w;
+{
+ return (u->x_coord-t->x_coord)*(v->y_coord-w->y_coord);
+}
+long jj(t,u,v,w)
+ Vertex *t,*u,*v,*w;
+{@+register long vx=v->x_coord, wy=w->y_coord;
+ return (u->x_coord-vx)*(u->x_coord-vx)+(u->y_coord-wy)*(u->y_coord-wy)@|
+ -(t->x_coord-vx)*(t->x_coord-vx)-(t->y_coord-wy)*(t->y_coord-wy);
+}
+
+@* Delaunay data structures. Now we are have the primitive predicates
+we need, and we can get on with the geometric aspects of |delaunay|.
+As mentioned above, each vertex is represented by two coordinates and an
+ID number, stored in the utility fields |x_coord|, |y_coord|, and~|z_coord|.
+
+Each edge of the current triangulation is represented by two arcs
+pointing in opposite directions; the two arcs are called mates. Each
+arc conceptually has a triangle on its left and a mate on its right.
+
+An \&{arc} record differs from an |Arc|; it has three fields:
+\smallskip
+|vert| is the vertex this arc leads to, or |NULL| if that vertex is $\infty$;
+\smallskip
+|next| is the next arc having the same triangle at the left;
+\smallskip
+|inst| is the branch node that points to the triangle at the left, as
+explained below.
+
+\smallskip\noindent
+If |p| points to an arc, then |p->next->next->next==p|, because a triangle
+is bounded by three arcs. We also have |p->next->inst==p->inst|, for
+all arcs~|p|.
+
+@<Type...@>=
+typedef struct a_struct {
+ Vertex *vert; /* |v|, if this arc goes from |u| to |v| */
+ struct a_struct *next; /* the arc from |v| that shares
+ a triangle with this one */
+ struct n_struct *inst; /* instruction to change
+ when the triangle is modified */
+} arc;
+
+@ Storage is allocated in such a way that, if |p| and |q| point respectively
+to an arc and its mate, then |p+q=&arc_block[0]+&arc_block[m-1]|, where |m| is
+the total number of arc records allocated in the |arc_block| array. This
+convention saves us one pointer field in each arc.
+
+When setting |q| to the mate of |p| we need to do the calculation
+cautiously, using an auxiliary register, because the constant
+|&arc_block[0]+&arc_block[m-1]| might be too large to evaluate without
+integer overflow on some systems.
+
+@d mate(a,b) { /* given |a|, set |b| to its mate */
+ reg=max_arc-(unsigned long)a;
+ b=(arc*)(reg+min_arc);
+}
+
+@<Local variables for |delaunay|@>=
+register unsigned long reg; /* used while computing mates */
+unsigned long min_arc,max_arc; /* |&arc_block[0]|, |&arc_block[m-1]| */
+arc *next_arc; /* the first arc record that hasn't yet been used */
+
+@ @<Initialize the array of arcs@>=
+next_arc=gb_alloc_type(6*g->n-6,@[arc@],working_storage);
+if (next_arc==NULL) return; /* |gb_alloc_trouble| is nonzero */
+min_arc=(unsigned long)next_arc;
+max_arc=(unsigned long)(next_arc+(6*g->n-7));
+
+@ @<Call |f(u,v)| for each Delaunay edge |uv|@>=
+a=(arc *)min_arc;
+b=(arc *)max_arc;
+for (; a<next_arc; a++,b--)
+ (*f)(a->vert,b->vert);
+
+@ The last and probably most crucial component of the data structure
+is the collection of {\it branch nodes}, which will be linked together
+into a binary tree. Given a new vertex |w|, we will ascertain what
+triangle it belongs to by starting at the root of this tree and
+executing a sequence of instructions, each of which has the form `if
+|w| lies to the right of the straight line from |u| to~|v| then go to
+$\alpha$ else go to~$\beta$', where $\alpha$ and~$\beta$ are nodes
+that continue the search. This process continues until we reach a
+terminal node, which says `congratulations, you're done, |w|~is in
+triangle such-and-such'. The terminal node points to one of the three
+arcs bounding that triangle. If a vertex of the triangle is~$\infty$,
+the terminal node points to the arc whose |vert| pointer is~|NULL|.
+
+@<Type...@>=
+typedef struct n_struct {
+ Vertex *u; /* first vertex, or |NULL| if this is a terminal node */
+ Vertex *v; /* second vertex, or pointer to the triangle
+ corresponding to a terminal node */
+ struct n_struct *l; /* go here if |w| lies to the left of $uv$ */
+ struct n_struct *r; /* go here if |w| lies to the right of $uv$ */
+} node;
+
+@ The search tree just described is actually a dag (a directed acyclic
+graph), because it has overlapping subtrees. As the algorithm proceeds,
+the dag gets bigger and bigger, since the number of triangles keeps
+growing. Instructions are never deleted; we just extend the dag by
+substituting new branches for nodes that once were terminal.
+
+The expected number of nodes in this dag is $O(n)$ when there are $n$~vertices,
+if we input the vertices in random order. But it can be as high as order~$n^2$
+in the worst case. So our program will allocate blocks of nodes dynamically
+instead of assuming a maximum size.
+
+@d nodes_per_block 127 /* on most computers we want it $\equiv 15$ (mod 16) */
+@d new_node(x)
+ if (next_node==max_node) {
+ x=gb_alloc_type(nodes_per_block,@[node@],working_storage);
+ if (x==NULL) {
+ gb_free(working_storage); /* release |delaunay|'s auxiliary memory */
+ return; /* |gb_alloc_trouble| is nonzero */
+ }
+ next_node=x+1; max_node=x+nodes_per_block;
+ } else x=next_node++;
+@#
+@d terminal_node(x,p) {@+new_node(x); /* allocate a new node */
+ x->v=(Vertex*)(p); /* make it point to a given arc from the triangle */
+} /* note that |x->u==NULL|, representing a terminal node */
+
+@<Local variables for |delaunay|@>=
+node *next_node; /* the first yet-unused node slot
+ in the current block of nodes */
+node *max_node; /* address of nonexistent node following the current
+ block of nodes */
+node root_node; /* start here to locate a vertex in its triangle */
+Area working_storage; /* where |delaunay| builds its triangulation */
+
+@ The algorithm begins with a trivial triangulation that contains
+only the first two vertices, together with two ``triangles'' extending
+to infinity at their left and right.
+
+@<Initialize the data structures@>=
+next_node=max_node=NULL;
+init_area(working_storage);
+@<Initialize the array of arcs@>;
+u=g->vertices;
+v=u+1;
+@<Make two ``triangles'' for |u|, |v|, and $\infty$@>;
+
+@ We'll need a bunch of local variables to do elementary operations on
+data structures.
+
+@<Local variables for |delaunay|@>=
+Vertex *p, *q, *r, *s, *t, *tp, *tpp, *u,*v,*w;
+arc *a,*aa,*b,*c,*d, *e;
+node *x,*y,*yp,*ypp;
+
+@ @<Make two ``triangles'' for |u|, |v|, and $\infty$@>=
+root_node.u=u; root_node.v=v;
+a=next_arc;
+terminal_node(x,a+1);
+root_node.l=x;
+a->vert=v;@+a->next=a+1;@+a->inst=x;
+(a+1)->next=a+2;@+(a+1)->inst=x; /* |(a+1)->vert=NULL|, representing $\infty$ */
+(a+2)->vert=u;@+(a+2)->next=a;@+(a+2)->inst=x;
+mate(a,b);
+terminal_node(x,b-2);
+root_node.r=x;
+b->vert=u;@+b->next=b-2;@+b->inst=x;
+(b-2)->next=b-1;@+(b-2)->inst=x; /* |(b-2)->vert=NULL|, representing $\infty$ */
+(b-1)->vert=v;@+(b-1)->next=b;@+(b-1)->inst=x;
+next_arc+=3;
+
+@*Delaunay updating.
+The main loop of the algorithm updates the data structure incrementally
+by adding one new vertex at a time. The new vertex will always be connected
+by an edge (i.e., by two arcs) to each of the vertices of the triangle that
+previously enclosed it. It may also deserve to be connected to other
+nearby vertices.
+
+@<Find the Delaunay triangulation...@>=
+if (g->n<2) return; /* no edges unless there are at least 2 vertices */
+@<Initialize the data structures@>;
+for (p=g->vertices+2;p<g->vertices+g->n;p++) {
+ @<Find an arc |a| on the boundary of the triangle containing |p|@>;
+ @<Divide the triangle left of |a| into three triangles surrounding |p|@>;
+ @<Explore the triangles surrounding |p|, ``flipping'' their neighbors
+ until all triangles that should touch |p| are found@>;
+}
+
+@ We have set up the branch nodes so that they solve the triangle location
+problem.
+
+@<Find an arc |a| on the boundary of the triangle containing |p|@>=
+x=&root_node;
+do {
+ if (ccw(x->u,x->v,p))
+ x = x->l;
+ else x = x->r;
+} while (x->u);
+a = (arc*) x->v; /* terminal node points to the arc we want */
+
+@ Subdividing a triangle is an easy exercise in data structure manipulation,
+except that we must do something special when one of the vertices is
+infinite. Let's look carefully at what needs to be done.
+
+Suppose the triangle containing |p| has the vertices |q|, |r|, and |s|
+in counterclockwise order. Let |x| be the terminal node that points to
+the triangle~$\Delta qrs$. We want to change |x| so that we will be
+able to locate a future point of $\Delta qrs$ within either $\Delta pqr$,
+$\Delta prs$, or $\Delta psq$.
+
+If |q|, |r|, and |s| are finite, we will change |x| and add five new nodes
+as follows:
+$$\vbox{\halign{\hfil#:\enspace&#\hfil\cr
+$x$&if left of $rp$, go to $x''$, else go to $x'$;\cr
+$x'$&if left of $sp$, go to $y$, else go to $y'$;\cr
+$x''$&if left of $qp$, go to $y'$, else go to $y''$;\cr
+$y$&you're in $\Delta prs$;\cr
+$y'$&you're in $\Delta psq$;\cr
+$y''$&you're in $\Delta pqr$.\cr}}$$
+
+But if, say, $q=\infty$, such instructions make no sense,
+because there are lines in all directions that run from $\infty$ to any point.
+In such a case we use ``wedges'' instead of triangles, as explained below.
+
+At the beginning of the following code, we have |x==a->inst|.
+
+@<Divide the triangle left of |a| into three triangles surrounding |p|@>=
+b=a->next;@+c=b->next;
+q=a->vert;@+r=b->vert;@+s=c->vert;
+@<Create new terminal nodes |y|, |yp|, |ypp|, and new arcs pointing to them@>;
+if (q==NULL) @<Compile instructions to update convex hull@>
+else {@+register node *xp;
+ x->u=r;@+x->v=p;
+ new_node(xp);
+ xp->u=q;@+xp->v=p;@+xp->l=yp;@+xp->r=ypp; /* instruction $x''$ above */
+ x->l=xp;
+ new_node(xp);
+ xp->u=s;@+xp->v=p;@+xp->l=y;@+xp->r=yp; /* instruction $x'$ above */
+ x->r=xp;
+}
+
+@ The only subtle point here is that |q=a->vert| might be |NULL|. A terminal
+node must point to the proper arc of an infinite triangle.
+
+@<Create new terminal nodes |y|, |yp|, |ypp|, and new arcs pointing to them@>=
+terminal_node(yp,a);@+terminal_node(ypp,next_arc);@+terminal_node(y,c);
+c->inst=y;@+a->inst=yp;@+b->inst=ypp;
+mate(next_arc,e);
+a->next=e;@+b->next=e-1;@+c->next=e-2;
+next_arc->vert=q;@+next_arc->next=b;@+next_arc->inst=ypp;
+(next_arc+1)->vert=r;@+(next_arc+1)->next=c;@+(next_arc+1)->inst=y;
+(next_arc+2)->vert=s;@+(next_arc+2)->next=a;@+(next_arc+2)->inst=yp;
+e->vert=(e-1)->vert=(e-2)->vert=p;
+e->next=next_arc+2;@+(e-1)->next=next_arc;@+(e-2)->next=next_arc+1;
+e->inst=yp;@+(e-1)->inst=ypp;@+(e-2)->inst=y;
+next_arc += 3;
+
+@ Outside of the current convex hull, we have ``wedges'' instead of
+triangles; these are exterior angles such that a point lies outside the
+edge $rs$ of the convex hull, but not outside the next edge on the other
+side of point |r|. When a new point lies in such a wedge, we have to
+see if it also lies outside the edges $st$, $tu$, etc., in the
+clockwise direction, in which case the convex hull loses points
+$s$, $t$, etc., and we must update the new wedges accordingly.
+
+This was the hardest part of the program to prove correct; a complete
+proof can be found in {\sl Axioms and Hulls}.
+
+@<Compile...@>=
+{@+register node *xp;
+ arc *aa;
+ x->u=r;@+x->v=p;@+x->l=ypp;
+ new_node(xp);
+ xp->u=s;@+xp->v=p;@+xp->l=y;@+xp->r=yp;
+ x->r=xp;
+ mate(a,aa);@+d=aa->next;@+t=d->vert;
+ while (t!=r && (ccw(p,s,t))) {@+register node *xpp;
+ terminal_node(xpp,d);
+ xp->r=d->inst;
+ xp=d->inst;
+ xp->u=t;@+xp->v=p;@+xp->l=xpp;@+xp->r=yp;
+ flip(a,aa,d,s,NULL,t,p,xpp,yp);
+ a=aa->next;@+mate(a,aa);@+d=aa->next;
+ s=t;@+t=d->vert;
+ yp->v=(Vertex*)a;
+ }
+ terminal_node(xp,d->next);
+ x=d->inst;@+x->u=s;@+x->v=p;@+x->l=xp;@+x->r=yp;
+ d->inst=xp;@+d->next->inst=xp;@+d->next->next->inst=xp;
+ r=s; /* this value of |r| shortens the exploration step that follows */
+}
+
+@ The updating process finishes by walking around the triangles
+that surround |p|, making sure that none of them are adjacent to
+triangles containing |p| in their circumcircle. (Such triangles are
+no longer in the Delaunay triangulation, by definition.)
+
+@<Explore...@>=
+while(1) {
+ mate(c,d);@+e=d->next;
+ t=d->vert;@+tp=c->vert;@+tpp=e->vert;
+ if (tpp && incircle(tpp,tp,t,p)) { /* triangle $tt''t'$ no longer Delaunay */
+ register node *xp, *xpp;
+ terminal_node(xp,e);
+ terminal_node(xpp,d);
+ x=c->inst;@+x->u=tpp;@+x->v=p;@+x->l=xp;@+x->r=xpp;
+ x=d->inst;@+x->u=tpp;@+x->v=p;@+x->l=xp;@+x->r=xpp;
+ flip(c,d,e,t,tp,tpp,p,xp,xpp);
+ c=e;
+ }
+ else if (tp==r) break;
+ else {
+ mate(c->next,aa);
+ c=aa->next;
+ }
+}
+
+@ Here |d| is the mate of |c|, |e=d->next|, |t=d->vert|, |tp=c->vert|,
+and |tpp=e->vert|. The triangles $\Delta tt'p$ and $\Delta t'tt''$ to the
+left and right of arc~|c| are being replaced in the current triangulation
+by $\Delta ptt''$ and $\Delta t''t'p$, corresponding to terminal nodes
+|xp| and |xpp|.
+
+@<Other...@>=
+flip(c,d,e,t,tp,tpp,p,xp,xpp)
+ arc *c,*d,*e;
+ Vertex *t,*tp,*tpp,*p;
+ node *xp,*xpp;
+{@+register arc *ep=e->next, *cp=c->next, *cpp=cp->next;
+ e->next=c;@+c->next=cpp;@+cpp->next=e;
+ e->inst=c->inst=cpp->inst=xp;
+ c->vert=p;
+ d->next=ep;@+ep->next=cp;@+cp->next=d;
+ d->inst=ep->inst=cp->inst=xpp;
+ d->vert=tpp;
+}
+
+@*Use of mileage data. The |delaunay| routine is now complete, and the
+only missing piece of code is the promised routine that generates
+planar graphs based on data from the real world.
+
+The subroutine call
+|plane_miles(n,north_weight,west_weight,pop_weight, extend,prob,seed)|
+will construct a planar graph with min$(128,n)$ vertices, where the
+vertices are exactly the same as the cities produced by the subroutine
+call |miles(n,north_weight,west_weight, pop_weight,0,0,seed)|. (As
+explained in module |gb_miles|, the weight parameters |north_weight|,
+|west_weight|, and |pop_weight| are used to rank the cities by
+location and/or population.) The edges of the new graph are obtained
+by first constructing the Delaunay triangulation of those cities,
+based on a simple projection onto the plane using their latitude and
+longitude, then discarding each Delaunay edge with probability
+|prob/65536|. The length of each surviving edge is the same as the
+mileage between cities that would appear in the complete graph
+produced by |miles|.
+
+If |extend!=0|, an additional vertex representing $\infty$ is also
+included. The Delaunay triangulation includes edges of length |INFTY|
+connecting this vertex with all cities on the convex hull; these edges,
+like the others, are subject to being discarded with probability |prob/65536|.
+(See the description of |plane| for further comments about the use of
+|prob| to control the sparseness of the graph.)
+
+The weight parameters must satisfy
+$$ \vert|north_weight|\vert\le100{,}000,\quad
+ \vert|west_weight|\vert\le100{,}000,\quad
+ \vert|pop_weight|\vert\le100.$$
+Vertices of the graph will appear in order of decreasing weight.
+The |seed| parameter defines the pseudo-random numbers used wherever
+a ``random'' choice between equal-weight vertices needs to be made,
+or when deciding whether to discard a Delaunay edge.
+
+@<The |plane_miles| routine@>=
+Graph *plane_miles(n,north_weight,west_weight,pop_weight,extend,prob,seed)
+ unsigned n; /* number of vertices desired */
+ int north_weight; /* coefficient of latitude in the weight function */
+ int west_weight; /* coefficent of longitude in the weight function */
+ int pop_weight; /* coefficient of population in the weight function */
+ unsigned extend; /* should a point at infinity be included? */
+ unsigned prob; /* probability of rejecting a Delaunay edge */
+ long seed; /* random number seed */
+{@+Graph *new_graph; /* the graph constructed by |plane_miles| */
+ @<Use |miles| to set up the vertices of a graph@>;
+ @<Compute the Delaunay triangulation and
+ run through the Delaunay edges; reject them with probability
+ |prob/65536|, otherwise append them with the road length in miles@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ gb_free(new_graph->aux_data); /* recycle special memory used by |miles| */
+ if (extend) new_graph->n++; /* make the ``infinite'' vertex legitimate */
+ return new_graph;
+}
+
+@ By setting the |max_distance| parameter to~1, we cause |miles|
+to produce a graph having the desired vertices but no edges.
+The vertices of this graph will have appropriate coordinate fields
+|x_coord|, |y_coord|, and~|z_coord|.
+
+@<Use |miles|...@>=
+if (extend) extra_n++; /* allocate one more vertex than usual */
+if (n==0 || n>MAX_N) n=MAX_N; /* compute true number of vertices */
+new_graph=miles(n,north_weight,west_weight,pop_weight,1,0,seed);
+if (new_graph==NULL) return; /* |panic_code| has been set by |miles| */
+sprintf(new_graph->id,"plane_miles(%u,%d,%d,%d,%u,%u,%ld)",
+ n,north_weight,west_weight,pop_weight,extend,prob,seed);
+if (extend) extra_n--; /* restore |extra_n| to its previous value */
+
+@ @<Compute the Delaunay triangulation and
+ run through the Delaunay edges; reject them with probability
+ |prob/65536|, otherwise append them with the road length in miles@>=
+gprob=prob;
+if (extend) {
+ inf_vertex=new_graph->vertices+new_graph->n;
+ inf_vertex->name=gb_save_string("INF");
+ inf_vertex->x_coord=inf_vertex->y_coord=inf_vertex->z_coord= -1;
+} else inf_vertex=NULL;
+delaunay(new_graph,new_mile_edge);
+
+@ The mileages will all have been negated by |miles|, so we make them
+positive again.
+
+@<Other...@>=
+void new_mile_edge(u,v)
+ Vertex *u,*v;
+{@+register long dx,dy;
+ if ((gb_next_rand()>>15)>=gprob) {
+ if (u) {
+ if (v) {
+ gb_new_edge(u,v,-miles_distance(u,v));
+ } else if (inf_vertex) gb_new_edge(u,inf_vertex,INFTY);
+ } else if (inf_vertex) gb_new_edge(inf_vertex,v,INFTY);
+ }
+}
+
+@* Index. As usual, we close with an index that
+shows where the identifiers of \\{gb\_plane} are defined and used.
diff --git a/support/graphbase/gb_raman.w b/support/graphbase/gb_raman.w
new file mode 100644
index 0000000000..243796ef15
--- /dev/null
+++ b/support/graphbase/gb_raman.w
@@ -0,0 +1,715 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace RAMAN}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\let\==\equiv % congruence sign
+
+\prerequisite{GB\_\thinspace GRAPH}
+@* Introduction. This GraphBase module contains the |raman| subroutine,
+which creates a family of ``Ramanajun graphs'' based on a theory
+developed by Alexander Lubotzky, Ralph Phillips, and Peter Sarnak
+[see {\sl Combinatorica \bf8} (1988), 261--277].
+
+Ramanujan graphs are defined by the following properties:
+They are connected, undirected graphs in which every vertex has
+degree~|k|, and every eigenvalue of the adjacency matrix
+is either $\pm k$ or has absolute value $\le2\sqrt{\mathstrut k-1}$.
+Such graphs are known to have good expansion properties, small diameter,
+and relatively small independent sets; they cannot be colored with
+fewer than $k/\bigl(2\sqrt{\mathstrut k-1}\,\bigr)$ colors unless they are
+bipartite. The particular examples of Ramanujan graphs constructed here
+are based on interesting properties of quaternions with integer coefficients.
+
+An example of the use of this procedure can be found in the demo program
+called |girth|.
+
+@(gb_raman.h@>=
+extern Graph *raman();
+
+@ The subroutine call `|raman(p,q,type,reduce)|'
+constructs an undirected graph in which each vertex has degree~|p+1|.
+The number of vertices is~|q+1| if |type=1|, or~${1\over2}q(q+1)$ if |type=2|,
+or ${1\over2}(q-1)q(q+1)$ if |type=3|, or |(q-1)q(q+1)| if
+|type=4|. The graph will be bipartite if and only if it has type~4.
+Parameters |p| and |q| must be distinct prime numbers,
+and |q|~must be odd. Furthermore there are additional restrictions:
+If |p=2|, the other parameter |q| must satisfy $q\bmod8\in\{1,3\}$
+and $q\bmod13\in{1,3,4,9,10,12}$; this rules out about one fourth of
+all primes. Moreover, if |type=3| the value of |p| must be a
+quadratic residue modulo~$q$; in other words, there must be an
+integer~$x$ such that $x^2\=p$ (mod~$q$). If |type=4|, the value of |p|
+must not be a quadratic residue.
+
+If you specify |type=0|, the procedure
+will choose the largest permissible type (either 3 or~4);
+the value of the type selected will
+appear as part of the string placed in the resulting graph's |id| field.
+For example, if |type=0|, |p=2|, and |q=43|, a type~4 graph will be
+generated, because 2 is not a quadratic residue modulo~43. This
+graph will have $44\times43\times42=79464$ vertices, each of degree~3.
+(Notice that graphs of types 3 and~4 can be quite large even when
+|q| is rather small.)
+
+The largest permissible value of |q| is 46337; this is the largest
+prime whose square is less than $2^{31}$. Of course you would use
+it only for a graph of type~1.
+
+If |reduce| is nonzero, loops and multiple edges will be suppressed.
+In this case the degrees of some vertices may turn out to be less than~|p+1|,
+in spite of what was said above.
+
+Although type 4 graphs are bipartite, the vertices
+are not separated into two blocks as in other bipartite
+graphs produced by GraphBase routines.
+
+All edges of the graphs have length 1.
+
+@ If the |raman| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |raman| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in
+|gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@d dead_panic(c) {@+gb_free(working_storage);@+panic(c);@+}
+@d late_panic(c) {@+gb_recycle(new_graph);@+dead_panic(c);@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@ The \Cee\ file \.{gb\_raman.c} has the following general shape:
+
+@p
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+@#
+@<Type declarations@>@;
+@<Private variables and routines@>@;
+@#
+Graph *raman(p,q,type,reduce)
+ int p; /* one less than the desired degree; must be prime */
+ int q; /* size parameter; must be prime and properly related to |type| */
+ unsigned type; /* selector between different possible constructions */
+ unsigned reduce; /* if nonzero, multiple edges and self-loops won't occur */
+{@+@<Local variables@>@;
+ @<Prepare tables for doing arithmetic modulo~|q|@>;
+ @<Choose or verify the |type|, and determine the number |n| of vertices@>;
+ @<Set up a graph with |n| vertices, and assign vertex labels@>;
+ @<Compute |p+1| generators that will define the graph's edges@>;
+ @<Append the edges@>;
+ if (gb_alloc_trouble)
+ late_panic(alloc_fault);
+ /* oops, we ran out of memory somewhere back there */
+ gb_free(working_storage);
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |raman| */
+Area working_storage; /* place for auxiliary tables */
+
+@* Brute force number theory. Instead of using routines like Euclid's
+algorithm to compute inverses and square roots modulo~|q|, we have
+plenty of time to build complete tables, since |q| is smaller than
+the number of vertices we will be generating.
+
+We will make three tables: |q_sqr[k]| will contain $k^2$ modulo~|q|;
+|q_sqrt[k]| will contain one of the values of $\sqrt{\mathstrut k}$
+if $k$ is a quadratic residue; and |q_inv[k]| will contain the multiplicative
+inverse of~|k|.
+
+@<Private...@>=
+static int *q_sqr; /* squares */
+static int *q_sqrt; /* square roots (or $-1$ if not a quadratic residue) */
+static int *q_inv; /* reciprocals */
+
+@ @<Prepare tables for doing arithmetic modulo~|q|@>=
+if (q<3 || q>46337) panic(very_bad_specs);
+ /* |q| is way too small or way too big */
+if (p<2) panic(very_bad_specs+1); /* |p| is way too small */
+init_area(working_storage);
+q_sqr=gb_alloc_type(3*q,@[int@],working_storage);
+if (q_sqr==0) panic(no_room+1);
+q_sqrt=q_sqr+q;
+q_inv=q_sqrt+q; /* note that |gb_alloc| has initialized everything to zero */
+@<Compute the |q_sqr| and |q_sqrt| tables@>;
+@<Find a primitive root |a|, modulo |q|, and its inverse |aa|@>;
+@<Compute the |q_inv| table@>;
+
+@ @<Compute the |q_sqr| and |q_sqrt| tables@>=
+for (a=1; a<q; a++) q_sqrt[a]=-1;
+for (a=1,aa=1; a<q; aa=(aa+a+a+1)%q,a++) {
+ q_sqr[a]=aa;
+ q_sqrt[aa]=q-a; /* the smaller square root will survive */
+ q_inv[aa]=-1;
+ /* we make |q_inv[aa]| nonzero when |aa| can't be a primitive root */
+}
+
+@ @<Local v...@>=
+register int a, aa, k; /* primary indices in loops */
+int b, bb, c, cc, d, dd; /* secondary indices */
+int n; /* the number of vertices */
+int n_factor; /* either ${1\over2}(q-1)$ (type~3) or $q-1$ (type 4) */
+register Vertex *v; /* the current vertex of interest */
+
+@ Here we implicitly test that |q| is prime, by finding a primitive
+root whose powers generate everything. If |q| is not prime, its smallest
+divisor will cause the inner loop in this step to terminate with |k>=q|,
+because no power of that divisor will be congruent to~1.
+
+@<Find a primitive root |a|, modulo |q|, and its inverse |aa|@>=
+for (a=2; ; a++)
+ if (q_inv[a]==0) {
+ for (b=a,k=1; b!=1&&k<q; aa=b,b=(a*b)%q,k++) q_inv[b]=-1;
+ if (k>=q) dead_panic(bad_specs+1); /* |q| is not prime */
+ if (k==q-1) break; /* good, |a| is the primitive root we seek */
+ }
+
+@ As soon as we have discovered
+a primitive root, it is easy to generate all the inverses. (We
+could also generate the discrete logarithms if we had a need for them.)
+
+We set |q_inv[0]=q|; this will be our internal representation of $\infty$.
+
+@<Compute the |q_inv| table@>=
+for (b=a,bb=aa; b!=bb; b=(a*b)%q,bb=(aa*bb)%q) q_inv[b]=bb,q_inv[bb]=b;
+q_inv[1]=1; q_inv[b]=b; /* at this point |b| must equal |q-1| */
+q_inv[0]=q;
+
+@ The conditions we stated for validity of |q| when |p=2| are equivalent
+to the existence of $\sqrt{-2}$ and $\sqrt{13}$ modulo~|q|, according
+to the law of quadratic reciprocity (see, for example, {\sl Fundamental
+Algorithms}, exercise 1.2.4--47).
+
+@<Choose or verify the |type|...@>=
+if (p==2) {
+ if (q_sqrt[13%q]<0 || q_sqrt[q-2]<0)
+ dead_panic(bad_specs+2); /* improper prime to go with |p=2| */
+}
+if ((a=p%q)==0) dead_panic(bad_specs+3); /* |p| divisible by |q| */
+if (type==0) type=(q_sqrt[a]>0? 3: 4);
+n_factor=(type==3? (q-1)/2: q-1);
+switch (type) {
+ case 1: n=q+1;@+break;
+ case 2: n=q*(q+1)/2;@+break;
+ default: if ((q_sqrt[a]>0 && type!=3) || (q_sqrt[a]<0 && type!=4))
+ dead_panic(bad_specs+4); /* wrong type for |p| modulo |q| */
+ if (q>1289) dead_panic(bad_specs+5); /* way too big for types 3, 4 */
+ n=n_factor*q*(q+1);
+ break;
+}
+if (p>=(long)(0x3fffffff/n)) dead_panic(bad_specs+6); /* $(p+1)n\ge2^{30}$ */
+
+@* The vertices. Graphs of type 1 will have vertices from the
+set $\{0,1,\ldots,q-1,\infty\}$, namely the integers modulo~|q| with
+an additional ``infinite'' element thrown in. The idea will be to
+operate on these quantities by adding constants, and/or multiplying by
+constants, and/or taking reciprocals, modulo~|q|.
+
+Graphs of type 2 will have vertices that are unordered pairs of
+distinct elements from that same set.
+
+Graphs of types 3 and 4 will have vertices that are $2\times2$ matrices
+having nonzero determinants modulo~|q|. The determinants of type~3 matrices
+will, in fact, be nonzero quadratic residues. We consider two matrices to be
+equivalent if one is obtained from the other by multiplying all entries
+by a constant (modulo~|q|); therefore we will normalize all the matrices
+so that the second row is either $(0,1)$ or has the form $(1,x)$ for
+some~$x$. The total number of equivalence classes of type~4 matrices obtainable
+in this way is $(q+1)q(q-1)$, because we can choose the second row in
+$q+1$ ways, after which there are two cases: Either the second row is
+$(0,1)$, and we can select the upper right corner element arbitrarily
+and choose the upper left corner element nonzero; or the second row is $(1,x)$,
+and we can select the upper left corner element arbitrarily and then choose
+an upper right corner element to make the determinant nonzero. For type~3
+the counting is similar, except that ``nonzero'' becomes ``nonzero
+quadratic residue,'' hence there are exactly half as many choices.
+
+It is easy to verify that the equivalence classes of matrices that
+correspond to vertices in these graphs of types 3 and~4 are closed
+under matrix multiplication. Therefore the vertices may be regarded as the
+elements of finite groups. The type~3 group for a given |q| is often
+called the linear fractional group $LF(2,{\bf F}_q)$, or the
+projective special linear group $PSL(2,{\bf F}_q)$, or the linear
+simple group $L_2(q)$; it can also be regarded as the group of
+$2\times2$ matrices with determinant~1 (mod~$q$), when the matrix $A$
+is considered equivalent to $-A$. (This group is a simple group for
+all primes |q>2|.) The type~4 group is officially known as the
+projective general linear group of degree~2 over the field of |q|~elements,
+$PGL(2,{\bf F}_q)$.
+
+@<Set up a graph...@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ dead_panic(no_room); /* out of memory before we try to add edges */
+sprintf(new_graph->id,"raman(%d,%d,%u,%u)",p,q,type,reduce);
+strcpy(new_graph->format,"ZZZIIZIZZZZZZZ");
+v=new_graph->vertices;
+switch(type) {
+ case 1: @<Assign labels from the set $\{0,1,\ldots,q-1,\infty\}$@>;@+break;
+ case 2: @<Assign labels for pairs of distinct elements@>;@+break;
+ default: @<Assign projective matrix labels@>;@+break;
+}
+
+@ Type 1 graphs are the easiest to label. We store a serial number
+in utility field |x.i|, using $q$ to represent $\infty$.
+
+@<Assign labels from the set $\{0,1,\ldots,q-1,\infty\}$@>=
+new_graph->format[4]='Z';
+for (a=0;a<q;a++) {
+ sprintf(name_buf,"%d",a);
+ v->name=gb_save_string(name_buf);
+ v->x.i=a;
+ v++;
+}
+v->name=gb_save_string("INF");
+v->x.i=q;
+v++;
+
+@ @<Private...@>=
+static char name_buf[]="(1111,1111;1,1111)"; /* place to form vertex names */
+
+@ The type 2 labels run from $\{0,1\}$ to $\{q-1,\infty\}$; we put the
+coefficients into |x.i| and |y.i|, where they might prove useful in
+some applications.
+
+@<Assign labels for pairs...@>=
+for (a=0;a<q;a++)
+ for (aa=a+1;aa<=q;aa++) {
+ if (aa==q) sprintf(name_buf,"{%d,INF}",a);
+ else sprintf(name_buf,"{%d,%d}",a,aa);
+ v->name=gb_save_string(name_buf);
+ v->x.i=a;@+v->y.i=aa;
+ v++;
+ }
+
+@ For graphs of types 3 and 4, we set the |x.i| and |y.i| fields to
+the elements of the first row of the matrix, and we set the |z.i|
+field equal to the ratio of the elements of the second row (again with $q$
+representing~$\infty$).
+
+The vertices in this case will consist of |q(q+1)| blocks of vertices
+having a given second row and a given element in the upper left or upper right
+position. Within each block of vertices, the determinants will
+be respectively congruent modulo~|q| to $1^2$, $2^2$, \dots,~$({q-1\over2})^2$
+in the case of type~3 graphs, or to 1,~2, \dots,~$q-1$ in the case of type~4.
+
+@<Assign projective matrix labels@>=
+new_graph->format[5]='I';
+for (c=0;c<=q;c++)
+ for (b=0;b<q;b++)
+ for (a=1;a<=n_factor;a++) {
+ v->z.i=c;
+ if (c==q) { /* second row of matrix is $(0,1)$ */
+ v->y.i=b;
+ v->x.i=(type==3? q_sqr[a]: a); /* determinant is $a^2$ or $a$ */
+ sprintf(name_buf,"(%d,%d;0,1)",v->x.i,b);
+ } else { /* second row of matrix is $(1,c)$ */
+ v->x.i=b;
+ v->y.i=(b*c+q-(type==3? q_sqr[a]: a))%q;
+ sprintf(name_buf,"(%d,%d;1,%d)",b,v->y.i,c);
+ } /* determinant is $a^2$ or $a$ */
+ v->name=gb_save_string(name_buf);
+ v++;
+ }
+
+@* Group generators. We will define a set of |p+1| permutations $\{\pi_0,
+\pi_1,\ldots,\pi_p\}$ of the vertices, such that the arcs of our graph will
+go from $v$ to $v\pi_k$ for |0<=k<=p|. Thus, each path in the graph will be
+defined by a product of permutations; the cycles of the graph will correspond
+to vertices that are left fixed by a product of permutations.
+The graph will be undirected, because the inverse of each $\pi_k$ will
+also be one of the permutations of the generating set.
+
+In fact, each permutation $\pi_k$ will be defined by a $2\times2$ matrix;
+for graphs of types 3 and~4, the permutations will therefore correspond to
+certain vertices, and the vertex $v\pi_k$ will simply be the product of matrix
+$v$ by matrix $\pi_k$.
+
+For graphs of type 1, the permutations will be defined by linear fractional
+transformations, which are mappings of the form
+$$v\;\longmapsto\; {av+b\over
+ cv+d}\bmod q\,.$$
+This transformation applies
+to all $v\in\{0,1,\ldots,q-1,\infty\}$, under the usual conventions
+that $x/0=\infty$ when $x\ne0$ and $(x\infty+x')/(y\infty+y')=x/y$.
+The composition of two such transformations is again a linear fractional
+transformation, corresponding to the product of the two associated
+matrices $\bigl({a\,b\atop c\,d}\bigr)$.
+
+Graphs of type 2 will be handled just like graphs of type 1,
+except that we will compute the images of two distinct points
+$v=\{v_1,v_2\}$ under the linear fractional transformation. The two
+images will be distinct, because the transformation is invertible.
+
+When |p=2|, a special set of three generating matrices $\pi_0$, $\pi_1$,
+$\pi_2$ can be shown to define Ramanujan graphs; these matrices are
+described below. Otherwise |p| is odd, and the generators are based on the
+theory of integral quaternions. Integral quaternions are quadruples of the form
+$\alpha=a_0+a_1i+a_2j+a_3k$, where $a_0$, $a_1$, $a_2$, and~$a_3$ are
+integers; we multiply them by using the associative but
+noncommutative multiplication rules $i^2=j^2=k^2=ijk=-1$. If we write
+$\alpha=a+A$, where $a$ is the ``scalar'' $a_0$ and $A$ is the ``vector''
+$a_1i+a_2j+a_3k$, the product of quaternions $\alpha=a+A$ and $\beta=b+B$
+can be expressed as
+$$(a+A)(b+B)=ab-A\cdot B+aB+bA+A\times B\,,$$
+where $A\cdot B$ and $A\times B$ are the usual dot product and cross
+product of vectors. The conjugate of $\alpha=a+A$ is $\overline\alpha=a-A$,
+and we have $\alpha\overline\alpha=a_0^2+a_1^2+a_2^2+a_3^2$. This
+important quantity is called $N(\alpha)$, the norm of $\alpha$. It
+is not difficult to verify that $N(\alpha\beta)=N(\alpha)N(\beta)$,
+because we have $\overline{\mathstrut\alpha\beta}=\overline{\mathstrut\beta}
+\,\overline{\mathstrut\alpha}$ and $\alpha x=x\alpha$ when $x$ is scalar.
+
+Integral quaternions have a beautiful theory; for example, there is a
+nice variant of Euclid's algorithm by which we can compute the greatest
+common left divisor of any two integral quaternions, and this makes
+it possible to prove that integral quaternions whose coefficients are
+relatively prime can be uniquely factored into quaternions whose norm is
+prime. However, the details of that theory are beyond the scope of this
+documentation. It will suffice for our purposes
+to observe that we can use quaternions to define the finite groups
+$PSL(2,{\bf F}_q)$ and $PGL(2,{\bf F}_q)$ in a different way from the
+definitions given earlier: Suppose
+we consider two quaternions to be equivalent if their coefficients are
+equal modulo~|q|, or if one is a nonzero scalar multiple of the other
+(modulo~|q|). Thus, for example, if $q=3$ we consider $1+4i-j$ to
+be equivalent to $1+i+2j$, and also equivalent to $2+2i+j$.
+It turns out that there are exactly $(q+1)q(q-1)$ such equivalence classes,
+and they form a group under quaternion multiplication that is the same as the
+projective group of $2\times2$ matrices under matrix multiplication,
+modulo~|q|. One way to prove this
+is by means of the one-to-one correspondence
+$$a_0+a_1i+a_2j+a_3k\;\longleftrightarrow\;
+ \left(\matrix{a_0+a_1g+a_3h&a_2+a_3g-a_1h\cr
+ -a_2+a_3g-a_1h&a_0-a_1g-a_3h\cr}\right)\,,$$
+where $g$ and $h$ are integers with $g^2+h^2\=-1$ (mod~|q|).
+
+Jacobi proved that the number of ways to represent
+any odd number |p| as a sum of four squares $a_0^2+a_1^2+a_2^2+a_3^2$
+is 8 times the sum of divisors of~|p|. [This fact appears in the
+concluding sentence of his monumental work {\sl Fundamenta Nova
+Theori\ae\ Functionum Ellipticorum}, K\"onigsberg, 1829.]
+In particular, when |p| is prime,
+the number of such representations is $8(p+1)$; in other words, there are
+exactly $8(p+1)$ quaternions $\alpha=a_0+a_1i+a_2j+a_3k$ with $N(\alpha)=p$.
+These quaternions form |p+1| equivalence classes under multiplication
+by the eight ``unit quaternions'' $\{\pm1,\pm i,\pm j,\pm k\}$; we will
+select one element from each equivalence class, and the resulting |p+1|
+quaternions will correspond to |p+1| matrices, which will generate the |p+1|
+arcs leading from each vertex in the graphs to be constructed.
+
+@<Type de...@>=
+typedef struct {
+ long a0,a1,a2,a3; /* coefficients of a quaternion */
+ unsigned bar; /* the index of the inverse (conjugate) quaternion */
+} quaternion;
+
+@ A global variable |gen_count| will be declared below,
+indicating the number of generators found so far. When |p| isn't prime,
+we will find more than |p+1| solutions; we allocate one extra slot in
+the |gen| table to hold a possible overflow entry.
+
+@<Compute |p+1| generators...@>=
+gen=gb_alloc_type(p+2,@[quaternion@],working_storage);
+if (gen==NULL) late_panic(no_room+2); /* not enough memory */
+gen_count=0;@+max_gen_count=p+1;
+if (p==2) @<Fill the |gen| table with special generators@>@;
+else @<Fill the |gen| table with representatives of all quaternions
+ having norm~|p|@>;
+if (gen_count!=max_gen_count) late_panic(bad_specs+7); /* |p| is not prime */
+
+@ @<Private...@>=
+static quaternion *gen; /* table of the |p+1| generators */
+
+@ As mentioned above, quaternions of norm |p| come in sets of 8,
+differing from each other only by unit multiples; we need to choose one
+of the~8. Suppose $a_0^2+a_1^2+a_2^2+a_3^2=p$.
+If $p\bmod4=1$, exactly one of the $a$'s will be odd;
+so we call it $a_0$ and assign it a positive sign. When $p\bmod4=3$, exactly
+one of the $a$'s will be even; we call it $a_0$, and if it is nonzero we
+make it positive. If $a_0=0$, we make sure that one of the
+others---say the rightmost appearance of the largest one---is positive.
+In this way we obtain a unique representative from each set of 8 equivalent
+quaternions.
+
+For example, the four quaternions of norm 3 are $\pm i\pm j+k$; the six
+of norm~5 are $1\pm2i$, $1\pm2j$, $1\pm2k$.
+
+In the program here we generate solutions to $a^2+b^2+c^2+d^2=p$ when
+$a\not\=b\=c\=d$ (mod~2) and $b\le c\le d$. The variables |aa|, |bb|, and |cc|
+hold the respective values $p-a^2-b^2-c^2-d^2$, $p-a^2-3b^2$, and
+$p-a^2-2c^2$. The |for| statements use the fact that $a^2$ increases
+by $4(a+1)$ when $a$ increases by~2.
+
+@<Fill the |gen| table with representatives...@>=
+{@+long sa,sb,sc; /* $p-a^2$, $p-a^2-b^2$, $p-a^2-b^2-c^2$ */
+ int pp=(p>>1)&1; /* 0 if $p\bmod4=1$, \ 1 if $p\bmod4=3$ */
+ for (a=1-pp,sa=p-a;sa>0;sa-=(a+1)<<2,a+=2)
+ for (b=pp,sb=sa-b,bb=sb-b-b;bb>=0;bb-=12*(b+1),sb-=(b+1)<<2,b+=2)
+ for (c=b,cc=bb,sc=(sb+cc)>>1;cc>=0;cc-=(c+1)<<3,sc-=(c+1)<<2,c+=2)
+ for (d=c,aa=cc;aa>=0;aa-=(d+1)<<2,d+=2)
+ if (aa==0) @<Deposit the quaternions associated with $a+bi+cj+dk$@>;
+ @<Change the |gen| table to matrix format@>;
+}
+
+@ If |a>0| and |0<b<c<d|, we obtain 48 different classes of quaternions
+having the same norm by permuting $\{b,c,d\}$ in six ways and attaching
+signs to each permutation in eight ways. This happens, for example,
+when $p=71$ and $(a,b,c,d)=(6,1,3,5)$. Fewer quaternions arise when
+|a=0| or |0=b| or |b=c| or |c=d|.
+
+The inverse of the matrix corresponding to a quaternion is the matrix
+corresponding to the conjugate quaternion. Therefore a generating
+matrix $\pi_k$ will be its own inverse if and only if it comes from
+a quaternion with |a=0|.
+
+It is convenient to have a subroutine that deposits a new quaternion
+and its conjugate into the table of generators.
+
+@<Private...@>=
+static unsigned gen_count; /* the next available quaternion slot */
+static unsigned max_gen_count; /* $p+1$, stored as a global variable */
+static void deposit(a,b,c,d)
+ long a,b,c,d; /* a solution to $a^2+b^2+c^2+d^2=p$ */
+{
+ if (gen_count>=max_gen_count) /* oops, we already found |p+1| solutions */
+ gen_count=max_gen_count+1; /* this will happen only if |p| isn't prime */
+ else {
+ gen[gen_count].a0=gen[gen_count+1].a0=a;
+ gen[gen_count].a1=b;@+gen[gen_count+1].a1=-b;
+ gen[gen_count].a2=c;@+gen[gen_count+1].a2=-c;
+ gen[gen_count].a3=d;@+gen[gen_count+1].a3=-d;
+ if (a) {
+ gen[gen_count].bar=gen_count+1;
+ gen[gen_count+1].bar=gen_count;
+ gen_count+=2;
+ } else {
+ gen[gen_count].bar=gen_count;
+ gen_count++;
+ }
+ }
+}
+
+@ @<Deposit...@>=
+{
+ deposit(a,b,c,d);
+ if (b) {
+ deposit(a,-b,c,d);@+deposit(a,-b,-c,d);
+ }
+ if (c) deposit(a,b,-c,d);
+ if (b<c) {
+ deposit(a,c,b,d);@+deposit(a,-c,b,d);@+deposit(a,c,d,b);@+deposit(a,-c,d,b);
+ if (b) {
+ deposit(a,c,-b,d);@+deposit(a,-c,-b,d);@+deposit(a,c,d,-b);@+
+ deposit(a,-c,d,-b);
+ }
+ }
+ if (c<d) {
+ deposit(a,b,d,c);@+deposit(a,d,b,c);
+ if (b) {
+ deposit(a,-b,d,c);@+deposit(a,-b,d,-c);@+deposit(a,d,-b,c);@+
+ deposit(a,d,-b,-c);
+ }
+ if (c) {
+ deposit(a,b,d,-c);@+deposit(a,d,b,-c);
+ }
+ if (b<c) {
+ deposit(a,d,c,b);@+deposit(a,d,-c,b);
+ if (b) {
+ deposit(a,d,c,-b);@+deposit(a,d,-c,-b);
+ }
+ }
+ }
+}
+
+@ Once we've found the generators in quaternion form, we want to
+convert them to $2\times2$ matrices, using the correspondence mentioned
+earlier:
+$$a_0+a_1i+a_2j+a_3k\;\longleftrightarrow\;
+ \left(\matrix{a_0+a_1g+a_3h&a_2+a_3g-a_1h\cr
+ -a_2+a_3g-a_1h&a_0-a_1g-a_3h\cr}\right)\,,$$
+where $g$ and $h$ are integers with $g^2+h^2\=-1$ (mod~|q|).
+Appropriate values for $g$ and~$h$ can always be found by letting
+$g=\sqrt{\mathstrut k}$ and $h=\sqrt{\mathstrut q-1-k}$, where
+$k$ is the largest quadratic residue modulo~|q|. For if $q-1$ is
+not a quadratic residue, and if $k+1$ isn't a residue either, then
+$q-1-k$ must be a quadratic residue because it is congruent to the
+product $(q-1)(k+1)$ of nonresidues. (We will have |h=0| if and
+only if $q\bmod4=1$; |h=1| if and only if $q\bmod8=3$; $h=\sqrt{\mathstrut2}$
+if and only if $q\bmod24=7$ or 15; etc.)
+
+@<Change the |gen| table to matrix format@>=
+{@+register int g,h;
+ int a00,a01,a10,a11; /* entries of $2\times2$ matrix */
+ for (k=q-1;q_sqrt[k]<0;k--) ; /* find the largest quadratic residue, |k| */
+ g=q_sqrt[k];@+h=q_sqrt[q-1-k];
+ for (k=p;k>=0;k--) {
+ a00=(gen[k].a0+g*gen[k].a1+h*gen[k].a3)%q;
+ if (a00<0) a00+=q;
+ a11=(gen[k].a0-g*gen[k].a1-h*gen[k].a3)%q;
+ if (a11<0) a11+=q;
+ a01=(gen[k].a2+g*gen[k].a3-h*gen[k].a1)%q;
+ if (a01<0) a01+=q;
+ a10=(-gen[k].a2+g*gen[k].a3-h*gen[k].a1)%q;
+ if (a10<0) a10+=q;
+ gen[k].a0=a00;@+gen[k].a1=a01;@+gen[k].a2=a10;@+gen[k].a3=a11;
+ }
+}
+
+@ When |p=2|, the following three appropriate generating matrices
+have been found by P.~Chiu:
+$$\left(\matrix{1&0\cr 0&-1\cr}\right)\,,\qquad
+ \left(\matrix{2+s&t\cr t&2-s\cr}\right)\,,\qquad\hbox{and}\qquad
+ \left(\matrix{2-s&-t\cr-t&2+s\cr}\right)\,,$$
+where $s^2\=-2$ and $t^2\=-26$ (mod~$q$). The determinants of
+these matrices are respectively $-1$, $32$, and~$32$; the product of
+the second and third matrices is 32 times the identity matrix. Notice that when
+2 is a quadratic residue (this happens when $q=8k+1$), the determinants
+are all quadratic residues, so we get a graph of type~3;
+when 2 is a quadratic nonresidue (which happens when $q=8k+3$),
+the determinants are all nonresidues, so we get a graph of type~4.
+
+@<Fill the |gen| table with special generators@>=
+{@+int s=q_sqrt[q-2], t=(q_sqrt[13%q]*s)%q;
+ gen[0].a0=1;@+gen[0].a1=gen[0].a2=0;@+gen[0].a3=q-1;@+gen[0].bar=0;
+ gen[1].a0=gen[2].a3=(2+s)%q;
+ gen[1].a1=gen[1].a2=t;
+ gen[2].a1=gen[2].a2=q-t;
+ gen[1].a3=gen[2].a0=(q+2-s)%q;
+ gen[1].bar=2;@+gen[2].bar=1;
+ gen_count=3;
+}
+
+@* Constructing the edges. The remaining task is to use the permutations
+defined by the |gen| table to create the arcs of the graph and
+their inverses.
+
+The |ref| fields in each arc will refer to the permutation leading to the
+arc. In most cases each vertex |v| will have degree exactly |p+1|, and the
+edges emanating from it will appear in a linked list having
+the respective |ref| fields 0,~1, \dots,~|p| in order. However,
+if |reduce| is nonzero, self-loops and multiple edges will be eliminated,
+so the degree may be less than |p+1|; in this case the |ref| fields
+will still be in ascending order, but some generators won't be referenced.
+
+There is also a subtle case where |reduce=0| but the degree of a vertex might
+actually be greater than |p+1|.
+We want the graph |g| generated by |raman| to satisfy the
+conventions for undirected graphs stated in |gb_graph|; therefore,
+if any of the generating permutations has a fixed point, we will create
+two arcs for that fixed point, and the corresponding vertex |v| will
+have an edge running to itself. Since each edge consists of two arcs, such
+an edge will produce two consecutive entries in the list |v->arcs|.
+If the generating permutation happens to be its own inverse,
+there will be two consecutive entries with the same |ref| field;
+this means there will be more than |p+1| entries in |v->arcs|,
+and the total number of arcs |g->m| will exceed |(p+1)n|.
+Self-inverse generating permutations arise only when |p=2| or
+when $p$ is expressible as a sum of three odd squares (hence
+$p\bmod8=3$); and such permutations will have fixed points only when
+|type<3|. Therefore this anomaly does not arise often. But it does
+occur, for example, in the smallest graph generated by |raman|, namely
+when |p=2|, |q=3|, and |type=1|, when there are 4~vertices and 14 (not~12)
+arcs.
+
+@d ref a.i /* the |ref| field of an arc refers to its permutation number */
+
+@<Append the edges@>=
+for (k=p;k>=0;k--) {@+int kk;
+ if ((kk=gen[k].bar)<=k) /* we assume that |kk=k| or |kk=k-1| */
+ for (v=new_graph->vertices;v<new_graph->vertices+n;v++) {
+ register Vertex* u;
+ @<Compute the image, |u|, of |v|
+ under the permutation defined by |gen[k]|@>;
+ if (u==v) {
+ if (!reduce) {
+ gb_new_edge(v,v,1);
+ v->arcs->ref=kk;@+(v->arcs+1)->ref=k;
+ /* see the remarks above regarding the case |kk=k| */
+ }
+ } else {@+register Arc* ap;
+ if (u->arcs && u->arcs->ref==kk)
+ continue; /* |kk=k| and we've already done this two-cycle */
+ else if (reduce)
+ for (ap=v->arcs;ap;ap=ap->next)
+ if (ap->tip==u) goto done;
+ /* there's already an edge between |u| and |v| */
+ gb_new_edge(v,u,1);
+ v->arcs->ref=k;@+u->arcs->ref=kk;
+ if ((ap=v->arcs->next)!=NULL && ap->ref==kk) {
+ v->arcs->next=ap->next;@+ap->next=v->arcs;@+v->arcs=ap;
+ } /* now the |v->arcs| list has |ref| fields in order again */
+ done:;
+ }
+ }
+}
+
+@ For graphs of types 3 and 4, our job is to compute a $2\times2$ matrix
+product, reduce it modulo~|q|, and find the appropriate
+equivalence class~|u|.
+
+@<Compute the image, |u|, of |v| under the permutation defined by |gen[k]|@>=
+if (type<3) @<Compute the image, |u|, of |v| under the linear fractional
+ transformation defined by |gen[k]|@>@;
+else {@+long a0=gen[k].a0,a1=gen[k].a1,a2=gen[k].a2,a3=gen[k].a3;
+ a=v->x.i;@+b=v->y.i;
+ if (v->z.i==q) c=0,d=1;
+ else c=1,d=v->z.i;
+ @<Compute the matrix product |(aa,bb;cc,dd)=(a,b;c,d)*(a0,a1;a2,a3)|@>;
+ a=(cc? q_inv[cc]: q_inv[dd]); /* now |a| is a normalization factor */
+ d=(a*dd)%q;@+c=(a*cc)%q;@+b=(a*bb)%q;@+a=(a*aa)%q;
+ @<Set |u| to the vertex whose label is |(a,b;c,d)|@>;
+}
+
+@ @<Compute the matrix product...@>=
+aa=(a*a0+b*a2)%q;
+bb=(a*a1+b*a3)%q;
+cc=(c*a0+d*a2)%q;
+dd=(c*a1+d*a3)%q;
+
+@ @<Set |u|...@>=
+if (c==0) d=q,aa=a;
+else {
+ aa=(a*d-b)%q;
+ if (aa<0) aa+=q;
+ b=a;
+} /* now |aa| is the determinant of the matrix */
+u=new_graph->vertices+((d*q+b)*n_factor+(type==3? q_sqrt[aa]: aa)-1);
+
+@* Linear fractional transformations. Given a nonsingular $2\times2$ matrix
+$\bigl({a\,b\atop c\,d}\bigr)$, the linear fractional transformation
+$z\mapsto(az+b)/(cz+d)$ is defined modulo~$q$ by the
+following subroutine. We assume that the matrix $\bigl({a\,b\atop c\,d}\bigr)$
+appears in row |k| of the |gen| table.
+
+@<Private...@>=
+static long lin_frac(a,k)
+ long a; /* the number being transformed; $q$ represents $\infty$ */
+ unsigned k; /* index into |gen| table */
+{@+register long q=q_inv[0]; /* the modulus */
+ long a00=gen[k].a0, a01=gen[k].a1, a10=gen[k].a2,
+ a11=gen[k].a3; /* the coefficients */
+ register num, den; /* numerator and denominator */
+ if (a==q) num=a00, den=a10;
+ else num=(a00*a+a01)%q, den=(a10*a+a11)%q;
+ if (den==0) return q;
+ else return (num*q_inv[den])%q;
+}
+
+@ We are computing the same values of |lin_frac| over and over again in type~2
+graphs, but the author was too lazy to optimize this.
+
+@<Compute the image, |u|, of |v| under the linear fractional
+ transformation defined by |gen[k]|@>=
+if (type==1) u=new_graph->vertices+lin_frac(v->x.i,k);
+else {
+ a=lin_frac(v->x.i,k);@+aa=lin_frac(v->y.i,k);
+ u=new_graph->vertices+(a<aa? (a*(2*q-1-a))/2+aa-1:
+ (aa*(2*q-1-aa))/2+a-1);
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_rand.w b/support/graphbase/gb_rand.w
new file mode 100644
index 0000000000..1d153795be
--- /dev/null
+++ b/support/graphbase/gb_rand.w
@@ -0,0 +1,575 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace RAND}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GRAPH}
+@*Random graphs. This GraphBase module provides two external
+subroutines called |random_graph| and |random_bigraph|, which generate
+graphs in which the arcs or edges have been selected ``at random.'' A
+third subroutine, |random_lengths|, randomizes the lengths of the arcs
+of a given graph. The performance of algorithms on such graphs can
+fruitfully be compared to their performance on the nonrandom graphs
+generated by other GraphBase routines.
+
+Before reading this code, the reader should be familiar with the
+basic data structures and conventions described in |gb_graph|. The
+routines in |gb_graph| are loaded together with all GraphBase applications,
+and the programs below are typical illustrations of how to use them.
+
+@f Graph int /* module |gb_graph| defines several types including these */
+@f Vertex int
+@f Arc int
+@f Area int
+
+@(gb_rand.h@>=
+extern Graph *random_graph();
+ /* users of |gb_rand| should include this header info */
+extern Graph *random_bigraph();
+extern int random_lengths();
+
+@ Here is an overview of the file \.{gb\_rand.c}, the \Cee\ code from which
+users can obtain the routines |random_graph| and |random_bigraph|:
+
+@p
+#include "gb_graph.h" /* this header file teaches \Cee\ about GraphBase */
+#include "gb_flip.h" /* we will use the |gb_flip| routines for random numbers */
+@<Private declarations@>@;
+@<Internal functions@>@;
+@<External functions@>
+
+@ The procedure |random_graph(n,m,multi,self,directed,dist_from,dist_to,min_len,max_len,seed)|
+is designed to produce a pseudo-random graph with |n| vertices and |m| arcs or
+edges, using pseudo-random numbers that depend on |seed| in a system-independent
+fashion. The remaining parameters specify a variety of options:
+$$\vcenter{\halign{#\hfil\cr
+|multi!=0| permits duplicate arcs;\cr
+|self!=0| permits self-loops (arcs from a vertex to itself);\cr
+|directed!=0| makes the graph directed; otherwise each arc becomes an undirected
+ edge;\cr
+|dist_from| and |dist_to| specify probability distributions on the arcs;\cr
+|min_len| and |max_len| bound the arc lengths, which will be uniformly
+distributed between these limits.\cr
+}}$$
+If |dist_from| or |dist_to| are |NULL|, the probability distribution is
+uniform over vertices; otherwise the \\{dist} parameter points to an array of
+|n| nonnegative integers that sum to $2^{30}$, specifying the respective
+probabilities (times $2^{30}$) that each given vertex will appear as the
+source or destination of the random arcs.
+
+A special option |multi=-1| is provided. This acts exactly like |multi=1|, except
+that arcs are not physically duplicated in computer memory---they are replaced
+by a single arc whose length is the minimum of all arcs having a common source
+and destination.
+
+The vertices are named simply |"0"|, |"1"|, |"2"|, and so on.
+
+@ Examples: |random_graph(1000,5000,0,0,0,NULL,NULL,1,1,0)| creates a random
+undirected graph with 1000 vertices and 5000 edges (hence 10000 arcs) of
+length~1, having
+no duplicate edges or self-loops. There are ${1000\choose2}=499500$ possible
+undirected edges on 1000 vertices, hence there are exactly $499500\choose5000$
+possible graphs meeting these specifications; every such graph would be
+equally likely, if |random_graph| had access to an ideal source of
+random numbers. The GraphBase programs are designed to be
+system-independent, so that identical graphs will be obtained by
+everybody who asks for |random_graph(1000,5000,0,0,0,NULL,NULL,1,1,0)|.
+Equivalent experiments on algorithms for graph manipulation can therefore
+be performed by researchers in different parts of the world.
+
+The subroutine call |random_graph(1000,5000,0,0,0,NULL,NULL,1,1,s)|
+will produce different graphs when the random seed |s| varies;
+however, the graph for any particular value of~|s| will be the same on
+all computers. The seed value can be any integer in the range $0\le s<2^{31}$.
+
+To get a random directed graph, allowing self-loops and repeated arcs,
+and with a uniform distribution on vertices, ask for
+$$\hbox{|random_graph(n,m,1,1,1,NULL,NULL,1,1,s)|}.$$
+Each of the $m$ arcs of that digraph has probability $1/n^2$ of being from
+$u$ to $v$, for all $u$ and~$v$. If self-loops are disallowed (by
+changing `|1,1,1|' to `|1,0,1|'), each arc has probability
+$1/(n^2-n)$ of being from $u$ to $v$, for all $u\ne v$.
+
+To get a random directed graph in which vertex $k$ is twice as likely
+as vertex $k+1$ to be the source of an arc but only half as likely to
+be the destination of an arc, for all~$k$, try
+$$\hbox{|random_graph(25,m,1,1,1,d0,d1,0,255,s)|}$$
+where the arrays |d0| and |d1| have the static declarations
+$$\vbox{
+\hbox{|long d0[31]={0x20000000,0x10000000,@t\dots@>,4,2,1,1};|}
+\hbox{|long d1[31]={1,1,2,4,@t\dots@>,0x10000000,0x20000000};|}}$$
+then about 1/4 of the arcs will run from 0 to 30, while arcs
+from 30 to 0 will be extremely rare (occurring with probability $2^{-60}$).
+Incidentally, the arc lengths in this example will be random bytes,
+uniformly distributed between 0 and 255, because the |min_len=0| and
+|max_len=255|.
+
+If we forbid repeated arcs in this example, by setting |multi=0|, the
+effect is to discard all arcs having the same source and destination
+as a previous arc, regardless of length. In such a case |m| had better not
+be too large, because the algorithm will keep going until it has found
+|m| distinct arcs, and many arcs are quite rare indeed; they will
+probably not be found until hundreds of centuries have elapsed.
+
+A random bipartite graph can also be obtained as a special case of
+|random_graph|; this case is explained below.
+
+Semantics:
+If |multi=directed=0| and |self!=0|, we have an undirected graph without duplicate
+edges but with self-loops permitted. A self-loop then consists of
+two identical self-arcs, in spite of the fact that |multi=0|.
+
+@ If the |random_graph| routine encounters a problem, it returns
+|NULL|, after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |random_graph| returns a pointer to the newly created graph
+and leaves |panic_code| unchanged. The |gb_alloc_trouble| will be
+cleared to zero after |random_graph| has acted.
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+
+@<External f...@>=
+Graph *random_graph(n,m,multi,self,directed,dist_from,dist_to,min_len,max_len,seed)
+ unsigned n; /* number of vertices desired */
+ unsigned long m; /* number of arcs or edges desired */
+ int multi; /* allow duplicate arcs? */
+ int self; /* allow self loops? */
+ int directed; /* directed graph? */
+ long *dist_from; /* distribution of arc sources */
+ long *dist_to; /* distribution of of arc destinations */
+ long min_len,max_len; /* bounds on random lengths */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+@#
+ if (n==0) panic(bad_specs); /* we gotta have a vertex */
+ if (min_len>max_len) panic(very_bad_specs); /* what are you trying to do? */
+ if (((unsigned long)(max_len))-((unsigned long)(min_len))>=
+ ((unsigned long)0x80000000)) panic(bad_specs+1); /* too much range */
+ @<Check the distribution parameters@>;
+ gb_init_rand(seed);
+ @<Create a graph with |n| vertices and no arcs@>;
+ @<Build tables for nonuniform distributions, if needed@>;
+ for (mm=m; mm; mm--)
+ @<Add a random arc or a random edge@>;
+trouble: if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ gb_free(new_graph->aux_data);
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |random_graph| */
+long mm; /* the number of arcs or edges we still need to generate */
+register int k; /* vertex being processed */
+
+@ @d dist_code(x) (x? "dist": "0")
+
+@<Create a graph with |n| vertices and no arcs@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+for (k=0; k<n; k++) {
+ sprintf(name_buffer,"%d",k);
+ (new_graph->vertices+k)->name=gb_save_string(name_buffer);
+}
+sprintf(new_graph->id,"random_graph(%u,%lu,%d,%d,%d,%s,%s,%ld,%ld,%ld)",@|
+ n,m,multi>0?1:multi<0?-1:0,self?1:0,directed?1:0,@|
+ dist_code(dist_from),dist_code(dist_to),min_len,max_len,seed);
+
+@ @<Private d...@>=
+static char name_buffer[]="9999999999";
+
+@ @d rand_len (min_len==max_len?min_len:min_len+gb_unif_rand(max_len-min_len))
+
+@<Add a random arc or a random edge@>=
+{@+register Vertex *u,*v;
+repeat:
+ if (dist_from)
+ @<Generate a random vertex |u| according to |dist_from|@>@;
+ else u=new_graph->vertices+gb_unif_rand(n);
+ if (dist_to)
+ @<Generate a random vertex |v| according to |dist_to|@>@;
+ else v=new_graph->vertices+gb_unif_rand(n);
+ if (u==v && !self) goto repeat;
+ if (multi<=0)
+ @<Search for duplicate arcs or edges; |goto repeat| or |done| if found@>;
+ if (directed) gb_new_arc(u,v,rand_len);
+ else gb_new_edge(u,v,rand_len);
+done:;
+}
+
+@ When we decrease the length of an existing edge, we use the fact that
+its two arcs are adjacent in memory. If |u==v| in this case, we encounter
+the first of two mated arcs before seeing the second; hence the mate of
+the arc we find is in location |a+1| when |u<=v|, and in location
+|a-1| when |u>v|.
+
+We must exit to location |trouble| if memory has been exhausted;
+otherwise there is a danger of an infinite loop, with |dummy_arc->next
+=dummy_arc|.
+
+@<Search for duplicate arcs or edges; |goto repeat| or |done| if found@>=
+if (gb_alloc_trouble) goto trouble;
+else {@+register Arc *a;
+ long len; /* length of new arc or edge being combined with previous */
+ for (a=u->arcs; a; a=a->next)
+ if (a->tip==v)
+ if (multi==0) goto repeat; /* reject a duplicate arc */
+ else { /* |multi<0| */
+ len=rand_len;
+ if (len<a->len) {
+ a->len=len;
+ if (!directed) {
+ if (u<=v) (a+1)->len=len;
+ else (a-1)->len=len;
+ }
+ }
+ goto done;
+ }
+}
+
+@* Nonuniform random number generation. The |random_graph| procedure is
+complete except for the parts that handle general distributions |dist_from|
+and |dist_to|. First, we had better check the input to make sure that
+it is well formed; otherwise disaster can ensue later. This part
+of the program is easy:
+
+ @<Check the distribution parameters@>=
+{@+register long acc; /* sum of probabilities */
+ register long *p; /* pointer to current probability of interest */
+ if (dist_from) {
+ for (acc=0,@,p=dist_from; p<dist_from+n; p++) {
+ if (*p<0) panic(invalid_operand);
+ /* |dist_from| contains a negative entry */
+ if (*p>0x40000000-acc) panic(invalid_operand+1);
+ /* probability too high */
+ acc+=*p;
+ }
+ if (acc!=0x40000000)
+ panic(invalid_operand+2); /* |dist_from| table doesn't sum to $2^{30}$ */
+ }
+ if (dist_to) {
+ for (acc=0,@,p=dist_to; p<dist_to+n; p++) {
+ if (*p<0) panic(invalid_operand+5);
+ /* |dist_to| contains a negative entry */
+ if (*p>0x40000000-acc) panic(invalid_operand+6);
+ /* probability too high */
+ acc+=*p;
+ }
+ if (acc!=0x40000000)
+ panic(invalid_operand+7); /* |dist_to| table doesn't sum to $2^{30}$ */
+ }
+}
+
+@ We generate nonuniform distributions by using Alistair J. Walker's alias
+method (see, for example, {\sl Seminumerical Algorithms}, second edition,
+exercise 3.4.1--7). This involves setting up ``magic'' tables
+of length |nn|, where |nn| is the smallest power of~2 that is |>=n|.
+
+@f magic_entry int
+
+@<Local v...@>=
+long nn=1; /* this will be increased to $2^{\lceil\mskip1mu\lg n\rceil}$ */
+int kk=31; /* this will be decreased to $31-\lceil\mskip1mu\lg n\rceil$ */
+magic_entry *dist_from_table, *dist_to_table; /* alias tables */
+
+@ @<Build...@>=
+{
+ if (dist_from) {
+ while (nn<n) nn+=nn, kk--;
+ dist_from_table=walker(n,nn,dist_from,new_graph);
+ }
+ if (dist_to) {
+ while (nn<n) nn+=nn, kk--;
+ dist_to_table=walker(n,nn,dist_to,new_graph);
+ }
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+}
+
+@ @<Private...@>=
+typedef struct {
+ long prob; /* a probability, multiplied by $2^{31}$ and translated */
+ long inx; /* index that might be selected */
+} magic_entry;
+
+@ Once the magic tables have been set up, we will be able to generate
+nonuniform vertices by using the following code:
+
+@<Generate a random vertex |u|...@>=
+{@+register magic_entry *magic;
+ register long uu=gb_next_rand(); /* uniform random number */
+ k=uu>>kk;
+ magic=dist_from_table+k;
+ if (uu<=magic->prob) u=new_graph->vertices+k;
+ else u=new_graph->vertices+magic->inx;
+}
+
+@ @<Generate a random vertex |v|...@>=
+{@+register magic_entry *magic;
+ register long uu=gb_next_rand(); /* uniform random number */
+ k=uu>>kk;
+ magic=dist_to_table+k;
+ if (uu<=magic->prob) v=new_graph->vertices+k;
+ else v=new_graph->vertices+magic->inx;
+}
+
+@ So all we have to do is set up those magic tables. If |uu| is a uniform
+random integer between 0 and $2^{31}-1$, the index |k=uu>>kk| will be a
+uniform random integer between 0
+and |nn-1|, because of the relation between |nn| and |kk|. Once |k| is
+computed in the code above, we will select vertex~|k| with probability
+|(p+1-(k<<kk))|/$2^{31}$, where |p=magic->prob| and |magic| is the $k$th
+element of the magic table; otherwise we will select
+vertex |magic->inx|. The trick is to set things up so that each vertex
+is selected with the proper overall probability.
+
+Let's imagine that the given distribution vector has length |nn|,
+instead of~|n|, by extending it if necessary with zeroes. Then the
+average entry among these |nn| integers is exactly $t=2^{30}/|nn|$.
+If some entry, say entry~|i|, exceeds |t|, there must be another entry
+that's less than |t|, say entry~|j|. We can set the $j$th entry
+of the magic table so that its |prob| field selects vertex~$j$ with the
+correct probability, and so that its |vert| field equals~|i|. Then
+we are selecting vertex~|i| with a certain residual probability, so we
+subtract that residual from |i|'s present probability, and repeat the
+process with vertex~|j| eliminated. The average of the remaining entries
+is still~|t|, so we can repeat this procedure until all remaining entries
+are exactly equal to~|t|. The rest is easy.
+
+During the calculation, we will maintain two linked lists of
+|(prob,vert)| pairs; the |hi| list will contain entries with |prob>t|,
+and the |lo| list will contain the rest. We'll call these list
+elements `nodes'; and we'll use the field names |key| and~|j| instead
+of |prob| and |vert| during this part of the computation.
+
+@<Private...@>=
+typedef struct node_struct {
+ long key; /* a numeric quantity */
+ struct node_struct *link; /* the next node on the list */
+ int j; /* a vertex number to be selected with probability $|key|/2^{30}$ */
+} node;
+static Area temp_nodes; /* nodes will be allocated in this area */
+static node *base_node; /* beginning of a block of nodes */
+
+@ @<Internal...@>=
+static magic_entry *walker(n,nn,dist,g)
+ int n; /* length of |dist| vector */
+ long nn; /* $2^{\lceil\mskip1mu\lg n\rceil}$ */
+ register long *dist; /* start of distribution table, which sums to $2^{30}$ */
+ Graph *g; /* tables will be allocated for this graph's vertices */
+{@+magic_entry *table; /* this will be the magic table we compute */
+ long t; /* average |key| value */
+ node *hi=NULL, *lo=NULL; /* nodes not yet included in magic table */
+ register node *p, *q; /* pointer variables for list manipulation */
+ register int *r; /* pointer variable to traverse the |dist| table */
+ base_node=gb_alloc_type(nn,@[node@],temp_nodes);
+ table=gb_alloc_type(nn,@[magic_entry@],g->aux_data);
+ if (!gb_alloc_trouble) {
+ @<Initialize the |hi| and |lo| lists@>;
+ while (hi) @<Remove a |lo| element and match it with a |hi| element;
+ deduct the residual probability from that |hi|~element@>;
+ while (lo) @<Remove a |lo| element of |key| value |t|@>;
+ }
+ gb_free(temp_nodes);
+ return table; /* if |gb_alloc_trouble| is nonzero, the table is empty */
+}
+
+@ @<Initialize the |hi| and |lo| lists@>=
+t=0x40000000/nn; /* this division is exact */
+p=base_node;
+while (nn>n) {
+ p->key=0;
+ p->link=lo;
+ p->j=--nn;
+ lo=p++;
+}
+for (dist=dist+n-1; n>0; dist--,p++) {
+ p->key=*dist;
+ p->j=--n;
+ if (*dist>t)
+ p->link=hi,@, hi=p;
+ else p->link=lo,@, lo=p;
+}
+
+@ When we change the scale factor from $2^{30}$ to $2^{31}$, we need to
+be careful lest integer overflow occur. The introduction of register |x| into
+this code removes the risk.
+
+@<Remove a |lo| element and match it with a |hi| element...@>=
+{register magic_entry *r; register long x;
+ p=hi,@, hi=p->link;
+ q=lo,@, lo=q->link;
+ r=table+q->j;
+ x=t*q->j+q->key-1;
+ r->prob=x+x+1;
+ r->inx=p->j;
+ /* we have just given |q->key| units of probability to vertex |q->j|,
+ and |t-q->key| units to vertex |p->j| */
+ if ((p->key-=t-q->key)>t)
+ p->link=hi,@, hi=p;
+ else p->link=lo,@, lo=p;
+}
+
+@ When all remaining entries have the average probability, the
+|vert| component need not be set, because it will never be used.
+
+@<Remove a |lo| element of |key| value |t|@>=
+{register magic_entry *r; register long x;
+ q=lo, lo=q->link;
+ r=table+q->j;
+ x=t*q->j+t-1;
+ r->prob=x+x+1;
+ /* that's |t| units of probability for vertex |q->j| */
+}
+
+@*Random bipartite graphs. The procedure call
+$$\hbox{|random_bigraph(n1,n2,m,multi,dist1,dist2,min_len,max_len,seed)|}$$
+is designed to produce a pseudo-random bipartite graph
+with |n1| vertices in one part and |n2| in the other, having |m| edges.
+The remaining parameters |multi|, |dist1|, |dist2|, |min_len|, |max_len|,
+and |seed| have the same meaning as the analogous parameters of |random_graph|.
+
+In fact, |random_bigraph| does its work by reducing its parameters
+to a special case of |random_graph|. Almost all that needs to be done is
+to pad |dist1| with |n2| trailing zeroes and |dist2| with |n1| leading
+zeroes. The only slightly tricky part occurs when |dist1| and/or |dist2| are
+null, since non-null distribution vectors summing exactly to $2^{30}$ must then
+be fabricated.
+
+@<External f...@>=
+Graph *random_bigraph(n1,n2,m,multi,dist1,dist2,min_len,max_len,seed)
+ unsigned n1,n2; /* number of vertices desired in each part */
+ unsigned long m; /* number of edges desired */
+ int multi; /* allow duplicate edges? */
+ long *dist1, *dist2; /* distribution of edge endpoints */
+ long min_len,max_len; /* bounds on random lengths */
+ long seed; /* random number seed */
+{@+int n=n1+n2; /* total number of vertices */
+ Area new_dists;
+ long *dist_from, *dist_to;
+ Graph *new_graph;
+ init_area(new_dists);
+ if (n1==0 || n2==0) panic(bad_specs); /* illegal options */
+ if (min_len>max_len) panic(very_bad_specs); /* what are you trying to do? */
+ if (((unsigned long)(max_len))-((unsigned long)(min_len))>=
+ ((unsigned long)0x80000000)) panic(bad_specs+1); /* too much range */
+ dist_from=gb_alloc_type(n,@[long@],new_dists);
+ dist_to=gb_alloc_type(n,@[long@],new_dists);
+ if (gb_alloc_trouble) {
+ gb_free(new_dists);
+ panic(no_room+2); /* no room for auxiliary distribution tables */
+ }
+ @<Compute the entries of |dist_from| and |dist_to|@>;
+ new_graph=random_graph(n,m,multi,0,0,dist_from,dist_to,min_len,max_len,seed);
+ sprintf(new_graph->id,"random_bigraph(%u,%u,%lu,%d,%s,%s,%ld,%ld,%ld)",@|
+ n1,n2,m,multi>0?1:multi<0?-1:0,dist_code(dist1),dist_code(dist2),@|
+ min_len,max_len,seed);
+ mark_bipartite(new_graph,n1);
+ gb_free(new_dists);
+ return new_graph;
+}
+
+@ The relevant identity we need here is the replicative law for the
+floor function:
+$$\left\lfloor x\over n\right\rfloor+\left\lfloor x+1\over n\right\rfloor
++ \cdots + \left\lfloor x+n-1\over n\right\rfloor = \lfloor x\rfloor\,.$$
+
+@<Compute the entries...@>=
+{@+register long *p, *q; /* traversers of the dists */
+ register int k; /* vertex count */
+ p=dist1; q=dist_from;
+ if (p)
+ while (p<dist1+n1) *q++=*p++;
+ else for (k=0; k<n1; k++) *q++=(0x40000000+k)/n1;
+ p=dist2; q=dist_to+n1;
+ if (p)
+ while (p<dist2+n2) *q++=*p++;
+ else for (k=0; k<n2; k++) *q++=(0x40000000+k)/n2;
+}
+
+@* Random lengths. The subroutine call
+$$\hbox{|random_lengths(g,directed,min_len,max_len,dist,seed)|}$$
+takes an existing graph and assigns new lengths to
+each of its arcs. The lengths will be uniformly distributed between
+|min_len| and |max_len| inclusive, if |dist=NULL|; otherwise |dist|
+should be a probability distribution vector of length |max_len-min_len+1|,
+like those in |random_graph|.
+
+If |directed=0|, pairs of arcs $u\to v$ and $v\to u$ will be regarded as
+a single edge, both arcs receiving the same length.
+
+The procedure returns a nonzero value if something goes wrong; in that
+case, graph |g| will not have been changed.
+
+Alias tables for generating nonuniform random lengths will survive
+in |g->aux_data|.
+
+@<External f...@>=
+int random_lengths(g,directed,min_len,max_len,dist,seed)
+ Graph *g; /* graph whose lengths will be randomized */
+ int directed; /* is it directed? */
+ long min_len,max_len; /* bounds on random lengths */
+ long *dist; /* distribution of lengths */
+ long seed; /* random number seed */
+{@+register Vertex *u,*v; /* current vertices of interest */
+ register Arc *a; /* current arc of interest */
+ long nn=1, kk=31; /* variables for nonuniform generation */
+ magic_entry *dist_table; /* alias table for nonuniform generation */
+ if (g==NULL) panic(missing_operand); /* where is |g|? */
+ gb_init_rand(seed);
+ if (min_len>max_len) return 102; /* what are you trying to do? */
+ if (((unsigned long)(max_len))-((unsigned long)(min_len))>=
+ ((unsigned long)0x80000000)) return 103; /* too much range */
+ @<Check |dist| for validity, and set up the |dist_table|@>;
+ sprintf(buffer,",%d,%ld,%ld,%s,%ld)",directed?1:0,@|
+ min_len,max_len,dist_code(dist),seed);
+ make_compound_id(g,"random_lengths(",g,buffer);
+ @<Run through all arcs and assign new lengths@>;
+ return 0;
+}
+
+@ @<Private dec...@>=
+static char buffer[]="1,-1000000001,-1000000000,dist,1000000000)";
+
+@ @<Check |dist| for validity...@>=
+if (dist) {@+register long acc; /* sum of probabilities */
+ register long *p; /* pointer to current probability of interest */
+ register n=max_len-min_len+1;
+ for (acc=0,p=dist; p<dist+n; p++) {
+ if (*p<0) return -1; /* negative probability */
+ if (*p>0x40000000-acc) return 1; /* probability too high */
+ acc+=*p;
+ }
+ if (acc!=0x40000000) return 2; /* probabilities don't sum to 1 */
+ while (nn<n) nn+=nn,kk--;
+ dist_table=walker(n,nn,dist,g);
+ if (gb_alloc_trouble) {
+ gb_alloc_trouble=0;
+ return 66; /* not enough room to generate the magic tables */
+ }
+}
+
+@ @<Run through all arcs and assign new lengths@>=
+for (u=g->vertices;u<g->vertices+g->n;u++)
+ for (a=u->arcs;a;a=a->next) {
+ v=a->tip;
+ if (directed==0 && u>v) a->len=(a-1)->len;
+ else {@+register long len; /* a random length */
+ if (dist==0) len=rand_len;
+ else {@+long uu=gb_next_rand();
+ long k=uu>>kk;
+ magic_entry *magic=dist_table+k;
+ if (uu<=magic->prob) len=min_len+k;
+ else len=min_len+magic->inx;
+ }
+ a->len=len;
+ if (directed==0 && u==v && a->next==a+1) (++a)->len=len;
+ }
+ }
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_roget.w b/support/graphbase/gb_roget.w
new file mode 100644
index 0000000000..fba3536c19
--- /dev/null
+++ b/support/graphbase/gb_roget.w
@@ -0,0 +1,224 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace ROGET}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the |roget| subroutine,
+which creates a family of graphs based on Roget's Thesaurus. An example
+of the use of this procedure can be found in the demo program
+|roget_components|.
+
+@(gb_roget.h@>=
+extern Graph *roget();
+
+@ The subroutine call `|roget(n,min_distance,prob,seed)|'
+constructs a graph based on the information in \.{roget.dat}.
+Each vertex of the graph corresponds to one of the 1022 categories in
+the 1882 edition of Peter Mark Roget's {\sl Thesaurus of English Words
+and Phrases}. An arc goes from one category to another if Roget gave a
+reference to the latter among the words and phrases of the former,
+or if the two categories were directly related to each other by their
+positions in Roget's book. For example, the vertex for category 312
+(`ascent') has arcs to the vertices for categories 224 (`obliquity'),
+313 (`descent'), and 316 (`leap'), because Roget gave explicit
+cross-references from 312 to 224 and~316, and because category 312
+was implicitly paired with 313 in his scheme.
+
+The constructed graph will have $\min(n,1022)$ vertices; however, the
+default value |n=1022| is substituted when |n=0|. If |n| is less
+than 1022, the |n| categories will be selected at random,
+and all arcs to unselected categories will be omitted.
+Arcs will also be omitted if they correspond to categories whose
+nuumbers differ by less than |min_distance|. For example, if
+|min_distance>1|, the arc between categories 312 and~313 will not
+be included. (Roget sometimes formed clusters of three interrelated
+categories; to avoid cross-references among these, you can set
+|min_distance=3|.)
+
+If |prob>0|, arcs that would ordinarily be included in the graph are
+rejected with probability |prob/65536|. This provides a way
+to obtain sparser graphs.
+
+The vertices will appear in random order. However, all ``randomness''
+in GraphBase graphs is reproducible; it depends only on the value of
+a given |seed|, which can be any nonnegative integer less than~$2^{31}$.
+For example, everyone who asks for |roget(1000,3,32768,50)| will
+obtain exactly the same graph, regardless of their computer system.
+
+Changing the value of |prob| will affect only the arcs of the
+generated graph; it will change neither the choice of vertices
+nor the vertex order.
+
+@d MAX_N 1022 /* the number of categories in Roget's book */
+
+@ If the |roget| routine encounters a problem, it returns |NULL|
+(\.{NULL}), after putting a code number into the external variable
+|panic_code|. This code number identifies the type of failure.
+Otherwise |roget| returns a pointer to the newly created graph, which
+will be represented with the data structures explained in |gb_graph|.
+(The external variable |@!panic_code| is itself defined in |gb_graph|.)
+
+@d panic(c) @+{@+panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+
+@ The \Cee\ file \.{gb\_roget.c} has the following general shape:
+
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_flip.h"
+ /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h" /* and we will use the |gb_graph| data structures */
+@#
+@<Private variables@>@;
+@#
+Graph *roget(n,min_distance,prob,seed)
+ unsigned n; /* number of vertices desired */
+ unsigned min_distance; /* smallest inter-category distance allowed
+ in an arc */
+ unsigned long prob; /* 65536 times the probability of rejecting an arc */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+ gb_init_rand(seed);
+ if (n==0 || n>MAX_N) n=MAX_N;
+ @<Set up a graph with |n| vertices@>;
+ @<Determine the |n| categories to use in the graph@>;
+ @<Input \.{roget.dat} and build the graph@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |roget| */
+
+@* Vertices.
+
+@<Set up a graph with |n| vertices@>=
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+sprintf(new_graph->id,"roget(%u,%u,%lu,%ld)",n,min_distance,prob,seed);
+strcpy(new_graph->format,"IZZZZZZZZZZZZZ");
+
+@ The first nontrivial thing we need to do is find a random selection and
+permutation of |n| vertices. We will compute a |mapping| table such that
+|mapping[k]| will be non-|NULL| for exactly |n| randomly selected
+category numbers~|k|, i.e., values of~|k| in the range |1<=k<=MAX_N|.
+Moreover, these non-|NULL| values will be a random permutation of the
+vertices of the graph.
+
+@<Priv...@>=
+Vertex *mapping[MAX_N+1]; /* the vertex corresponding to a given category */
+int cats[MAX_N]; /* table of category numbers that have not yet been used */
+
+@ In the loop on |v| below, |k| is the number of categories whose |mapping|
+value is still |NULL|. The first |k| entries of |cats| will contain
+those category numbers in some order.
+
+@<Determine the |n| categories to use in the graph@>=
+for (k=0; k<MAX_N; k++)
+ cats[k]=k+1,@,mapping[k+1]=NULL;
+for (v=new_graph->vertices+n-1; v>=new_graph->vertices; v--) {
+ j=gb_unif_rand(k);
+ mapping[cats[j]]=v; cats[j]=cats[--k];
+}
+
+@ @<Local...@>=
+register int j,k; /* all-purpose indices */
+register Vertex *v; /* current vertex */
+
+@* Arcs. The data in \.{roget.dat} appears in 1022 lines, one for each
+category. For example, the line
+$$\hbox{\tt 312ascent:224 313 316}$$
+specifies the arcs from category 312 as explained above. First comes the
+category number, then the category name, then a colon, then zero or more
+numbers specifying arcs to other categories, separated by spaces.
+
+Some categories have too many arcs to fit on a single line; the data
+for these categories can be found on two lines, the first line ending
+with a backslash and the second line beginning with a space.
+
+@<Input \.{roget.dat} and build the graph@>=
+if (gb_open("roget.dat")!=0)
+ panic(early_data_fault);
+ /* couldn't open |"roget.dat"| using GraphBase conventions */
+for (k=1; !gb_eof(); k++)
+ @<Read the data for category |k|, and put it in the graph if it
+ has been selected@>;
+if (gb_close()!=0)
+ panic(late_data_fault);
+ /* something's wrong with |"roget.dat"|; see |io_errors| */
+if (k!=MAX_N+1) panic(impossible);
+ /* we don't have the right value of |MAX_N| */
+
+@ We want to check that the data isn't garbled, except that we don't
+bother to look at unselected categories.
+
+The original category number is stored in vertex utility field |cat_no|,
+in case anybody wants to see it.
+
+@d cat_no u.i /* utility field |u| of each vertex holds the category number */
+
+@<Read the data for category |k|, and put it in the graph if it
+ has been selected@>=
+{
+ if (mapping[k]) { /* yes, this category has been selected */
+ if (gb_number(10)!=k) panic(syntax_error); /* out of synch */
+ (void)gb_string(str_buf,':');
+ if (gb_char()!=':') panic(syntax_error+1); /* no colon found */
+ v=mapping[k];
+ v->name=gb_save_string(str_buf);
+ v->cat_no=k;
+ @<Add arcs from |v| for every category that's both listed on the line
+ and selected@>;
+ } else @<Skip past the data for one category@>;
+}
+
+@ @(gb_roget.h@>=
+#define cat_no @t\quad@> u.i
+ /* definition of |cat_no| is repeated in the header file */
+
+@ @d iabs(x) ((x)<0? -(x): (x))
+
+@<Add arcs from |v| for every...@>=
+j=gb_number(10);
+if (j==0) goto done; /* some categories lead to no arcs at all */
+while (1) {@+Arc *a;
+ if (j>MAX_N) panic(syntax_error+2); /* category code out of range */
+ if (mapping[j] && iabs(j-k)>=min_distance &&
+ (prob==0 || ((gb_next_rand()>>15)>=prob)))
+ gb_new_arc(v,mapping[j],1);
+ switch (gb_char()) {
+ case '\\': gb_newline();
+ if (gb_char()!=' ')
+ panic(syntax_error+3); /* space should begin a continuation line */
+ /* fall through to the space case */
+ case ' ': j=gb_number(10);@+break;
+ case '\n': goto done;
+ default: panic(syntax_error+4);
+ /* illegal character following category number */
+ }
+}
+done: gb_newline();
+
+@ We want to call |gb_newline()| twice if the current line ends with a
+backslash; otherwise we want to call it just once. There's an obvious
+way to do that, and there's also a faster and trickier way. The
+author apologizes here for succumbing to some old-fashioned impulses.
+(Recall that |gb_string| returns the location just following the
+|'\0'| it places at the end of a scanned string.)
+
+@<Skip past the data for one category@>=
+{
+ if (*(gb_string(str_buf,'\n')-2)=='\\')
+ gb_newline(); /* the first line ended with backslash */
+ gb_newline();
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_save.w b/support/graphbase/gb_save.w
new file mode 100644
index 0000000000..06e675a1f4
--- /dev/null
+++ b/support/graphbase/gb_save.w
@@ -0,0 +1,872 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace SAVE}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module contains the code for
+two utility routines, |save_graph| and |restore_graph|, which
+convert graphs back and forth between the internal representation
+described in |gb_graph| and a symbolic file format described below.
+Researchers can use these routines to transmit graphs between
+computers in a machine-independent way, or to use GraphBase graphs with other
+graph manipulation software that supports the same symbolic format.
+
+All kinds of tricks are possible in the \Cee\ language, so it is
+easy to abuse the GraphBase conventions and to create data structures that
+make sense only on a particular machine. But if users follow the
+recommended ground rules, |save_graph| will be able to transform their
+graphs into files that any other GraphBase installation will be able
+to read with |restore_graph|; the graphs created on remote machines will
+then be semantically equivalent to the originals.
+
+Restrictions: Strings must contain only standard printable characters, not
+including \.\\ or \." or newline, and must be at most 4095 characters long;
+the |g->id| string should be at most 154 characters long. All
+pointers to vertices and arcs must be confined to blocks within the
+|g->data| area; blocks within |g->aux_data| are not saved or restored.
+Storage blocks in |g->data| must be ``pure''; i.e., each block must be entirely
+devoted either to |Vertex| records, or to |Arc| records, or to
+characters of strings. The |save_graph| procedure places all
+|Vertex| records into a single |Vertex| block and
+all |Arc| records into a single |Arc| block, preserving the
+relative order of the original records where possible, but it does not
+preserve the relative order of string data in memory. For example, if
+|u->name| and |v->name| point to the same memory location in the saved
+graph, they will point to different memory locations (representing equal
+strings) in the restored graph. All utility fields must conform to
+the conventions of the graph's |format| string; the \.G option, which
+leads to graphs within graphs, is not permitted in that string.
+
+@d MAX_SAVED_STRING 4095 /* longest strings supported */
+@d MAX_SAVED_ID 154 /* longest |id| supported, is less than |ID_FIELD_SIZE| */
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+@f Area int
+@f util int
+
+@(gb_save.h@>=
+extern int save_graph();
+extern Graph *restore_graph();
+
+@ Here is an overview of the \Cee\ code, \.{gb\_save.c}, for this module:
+
+@p
+#include "gb_io.h" /* we use the input/output conventions of |gb_io| */
+#include "gb_graph.h" /* and, of course, the data structures of |gb_graph| */
+@<Type declarations@>@;
+@<Private variables@>@;
+@<Private functions@>@;
+@<External functions@>
+
+@* External representation of graphs. The internal representation of
+graphs has been described in |gb_graph|. We now need to supplement
+that description by devising an alternative format suitable for
+human-and-machine-readable files.
+
+The following somewhat contrived example illustrates the simple conventions
+that we shall follow:
+$$\let\par=\cr \obeylines %
+\vbox{\halign{\.{#}\hfil
+* GraphBase graph (format IZAZZZZVZZZZSZ,3V,4A)
+"somewhat\_contrived\_example(3.14159265358979323846264338327\\
+9502884197169399375105820974944592307816406286208998628)",1,
+3,"pi"
+* Vertices
+"look",A0,15,A1
+"feel",0,-9,A1
+"",0,0,0
+* Arcs
+V0,A2,3,V1
+V1,0,5,0
+V1,0,-8,1
+0,0,0,0
+* Checksum 271828
+}}$$
+The first line specifies the 14 |format| characters and the total number
+of |Vertex| and |Arc| records; in this case there are 3 vertices and
+4~arcs. The next line or lines specify the |id|,
+|n|, and |m| fields of the |Graph| record, together with any utility
+fields that are not being ignored. In this case, the |id| is a rather
+long string; a string may be broken into parts by ending the initial parts
+with a backslash, so that no line of the file has more than 79 characters.
+The last six characters of |format| refer to the utility fields of the
+|Graph| record, and in this case they are \.{ZZZZSZ}; so all utility
+fields are ignored except the second-to-last, |y|, which is of type
+string. The |restore_graph| routine will construct a |Graph| record~|g| from
+this example in which |g->n=1|, |g->m=3|, and |g->y.s="pi"|.
+
+Notice that the individual field values for a record are separated by commas.
+If a line ends with a comma, the following line contains
+additional fields of the same record.
+
+After the |Graph| record fields have been specified, there's a special line
+`\.{*\ Vertices}', after which we learn the fields of each vertex in turn.
+First comes the |name| field, then the |arcs| field, and then any
+non-ignored utility fields. In this example the |format| characters
+for |Vertex| records are \.{IZAZZZ}, so the utility field values are
+|u.i| and |w.a|. Let |v| point to the first |Vertex| record (which incidentally
+is also pointed to by |g->vertices|), and let |a| point to the first
+|Arc| record. Then in this example we will have |v->name="look"|,
+|v->arcs=a|, |v->u.i=15|, and |v->w.a=(a+1)|.
+
+After the |Vertex| records comes a special line `\.{*\ Arcs}', followed by
+the fields of each |Arc| record in an entirely analogous way. First
+comes the |tip| field, then the |next| field, then the |len|, and finally
+the utility fields (if any). In this example the format characters
+for |Arc| utility fields are \.{ZV}; hence field |a| is ignored, and
+field~|b| is a pointer to a |Vertex|. We will have |a->tip=v|, |a->next=(a+2)|,
+|a->len=3|, and |a->b.v=(v+1)|.
+
+The null pointer |NULL| is denoted by \.0. Furthermore, a |Vertex| pointer
+is allowed to have the special value \.1, because of conventions
+explained in |gb_gates|. (This special value appears in the fourth
+field of the third arc in the example above.) The |restore_graph| procedure
+does not allow |Vertex| pointers to take on constant values
+greater than~1, nor does it permit the value `\.1' where an |Arc|
+pointer ought to be.
+
+There should be exactly as many |Vertex| and |Arc| specifications as
+indicated after the format specs at the beginning of the file. The
+final |Arc| should then be followed by a special checksum line, which
+must contain a number consistent with the data on all the previous
+lines. All information after the checksum line is ignored.
+
+Users should not edit the files produced by |save_graph|, because an
+incorrect checksum is liable to ruin everything. However, additional
+lines beginning with `\.*' may be placed as comments at the very
+beginning of the file; such lines are immune to checksumming.
+
+@ We can establish these conventions firmly in mind by writing the
+|restore_graph| routine before we write |save_graph|. The subroutine
+call |restore_graph("foo.gb")| produces a pointer to the graph
+defined in file |"foo.gb"|, or a null pointer in case that file
+is unreadable or incorrect. In the latter case, |panic_code|
+indicates the problem.
+
+@<External functions@>=
+Graph *restore_graph(f)
+ char *f; /* the file name */
+{@+Graph *g=NULL; /* the graph being restored */
+ register char *p; /* register for string manipulation */
+ int m; /* the number of |Arc| records to allocate */
+ int n; /* the number of |Vertex| records to allocate */
+ @<Open the file and parse the format line; |goto sorry| if there's trouble@>;
+ @<Create the |Graph| record |g| and fill in its fields@>;
+ @<Fill in the fields of all |Vertex| records@>;
+ @<Fill in the fields of all |Arc| records@>;
+ @<Check the checksum and close the file@>;
+ return g;
+sorry: gb_weak_close();@+gb_recycle(g);@+return NULL;
+}
+
+@ As mentioned above, users can add comment lines at the beginning
+of the file, if they put a \.* at the beginning of every such line.
+But the format line that precedes the data proper must adhere to
+strict standards.
+
+@d panic(c) {@+panic_code=c;@+goto sorry;@+}
+
+@<Open the file...@>=
+gb_weak_open(f);
+if (io_errors) panic(early_data_fault); /* can't open the file */
+while (1) {
+ gb_string(str_buf,')');
+ if (sscanf(str_buf,"* GraphBase graph (format %14[ZIVSA],%dV,%dA",
+ str_buf+80,&n,&m)==3 && strlen(str_buf+80)==14) break;
+ if (str_buf[0]!='*') panic(syntax_error); /* format line is unreadable */
+}
+
+@ The previous code has placed the graph's |format| field into
+location |str_buf+80|, and verified that it contains precisely
+14 characters, all belonging to the set $\{\.Z,\.I,\.V,\.S,\.A\}$.
+
+@<Create the |Graph| record |g| and fill in its fields@>=
+g=gb_new_graph(0);
+if (g==NULL) panic(no_room); /* out of memory before we're even started */
+gb_free(g->data);
+g->vertices=verts=gb_alloc_type(n==0?1:n,@[Vertex@],g->data);
+last_vert=verts+n;
+arcs=gb_alloc_type(m==0?1:m,@[Arc@],g->data);
+last_arc=arcs+m;
+if (gb_alloc_trouble) panic(no_room+1);
+ /* not enough room for vertices and arcs */
+strcpy(g->format,str_buf+80);
+gb_newline();
+if (gb_char()!='"') panic(syntax_error+1);
+ /* missing quotes before graph |id| string */
+p=gb_string(g->id,'"');
+if (*(p-2)=='\n' && *(p-3)=='\\' && p>g->id+2) {
+ gb_newline(); gb_string(p-3,'"');
+}
+if (gb_char()!='"') panic(syntax_error+2);
+ /* missing quotes after graph |id| string */
+@<Fill in |g->n|, |g->m|, and |g|'s utility fields@>;
+
+@ The |format| and |id| fields are slightly different from other string
+fields, because we store them directly in the |Graph| record instead of
+storing a pointer. The other fields to be filled by |restore_graph|
+can all be done by a macro called |fillin|, which invokes a subroutine
+called |fill_field|. The first parameter
+to |fillin| is the address of a field in a record; the second parameter
+is one of the codes $\{\.Z,\.I,\.V,\.S,\.A\}$. A global variable
+|comma_expected| is nonzero when this field is not the first in its record.
+
+The value returned by |fill_field| is nonzero if something goes wrong.
+
+We assume here that a utility field takes exactly as much space as
+a field of any of its constituent types.
+@^system dependencies@>
+
+@d fillin(l,t) if (fill_field((util*)&(l),t)) goto sorry
+
+@<Private f...@>=
+static int fill_field(l,t)
+ util *l; /* location of field to be filled in */
+ char t; /* its type code */
+{@+register char c; /* character just read */
+ if (t!='Z'&&comma_expected) {
+ if (gb_char()!=',') return (panic_code=13); /* missing comma */
+ if (gb_char()=='\n') gb_newline();
+ else gb_backup();
+ }
+ else comma_expected=1;
+ c=gb_char();
+ switch (t) {
+ case 'I': @<Fill in a numeric field@>;
+ case 'V': @<Fill in a vertex pointer@>;
+ case 'S': @<Fill in a string pointer@>;
+ case 'A': @<Fill in an arc pointer @>;
+ default: gb_backup();@+break;
+ }
+ return panic_code;
+}
+
+@ Some of the communication between |restore_graph| and |fillin| is best
+done via global variables.
+
+@<Private v...@>=
+static int comma_expected; /* should |fillin| look for a comma? */
+static Vertex *verts; /* beginning of the block of |Vertex| records */
+static Vertex *last_vert; /* end of the block of |Vertex| records */
+static Arc *arcs; /* beginning of the block of |Arc| records */
+static Arc *last_arc; /* end of the block of |Arc| records */
+
+@ @<Fill in a numeric field@>=
+if (c=='-') l->i=-gb_number(10);
+else {
+ gb_backup();
+ l->i=gb_number(10);
+}
+break;
+
+@ @<Fill in a vertex pointer@>=
+if (c=='V') {
+ l->v=verts+gb_number(10);
+ if (l->v>=last_vert || l->v<verts) panic_code=14; /* vertex address too big */
+} else if (c=='0' || c=='1') l->i=c-'0';
+else panic_code=15; /* vertex numeric address illegal */
+break;
+
+@ @<Fill in an arc pointer@>=
+if (c=='A') {
+ l->a=arcs+gb_number(10);
+ if (l->a>=last_arc || l->a<arcs) panic_code=16; /* arc address too big */
+} else if (c=='0') l->a=NULL;
+else panic_code=17; /* arc numeric address illegal */
+break;
+
+@ We can restore a string slightly longer than the strings we can save.
+
+@<Fill in a string pointer@>=
+if (c!='"') panic_code=18; /* missing quotes at beginning of string */
+else {@+register char* p;
+ p=gb_string(item_buf,'"');
+ while (*(p-2)=='\n' && *(p-3)=='\\' && p>item_buf+2 && p<=buffer) {
+ gb_newline(); p=gb_string(p-3,'"'); /* splice a broken string together */
+ }
+ if (gb_char()!='"') panic_code=19; /* missing quotes at end of string */
+ else if (item_buf[0]=='\0') l->s=null_string;
+ else l->s=gb_save_string(item_buf);
+}
+break;
+
+@ @<Private v...@>=
+static char item_buf[MAX_SAVED_STRING+3]; /* an item to be output */
+static char buffer[81]; /* a line of output */
+ /* NB: |buffer| must immediately follow |item_buf| */
+
+@ When all fields of a record have been filled in, we call |finish_record|
+and hope that it returns~0.
+
+@<Private f...@>=
+static int finish_record()
+{
+ if (gb_char()!='\n') return (panic_code=20); /* garbage present */
+ gb_newline();
+ comma_expected=0;
+ return 0;
+}
+
+@ @<Fill in |g->n|, |g->m|, and |g|'s utility fields@>=
+panic_code=0;
+comma_expected=1;
+fillin(g->n,'I');
+fillin(g->m,'I');
+fillin(g->u,g->format[8]);
+fillin(g->v,g->format[9]);
+fillin(g->w,g->format[10]);
+fillin(g->x,g->format[11]);
+fillin(g->y,g->format[12]);
+fillin(g->z,g->format[13]);
+if (finish_record()) goto sorry;
+
+@ The rest is easy.
+
+@<Fill in the fields of all |Vertex| records@>=
+{@+register Vertex* v;
+ gb_string(str_buf,'\n');
+ if (strcmp(str_buf,"* Vertices")!=0)
+ panic(syntax_error+3); /* introductory line for vertices is missing */
+ gb_newline();
+ for (v=verts;v<last_vert;v++) {
+ fillin(v->name,'S');
+ fillin(v->arcs,'A');
+ fillin(v->u,g->format[0]);
+ fillin(v->v,g->format[1]);
+ fillin(v->w,g->format[2]);
+ fillin(v->x,g->format[3]);
+ fillin(v->y,g->format[4]);
+ fillin(v->z,g->format[5]);
+ if (finish_record()) goto sorry;
+ }
+}
+
+@ @<Fill in the fields of all |Arc| records@>=
+{@+register Arc* a;
+ gb_string(str_buf,'\n');
+ if (strcmp(str_buf,"* Arcs")!=0)
+ panic(syntax_error+4); /* introductory line for arcs is missing */
+ gb_newline();
+ for (a=arcs;a<last_arc;a++) {
+ fillin(a->tip,'V');
+ fillin(a->next,'A');
+ fillin(a->len,'I');
+ fillin(a->a,g->format[6]);
+ fillin(a->b,g->format[7]);
+ if (finish_record()) goto sorry;
+ }
+}
+
+@ @<Check the checksum and close the file@>=
+{@+int s;
+ gb_string(str_buf,'\n');
+ if (sscanf(str_buf,"* Checksum %d",&s)!=1)
+ panic(syntax_error+5); /* checksum line is missing */
+ if (gb_weak_close()!=s) panic(late_data_fault); /* checksum does not match */
+}
+
+@* Saving a graph. Now that we know how to restore a graph, once it has
+been saved, we are ready to write the |save_graph| routine.
+
+Users say |save_graph(g,"foo.gb")|; our job is to create a file
+|"foo.gb"| from which |restore_graph("foo.gb")| will be able to
+reconstruct a graph equivalent to~|g|, assuming that |g| meets the restrictions
+stated earlier.
+If nothing goes wrong, |save_graph| should return the value zero.
+Otherwise it should return an encoded trouble report.
+
+We will set things up so that |save_graph| will produce
+a syntactically correct file |"foo.gb"| in almost
+every case, with explicit error indications written at the end of the file
+whenever certain aspects of the given graph had to be changed.
+The value |-1| will be returned if |g==NULL|; the value
+|-2| will be returned if |g!=NULL| but the file |"foo.gb"| could not
+be opened for output; in other cases a file |"foo.gb"| will be created.
+
+Here is a list of things that might go wrong, and the corresponding
+corrective actions to be taken in each case, assuming that
+|save_graph| does create a file:
+
+@d bad_format_code 0x1 /* illegal |format| character, is changed to |'Z'| */
+@d string_too_long 0x2 /* extralong string, is truncated */
+@d addr_not_in_data_area 0x4 /* address out of range, is changed to |NULL| */
+@d addr_in_mixed_block 0x8 /* address not in pure block, is |NULL|ified */
+@d bad_string_char 0x10 /* illegal string character, is changed to |'?'| */
+@d ignored_data 0x20 /* nonzero value in |'Z'| format, is not output */
+
+@<Private v...@>=
+static long anomalies; /* problems accumulated by |save_graph| */
+static FILE *save_file; /* the file being written */
+
+@ @<External f...@>=
+int save_graph(g,f)
+ Graph *g; /* graph to be saved */
+ char *f; /* name of the file to be created */
+{@+@<Local variables for |save_graph|@>;
+ if (g==NULL || g->vertices==NULL) return -1; /* where is |g|? */
+ save_file=fopen(f,"w");
+ if (!save_file) return -2; /* oops, the operating system won't cooperate */
+ anomalies=0;
+ @<Figure out the extent of |g|'s internal records@>;
+ @<Translate |g| into external format@>;
+ @<Make notes at the end of the file about any changes that were necessary@>;
+ fclose(save_file);
+ gb_free(working_storage);
+ return anomalies;
+}
+
+@ The main difficulty faced by |save_graph| is the problem of
+translating vertex and arc pointers into symbolic form. A graph's
+vertices usually appear in a single block, |g->vertices|, but its arcs
+usually appear in separate blocks that were created whenever the
+|gb_new_arc| routine needed more space. Other blocks, created by
+|gb_save_string|, are usually also present in the |g->data| area. We
+need to identify the various data blocks, and we also want to be able
+to handle graphs that have been created with homegrown methods of
+memory allocation, because GraphBase structures need not conform to
+the conventions of |gb_new_arc| and |gb_save_string|.
+
+A simple data structure based on \&{block\_rep} records will
+facilitate our task. Each \&{block\_rep} will be set up to contain
+the information we need to know about a particular block of data
+accessible from |g->data|. Such blocks are classified into four
+categories, identified by the |cat| field in a \&{block\_rep}:
+
+@d unk 0 /* |cat| value for blocks of unknown nature */
+@d ark 1 /* |cat| value for blocks assumed to hold |Arc| records */
+@d vrt 2 /* |cat| value for blocks assumed to hold |Vertex| records */
+@d mxt 3 /* |cat| value for blocks being used for more than one purpose */
+
+@<Type...@>=
+typedef struct {
+ char *start_addr; /* starting address of a data block */
+ char *end_addr; /* ending address of a data block */
+ long offset; /* index number of first record in the block, if known */
+ int cat; /* |cat| code for the block */
+ int expl; /* have we finished exploring this block? */
+} block_rep;
+
+@ The |block_rep| records don't need to be linked together in any fancy way,
+because there usually aren't very many of them. We will simply create
+an array, organized in decreasing order of |start_addr| and |end_addr|, with a
+dummy record standing as a sentinel at the end.
+
+A system-dependent change needs to be made here if pointer values can be
+longer than 32 bits.
+@^system dependencies@>
+
+@<Private v...@>=
+static block_rep* blocks; /* beginning of table of block representatives */
+static Area working_storage;
+
+@ Initially we set the |end_addr| field to the location following a
+block's data area. Later we will change it as explained below.
+
+The code in this section uses the fact that all bits of storage blocks
+are zero until set nonzero. In particular, the |cat| field of each
+|block_rep| will initially be |unk|, and the |expl| will be zero;
+the |start_addr| and |end_addr| of the sentinel record will be zero.
+
+@<Initialize the |blocks| array@>=
+{@+Area t; /* variable that runs through |g->data| */
+ for (*t=*(g->data),block_count=0;*t;*t=(*t)->next) block_count++;
+ blocks=gb_alloc_type(block_count+1,@[block_rep@],working_storage);
+ for (*t=*(g->data),block_count=0;*t;*t=(*t)->next,block_count++) {
+ cur_block=blocks+block_count;
+ while (cur_block>blocks&&(cur_block-1)->start_addr<(*t)->first) {
+ cur_block->start_addr=(cur_block-1)->start_addr;
+ cur_block->end_addr=(cur_block-1)->end_addr;
+ cur_block--;
+ }
+ cur_block->start_addr=(*t)->first;
+ cur_block->end_addr=(char*)*t;
+ }
+}
+
+@ @<Local variables for |save...@>=
+register block_rep *cur_block; /* the current block of interest */
+int block_count; /* how many blocks have we processed? */
+
+@ The |save_graph| routine makes two passes over the graph. The
+goal of the first pass is reconnaissance: We try to see where everything
+is, and we prune off parts that don't conform to the restrictions.
+When we get to the second pass, our task will then be almost trivial:
+We will be able to march through the known territory and spew out a copy
+of what we encounter.
+
+The first pass is essentially a sequence of calls of the |lookup| macro,
+which looks at one field of one record and notes whether or not
+the existence of this field extends the known boundaries of the graph.
+The |lookup| macro is a shorthand notation for calling the |classify|
+subroutine. We make the same assumption about field sizes as the
+|fill_field| routine did above.
+@^system dependencies@>
+
+@d lookup(l,t) classify((util*)&(l),t) /* explore field |l| of format |t| */
+
+@<Private f...@>=
+classify(l,t)
+ util *l; /* location of field to be classified */
+ char t; /* its type code, from the set $\{\.Z,\.I,\.V,\.S,\.A\}$ */
+{@+register block_rep *cur_block;
+ register char* loc;
+ register int tcat; /* category corresponding to |t| */
+ register int tsize; /* record size corresponding to |t| */
+ switch (t) {
+ default: return;
+ case 'V': if (l->i==1) return;
+ tcat=vrt;
+ tsize=sizeof(Vertex);
+ break;
+ case 'A': tcat=ark;
+ tsize=sizeof(Arc);
+ break;
+ }
+ if (l->i==0) return;
+ @<Classify a pointer variable@>;
+}
+
+@ At this point we know that |l| either points to a |Vertex| or
+to an |Arc|, according as |tcat| is |vrt| or |ark|. We need to check that
+this doesn't violate any assumptions about all such pointers lying
+in pure blocks within the |g->data| area.
+
+@<Classify a pointer variable@>=
+loc=(char*)l->v;
+for (cur_block=blocks; cur_block->start_addr>loc; cur_block++) ;
+if (loc<cur_block->end_addr) {
+ if ((loc-cur_block->start_addr)%tsize!=0 || loc+tsize>cur_block->end_addr)
+ cur_block->cat=mxt;
+ if (cur_block->cat==unk) cur_block->cat=tcat;
+ else if (cur_block->cat!=tcat) cur_block->cat=mxt;
+}
+
+@ We go through the list of blocks repeatedly until reaching a stable
+situation in which every |vrt| or |ark| block has been explored.
+
+@<Figure out the extent of |g|'s internal records@>=
+{@+int activity;
+ @<Initialize the |blocks| array@>;
+ lookup(g->vertices,'V');
+ lookup(g->u,g->format[8]);
+ lookup(g->v,g->format[9]);
+ lookup(g->w,g->format[10]);
+ lookup(g->x,g->format[11]);
+ lookup(g->y,g->format[12]);
+ lookup(g->z,g->format[13]);
+ do {@+activity=0;
+ for(cur_block=blocks;cur_block->end_addr;cur_block++) {
+ if (cur_block->cat==vrt && !cur_block->expl)
+ @<Explore a block of supposed vertex records@>@;
+ else if (cur_block->cat==ark && !cur_block->expl)
+ @<Explore a block of supposed arc records@>@;
+ else continue;
+ cur_block->expl=activity=1;
+ }
+ }@+while (activity);
+}
+
+@ While we are exploring a block, the |lookup| routine might classify
+a previously explored block (or even the current block) as |mxt|.
+Therefore some data we assumed would be accessible will actually be
+removed from the graph; contradictions that arose may no longer exist.
+But we plunge ahead anyway, because we aren't going to try especially
+hard to ``save'' portions of graphs that violate our ground rules.
+
+@<Explore a block of supposed vertex records@>=
+{@+register Vertex*v;
+ for (v=(Vertex*)cur_block->start_addr;@|
+ (char*)(v+1)<=cur_block->end_addr && cur_block->cat==vrt;v++) {
+ lookup(v->arcs,'A');
+ lookup(v->u,g->format[0]);
+ lookup(v->v,g->format[1]);
+ lookup(v->w,g->format[2]);
+ lookup(v->x,g->format[3]);
+ lookup(v->y,g->format[4]);
+ lookup(v->z,g->format[5]);
+ }
+}
+
+@ @<Explore a block of supposed arc records@>=
+{@+register Arc*a;
+ for (a=(Arc*)cur_block->start_addr;@|
+ (char*)(a+1)<=cur_block->end_addr && cur_block->cat==ark;a++) {
+ lookup(a->tip,'V');
+ lookup(a->next,'A');
+ lookup(a->a,g->format[6]);
+ lookup(a->b,g->format[7]);
+ }
+}
+
+@ OK, the first pass is complete. And the second pass is routine:
+
+@<Translate |g| into external format@>=
+@<Orient the |blocks| table for translation@>;
+@<Initialize the output buffer mechanism and output the first line@>;
+@<Translate the |Graph| record@>;
+@<Translate the |Vertex| records@>;
+@<Translate the |Arc| records@>;
+@<Output the checksum line@>;
+
+@ During this pass we decrease the |end_addr| field of a |block_rep|,
+so that it points to the first byte of
+the final record in a |vrt| or |ark| block.
+
+The variables |m| and |n| will be set to the number of arc records and
+vertex records, respectively.
+
+@<Local variables for |save...@>=
+int m; /* total number of |Arc| records to be translated */
+int n; /* total number of |Vertex| records to be translated */
+register int s; /* accumulator register for arithmetic calculations */
+
+@ One tricky point needs to be observed, in the unusual case that there are
+two or more block of \&{Vertex} records: The base block |g->vertices| must
+come first in the final ordering. (This is the only exception to the rule
+that \&{Vertex} and \&{Arc} records retain their relative order with respect
+to less-than and greater-than.)
+
+@<Orient the |blocks| table for translation@>=
+m=0;@+@<Set |n| to the size of the block that starts with |g->vertices|@>;
+for (cur_block=blocks+block_count-1;cur_block>=blocks;cur_block--) {
+ if (cur_block->cat==vrt) {
+ s=(cur_block->end_addr-cur_block->start_addr)/sizeof(Vertex);
+ cur_block->end_addr=cur_block->start_addr+((s-1)*sizeof(Vertex));
+ if (cur_block->start_addr!=(char*)g->vertices) {
+ cur_block->offset=n;@+ n+=s;
+ } /* otherwise |cur_block->offset| remains zero */
+ } else if (cur_block->cat==ark) {
+ s=(cur_block->end_addr-cur_block->start_addr)/sizeof(Arc);
+ cur_block->end_addr=cur_block->start_addr+((s-1)*sizeof(Arc));
+ cur_block->offset=m;
+ m+=s;
+ }
+}
+
+@ @<Set |n| to the size of the block that starts with |g->vertices|@>=
+n=0;
+for (cur_block=blocks+block_count-1;cur_block>=blocks;cur_block--)
+ if (cur_block->start_addr==(char *)g->vertices) {
+ n=(cur_block->end_addr-cur_block->start_addr)/sizeof(Vertex);
+ break;
+ }
+
+@ We will store material to be output in the |buffer| array,
+so that we can compute the correct checksum.
+
+@<Private v...@>=
+static char *buf_ptr; /* the first unfilled position in |buffer| */
+static long magic; /* the checksum */
+
+@ @<Private f...@>=
+static flushout() /* output the buffer to |save_file| */
+{
+ *buf_ptr++='\n';
+ *buf_ptr='\0';
+ magic=new_checksum(buffer,magic);
+ fputs(buffer,save_file);
+ buf_ptr=buffer;
+}
+
+@ If a supposed string pointer is zero, we output the null string.
+(This case arises when a string field has not been initialized,
+for example in vertices and arcs that have been allocated but not used.)
+
+@<Private f...@>=
+static prepare_string(s)
+ char *s; /* put a string into |item_buf| and possible |split_string| */
+{@+register char *p,*q;
+ item_buf[0]='"';
+ p=&item_buf[1];
+ if (s==0) goto sready;
+ for (q=s;*q&&p<=&item_buf[MAX_SAVED_STRING];q++,p++)
+ if (*q=='"'||*q=='\n'||*q=='\\'||imap_ord(*q)==unexpected_char) {
+ anomalies |= bad_string_char;
+ *p='?';
+ } else *p=*q;
+ if (*q) anomalies |= string_too_long;
+sready: *p='"';
+ *(p+1)='\0';
+}
+
+@ The main idea of this part of the program is to format an item into
+|item_buf|, then move it to |buffer|, making sure that there is always
+room for a comma.
+
+@d append_comma *buf_ptr++=','
+
+@<Private f...@>=
+static move_item()
+{@+register int l=strlen(item_buf);
+ if (buf_ptr+l>&buffer[78]) {
+ if (l<=78) flushout();
+ else {@+register char *p=item_buf;
+ if (buf_ptr>&buffer[77]) flushout();
+ /* no room for initial \.{\char`\"} */
+ do@+{
+ for (;buf_ptr<&buffer[78];buf_ptr++,p++,l--) *buf_ptr=*p;
+ *buf_ptr++='\\';
+ flushout();
+ }@+while(l>78);
+ strcpy(buffer,p);
+ buf_ptr=&buffer[l];
+ return;
+ }
+ }
+ strcpy(buf_ptr,item_buf);
+ buf_ptr+=l;
+}
+
+@ @<Initialize the output buffer mechanism and output the first line@>=
+buf_ptr=buffer;
+magic=0;
+fputs("* GraphBase graph (format ",save_file);
+{@+register char*p;
+ for (p=g->format;p<g->format+14;p++)
+ if (*p=='Z'||*p=='I'||*p=='V'||*p=='S'||*p=='A') fputc(*p,save_file);
+ else fputc('Z',save_file);
+}
+fprintf(save_file,",%dV,%dA)\n",n,m);
+
+@ A macro called |translate|, which is sort of an inverse to |fillin|,
+takes care of the main work in the second pass.
+
+@d translate(l,t) translate_field((util*)&(l),t)
+
+@<Private f...@>=
+translate_field(l,t)
+ util *l; /* address of field to be output in symbolic form */
+ char t; /* type of formatting desired */
+{@+register block_rep *cur_block;
+ register char* loc;
+ register int tcat; /* category corresponding to |t| */
+ register int tsize; /* record size corresponding to |t| */
+ if (comma_expected) append_comma;
+ else comma_expected=1;
+ switch (t) {
+ default: anomalies|=bad_format_code;
+ /* fall through to case \.Z */
+ case 'Z': buf_ptr--; /* forget spurious comma */
+ if (l->i) anomalies|=ignored_data;
+ return;
+ case 'I': numeric: sprintf(item_buf,"%d",l->i);@+goto ready;
+ case 'S': prepare_string(l->s);@+goto ready;
+ case 'V': if (l->i==1) goto numeric;
+ tcat=vrt;@+tsize=sizeof(Vertex);@+break;
+ case 'A': tcat=ark;@+tsize=sizeof(Arc);@+break;
+ }
+ @<Translate a pointer variable@>;
+ready:move_item();
+}
+
+@ @<Translate a pointer variable@>=
+loc=(char*)l->v;
+item_buf[0]='0';@+item_buf[1]='\0'; /* |NULL| will be the default */
+if (loc==NULL) goto ready;
+for (cur_block=blocks; cur_block->start_addr>loc; cur_block++) ;
+if (loc>cur_block->end_addr) {
+ anomalies|=addr_not_in_data_area;
+ goto ready;
+}
+if (cur_block->cat!=tcat||(loc-cur_block->start_addr)%tsize!=0) {
+ anomalies|=addr_in_mixed_block;
+ goto ready;
+}
+sprintf(item_buf,"%c%d",t,
+ cur_block->offset+((loc-cur_block->start_addr)/tsize));
+
+@ @<Translate the |Graph| record@>=
+prepare_string(g->id);
+if (strlen(g->id)>MAX_SAVED_ID) {
+ strcpy(item_buf+MAX_SAVED_ID+1,"\"");
+ anomalies|=string_too_long;
+}
+move_item();
+comma_expected=1;
+translate(g->n,'I');
+translate(g->m,'I');
+translate(g->u,g->format[8]);
+translate(g->v,g->format[9]);
+translate(g->w,g->format[10]);
+translate(g->x,g->format[11]);
+translate(g->y,g->format[12]);
+translate(g->z,g->format[13]);
+flushout();
+
+@ @<Translate the |Vertex| records@>=
+{@+register Vertex* v;
+ fputs("* Vertices\n",save_file);
+ for (cur_block=blocks+block_count-1;cur_block>=blocks;cur_block--)
+ if (cur_block->cat==vrt && cur_block->offset==0)
+ @<Translate all |Vertex| records in |cur_block|@>;
+ for (cur_block=blocks+block_count-1;cur_block>=blocks;cur_block--)
+ if (cur_block->cat==vrt && cur_block->offset!=0)
+ @<Translate all |Vertex| records in |cur_block|@>;
+}
+
+@ @<Translate all |Vertex| records in |cur_block|@>=
+for (v=(Vertex*)cur_block->start_addr;
+ v<=(Vertex*)cur_block->end_addr;v++) {
+ comma_expected=0;
+ translate(v->name,'S');
+ translate(v->arcs,'A');
+ translate(v->u,g->format[0]);
+ translate(v->v,g->format[1]);
+ translate(v->w,g->format[2]);
+ translate(v->x,g->format[3]);
+ translate(v->y,g->format[4]);
+ translate(v->z,g->format[5]);
+ flushout();
+}
+
+@ @<Translate the |Arc| records@>=
+{@+register Arc* a;
+ fputs("* Arcs\n",save_file);
+ for (cur_block=blocks+block_count-1;cur_block>=blocks;cur_block--)
+ if (cur_block->cat==ark)
+ for (a=(Arc*)cur_block->start_addr;a<=(Arc*)cur_block->end_addr;a++) {
+ comma_expected=0;
+ translate(a->tip,'V');
+ translate(a->next,'A');
+ translate(a->len,'I');
+ translate(a->a,g->format[6]);
+ translate(a->b,g->format[7]);
+ flushout();
+ }
+}
+
+@ @<Output the checksum line@>=
+fprintf(save_file,"* Checksum %d\n",magic);
+
+@ @<Make notes at the end of the file about any changes that were necessary@>=
+if (anomalies) {
+ fputs("> WARNING: I had trouble making this file from the given graph!\n",
+ save_file);
+ if (anomalies&bad_format_code)
+ fputs(">> The original format string had to be corrected.\n",save_file);
+ if (anomalies&ignored_data)
+ fputs(">> Some data suppressed by Z format was actually nonzero.\n",
+ save_file);
+ if (anomalies&string_too_long)
+ fputs(">> At least one long string had to be truncated.\n",
+ save_file);
+ if (anomalies&bad_string_char)
+ fputs(">> At least one string character had to be changed to '?'.\n",
+ save_file);
+ if (anomalies&addr_not_in_data_area)
+ fputs(">> At least one pointer led out of the data area.\n",save_file);
+ if (anomalies&addr_in_mixed_block)
+ fputs(">> At least one data block had an illegal mixture of records.\n",
+ save_file);
+ if (anomalies&(addr_not_in_data_area+addr_in_mixed_block))
+ fputs(">> (Pointers to improper data have been changed to 0.)\n",
+ save_file);
+ fputs("> You should be able to read this file with restore_graph,\n",
+ save_file);
+ fputs("> but the graph you get won't be exactly like the original.\n",
+ save_file);
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_sort.w b/support/graphbase/gb_sort.w
new file mode 100644
index 0000000000..831bae134b
--- /dev/null
+++ b/support/graphbase/gb_sort.w
@@ -0,0 +1,177 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_\thinspace SORT}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+@* Introduction. This short GraphBase module provides a simple utility
+routine called |gb_linksort|, which is used in many of the other programs.
+
+@d NULL 0 /* |NULL| */
+
+@p
+#include "gb_flip.h" /* we need to use the random number generator */
+@<Declarations@>@;
+@<The |gb_linksort| routine@>
+
+@ Most of the graphs obtained from GraphBase data are parameterized,
+so that different effects can be obtained easily from the same
+underlying body of information. In many cases the desired graph
+is determined by selecting the ``heaviest'' vertices according to some
+notion of ``weight,'' and/or by taking a random sample of vertices. For
+example, the GraphBase routine |words(n,wt_vector,wt_threshold,seed)| creates a
+graph based on the |n| most common words of English, where common-ness is
+determined by a given weight vector. When several words have equal weight,
+we want to choose between them at random. In particular, this means that
+we can obtain a completely random choice of words if the weight vector
+assigns the same weight to each word.
+
+The |gb_linksort| routine is a convenient tool for this purpose. It takes a
+given linked list of nodes and shuffles their link fields so that the
+nodes can be read in decreasing order of weight, and so that equal-weight
+nodes appear in random order. {\sl Note: The random number generator of
+|gb_flip| must be initialized before |gb_linksort| is called.}
+
+The nodes sorted by |gb_linksort| can be records of any structure type,
+provided only that the first field is `|long| |key|' and the second field
+is `|struct| \\{this\_struct\_type} |*link|'. Further fields are not
+examined. The |node| type defined below is the simplest possible
+example of such a structure.
+
+Sorting is done by means of the |key| fields, which must each contain
+nonnegative integers less than $2^{31}$.
+
+After sorting is complete, the data will appear in 128 linked lists:
+|gb_sorted[127]|, |gb_sorted[126]|, \dots, |gb_sorted[0]|. Reading through
+these lists with a routine such as
+$$\vcenter{\halign{#\hfil\cr
+|{@+int j; @+node *p;|\cr
+\quad|for (j=127; j>=0; j--)|\cr
+\qquad|for (p=(node*)gb_sorted[j]; p; p=p->link)|\cr
+\qquad\qquad\\{look\_at}|(p)|;\cr
+}}$$
+will look at the nodes in decreasing order of weight, as desired. In fact,
+all nodes whose keys are in the range $j\cdot2^{24}\le|key|<(j+1)\cdot2^{24}$
+will appear in list |gb_sorted[j]|. Therefore the results will all be found
+in the single list |gb_sorted[0]|, if all the keys are strictly less
+than~$2^{24}$.
+
+@<Declarations@>=
+typedef struct node_struct {
+ long key; /* a numeric quantity, assumed nonnegative */
+ struct node_struct *link; /* the next node on a list */
+} node; /* applications of |gb_linksort| may have other fields after |link| */
+
+@ In the header file, |gb_sorted| is declared to be
+an array of pointers to |char|, since
+nodes may have different types in different applications. User programs
+should cast |gb_sorted| to the appropriate type as in the example above.
+
+@(gb_sort.h@>=
+extern void gb_linksort(); /* procedure to sort a linked list */
+extern char* gb_sorted[]; /* the results of |gb_linksort| */
+
+@ Six passes of a radix sort, using radix 256, will accomplish the desired
+objective rather quickly. (See, for example, Algorithm 5.2.5R in
+{\sl Sorting and Searching}.) The first two passes use random numbers instead
+of looking at the key fields, thereby effectively extending the keys
+so that nodes with equal keys will appear in reasonably random order.
+
+We move the nodes back and forth between two arrays of lists: the external
+array |gb_sorted| and a private array called |alt_sorted|.
+
+@<Declarations@>=
+node *gb_sorted[256]; /* external bank of lists, for even-numbered passes */
+static node *alt_sorted[256];
+ /* internal bank of lists, for odd-numbered passes */
+
+@ So here we go with six passes over the data.
+
+@<The |gb_linksort| routine@>=
+void gb_linksort(l)
+ node *l;
+{@+register int k; /* index to destination list */
+ register node **pp; /* current place in list of pointers */
+ register node *p, *q; /* pointers for list manipulation */
+ @<Partition the given list into 256 random sublists |alt_sorted|@>;
+ @<Partition the |alt_sorted| lists into 256 random sublists |gb_sorted|@>;
+ @<Partition the |gb_sorted| lists into |alt_sorted| by low-order byte@>;
+ @<Partition the |alt_sorted| lists into |gb_sorted| by second-lowest byte@>;
+ @<Partition the |gb_sorted| lists into |alt_sorted| by second-highest byte@>;
+ @<Partition the |alt_sorted| lists into |gb_sorted| by high-order byte@>;
+}
+
+@ @<Partition the given list into 256 random sublists |alt_sorted|@>=
+for (pp=alt_sorted+255; pp>=alt_sorted; pp--) *pp=NULL;
+ /* empty all the destination lists */
+for (p=l; p; p=q) {
+ k=gb_next_rand() >> 23; /* extract the eight most significant bits */
+ q=p->link;
+ p->link=alt_sorted[k];
+ alt_sorted[k]=p;
+}
+
+@ @<Partition the |alt_sorted| lists into 256 random sublists |gb_sorted|@>=
+for (pp=gb_sorted+255; pp>=gb_sorted; pp--) *pp=NULL;
+ /* empty all the destination lists */
+for (pp=alt_sorted+255; pp>=alt_sorted; pp--)
+ for (p=*pp; p; p=q) {
+ k=gb_next_rand() >> 23; /* extract the eight most significant bits */
+ q=p->link;
+ p->link=gb_sorted[k];
+ gb_sorted[k]=p;
+}
+
+@ @<Partition the |gb_sorted| lists into |alt_sorted| by low-order byte@>=
+for (pp=alt_sorted+255; pp>=alt_sorted; pp--) *pp=NULL;
+ /* empty all the destination lists */
+for (pp=gb_sorted+255; pp>=gb_sorted; pp--)
+ for (p=*pp; p; p=q) {
+ k=p->key & 0xff; /* extract the eight least significant bits */
+ q=p->link;
+ p->link=alt_sorted[k];
+ alt_sorted[k]=p;
+}
+
+@ Here we must read from |alt_sorted| from 0 to 255, not from 255 to 0,
+to get the desired final order. (Each pass reverses the order of the lists;
+it's tricky, but it works.)
+
+@<Partition the |alt_sorted| lists into |gb_sorted| by second-lowest byte@>=
+for (pp=gb_sorted+255; pp>=gb_sorted; pp--) *pp=NULL;
+ /* empty all the destination lists */
+for (pp=alt_sorted; pp<alt_sorted+256; pp++)
+ for (p=*pp; p; p=q) {
+ k=(p->key >> 8) & 0xff; /* extract the next eight bits */
+ q=p->link;
+ p->link=gb_sorted[k];
+ gb_sorted[k]=p;
+}
+
+@ @<Partition the |gb_sorted| lists into |alt_sorted| by second-highest byte@>=
+for (pp=alt_sorted+255; pp>=alt_sorted; pp--) *pp=NULL;
+ /* empty all the destination lists */
+for (pp=gb_sorted+255; pp>=gb_sorted; pp--)
+ for (p=*pp; p; p=q) {
+ k=(p->key >> 16) & 0xff; /* extract the next eight bits */
+ q=p->link;
+ p->link=alt_sorted[k];
+ alt_sorted[k]=p;
+}
+
+@ The most significant bits will lie between 0 and 127, because we assumed
+that the keys are nonnegative and less than $2^{31}$. (A similar routine
+would be able to sort signed integers, or unsigned long integers, but
+the \Cee\ code would not then be portable.)
+
+@<Partition the |alt_sorted| lists into |gb_sorted| by high-order byte@>=
+for (pp=gb_sorted+255; pp>=gb_sorted; pp--) *pp=NULL;
+ /* empty all the destination lists */
+for (pp=alt_sorted; pp<alt_sorted+256; pp++)
+ for (p=*pp; p; p=q) {
+ k=(p->key >> 24) & 0xff; /* extract the most significant bits */
+ q=p->link;
+ p->link=gb_sorted[k];
+ gb_sorted[k]=p;
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/gb_words.w b/support/graphbase/gb_words.w
new file mode 100644
index 0000000000..5a83b67e49
--- /dev/null
+++ b/support/graphbase/gb_words.w
@@ -0,0 +1,561 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GB\_WORDS}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\font\logosl=logosl10
+
+\prerequisites{GB\_\thinspace GRAPH}{GB\_\thinspace IO}
+@* Introduction. This GraphBase module provides two external subroutines:
+$$\vcenter{\halign{#\hfil\cr
+ |words|, a routine that creates a graph based on five-letter words;\cr
+ |find_word|, a routine that looks for a given vertex in such a graph.\cr}}$$
+Examples of the use of these routines can be found in the demo programs
+called |word_components| and |ladders|.
+
+@(gb_words.h@>=
+extern Graph *words();
+extern Vertex *find_word();
+
+@ The subroutine call `|words(n,wt_vector,wt_threshold,seed)|'
+constructs a graph based on the five-letter words in \.{words.dat}.
+Each vertex of the graph corresponds to a single five-letter word. Two
+words are adjacent in the graph if they are the same except in one
+letter position. For example, `\.{words}' is adjacent to other words such as
+`\.{cords}', `\.{wards}', `\.{woods}', `\.{worms}', and `\.{wordy}'.
+
+The constructed graph has at most |n| vertices; indeed, it has exactly
+|n| vertices if there are enough qualifying words. A word `qualifies'
+if its weight is |wt_threshold| or more, where the `weight' is
+computed from a table pointed to by~|wt_vector| according to rules
+described below. (If parameter~|wt_vector|
+is |NULL|, i.e., \.{NULL}, default weights are used.) The fourth parameter,
+|seed|, is the seed of a random number generator.
+
+All words of \.{words.dat} are sorted by weight. The first vertex of
+the graph will be the word of largest
+weight, the second vertex will have second-largest weight, and so on.
+Words of equal weight will appear in pseudo-random order, as determined
+by the value of |seed| in a system-independent fashion.
+The first |n| words in order of decreasing weight are chosen to be
+vertices of the graph. However, if fewer than |n| words have weight |>=
+wt_threshold|, the graph will contain only the words that qualify. In
+such cases the graph will have fewer than |n| vertices---possibly none at all.
+
+Exception: The special case |n=0| is equivalent to the case when |n|
+has been set to the highest possible value. It causes all qualifying
+words to appear.
+
+@ Every word in \.{words.dat} has been classified as `common' (\.*), `advanced'
+(\.+), or `unusual' (\.\ ). Each word has also been assigned seven
+frequency counts $c_1$, \dots,~$c_7$, separated by commas; these counts show
+how often the word has occurred in different publication contexts:
+$$\vcenter{\halign{$c_#$ times in &#\hfil\cr
+1&the American Heritage Intermediate Corpus of elementary school material;\cr
+2&the Brown Corpus of reading material from America;\cr
+3&the Lancaster-Oslo/Bergen Corpus of reading material from Britain;\cr
+4&the Melbourne-Surrey Corpus of newspaper material from Australia;\cr
+5&the Revised Standard Version of the Bible;\cr
+6&{\sl The \TeX book\/} and {\sl The {\logosl METAFONT\kern1pt}book\/}
+ by D. E. Knuth;\cr
+7&{\sl Concrete Mathematics\/} by Graham, Knuth, and Patashnik.\cr}}$$
+For example, one of the entries in \.{words.dat} is
+$$\.{happy*774,92,121,2,26,8,1}$$
+indicating a common word with $c_1=774$, \dots, $c_7=1$.
+
+Parameter |wt_vector| points to an array of nine integers
+$(a,b,w_1,\ldots,w_7)$.
+The weight of each word is computed from these nine numbers by using the
+formula
+$$c_1w_1+\cdots+c_7w_7+
+ \cases{a,&if the word is `common';\cr
+ b,&if the word is `advanced';\cr
+ 0,&if the word is `unusual'.\cr}$$
+The components of |wt_vector| must be chosen so that
+$$\max\bigl(\vert a\vert, \vert b\vert\bigr)
+ + C_1\vert w_1\vert + \cdots +C_7\vert w_7\vert < 2^{30},$$
+where $C_j$ is the maximum value of $c_j$ in the file; this restriction
+ensures that the |words| procedure will produce the same results on all
+computer systems.
+
+@ The maximum frequency counts actually present are $C_1=15194$, $C_2=3560$,
+$C_3=4467$, $C_4=460$, $C_5=6976$, $C_6=756$, and $C_7=362$; these can be
+found in the entries for the common words `\.{shall}', `\.{there}',
+`\.{which}', and `\.{would}'.
+
+The default weights are $a=100$, $b=10$, $c_1=4$, $c_2=c_3=2$, $c_4=c_5=
+c_6=c_7=1$.
+
+File \.{words.dat} contains 5678 words, of which 3294 are `common', 1189 are
+`advanced', and 1195 are `unusual'. Included among the unusual words are
+823 having $c_1=\cdots=c_7=0$; such words
+will always have weight zero, regardless of the weight vector parameter.
+
+@<Private variables@>=
+static int max_c[]={15194,3560,4467,460,6976,756,362};
+ /* maximum counts $C_j$ */
+static int default_wt_vector[]={100,10,4,2,2,1,1,1,1};
+ /* use this if |wt_vector=NULL| */
+
+@ Examples: If you call |words(2000,NULL,0,0)|, you get a graph with
+2000 of the most common five-letter words of English, using the
+default weights. The GraphBase programs are designed to be
+system-independent, so that identical graphs will be obtained by
+everybody who asks for |words(2000,NULL,0,0)|. Equivalent experiments
+on algorithms for graph manipulation can therefore be performed by
+researchers in different parts of the world.
+
+The subroutine call |words(2000,NULL,0,s)| will produce slightly
+different graphs when the random seed |s| varies, because some words
+have equal weight. However, the graph for any particular value of~|s|
+will be the same on all computers. The seed value can be any integer
+in the range $0\le s<2^{31}$.
+
+Suppose you call |words(6000,w,1,0)|, with |w| defined by the \Cee\ declaration
+$$\hbox{|int w[9] = {1};|}$$
+this means that $a=1$ and $b=w_1=\cdots=w_7=0$. Therefore you'll get a graph
+containing only the 3294 `common' words. Similarly, it's possible to obtain
+only the $3294+1189=4483$ non-`unusual' words, by specifying the weight vector
+$$\hbox{|int w[9] = {1,1};|}$$
+this makes $a=b=1$ and $w_1=\cdots=w_7=0$. In both of these examples, the
+qualifying words all have weight~1, so the vertices of the graph will appear
+in pseudo-random order.
+
+If |w| points to an array of nine 0's, the call |words(n,w,0,s)| gives a
+random sample of |n| words, depending on |s| in a system-independent fashion.
+
+If the entries of the weight vector are all nonnegative, and if the
+weight threshold is zero, every word of \.{words.dat} will qualify. Thus
+you will obtain a graph with $\min(n,5678)$ vertices.
+
+If |w| points to an array with {\it negative\/} weights, the call
+|words(n,w,-0x7fffffff,0)| selects |n| of the {\it least\/} common
+words in \.{words.dat}.
+
+@ If the |words| routine encounters a problem, it returns |NULL|, after putting
+a code number into the external variable |panic_code|. This code number
+identifies the type of failure. Otherwise |words| returns a pointer to the
+newly created graph, which will be represented with the data structures
+explained in |gb_graph|. (The external variable |@!panic_code| is itself
+defined in |gb_graph|.)
+
+@d panic(c) @+{@+gb_free(node_blocks);
+ panic_code=c;@+gb_alloc_trouble=0;@+return NULL;@+}
+@#
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Area int
+
+@ Now let's get going on the program. The \Cee\ file \.{gb\_words.c} begins
+as follows:
+
+@p
+#include "gb_io.h" /* we will use the |gb_io| routines for input */
+#include "gb_flip.h" /* we will use the |gb_flip| routines for random numbers */
+#include "gb_graph.h" /* we will use the |gb_graph| data structures */
+#include "gb_sort.h" /* and |gb_linksort| for sorting */
+@#
+@<Type declarations@>@;
+@<Private variables@>@;
+@<Private functions@>@;
+@#
+Graph *words(n,wt_vector,wt_threshold,seed)
+ unsigned n; /* maximum number of vertices desired */
+ int wt_vector[]; /* pointer to array of weights */
+ long wt_threshold; /* minimum qualifying weight */
+ long seed; /* random number seed */
+{@+@<Local variables@>@;
+ gb_init_rand(seed);
+ @<Check that |wt_vector| is valid@>;
+ @<Input the qualifying words to a linked list, computing their weights@>;
+ @<Sort and output the words, determining adjacencies@>;
+ if (gb_alloc_trouble) {
+ gb_recycle(new_graph);
+ panic(alloc_fault); /* oops, we ran out of memory somewhere back there */
+ }
+ return new_graph;
+}
+
+@ @<Local var...@>=
+Graph *new_graph; /* the graph constructed by |words| */
+
+@* Validating the weights. The first job that |words| needs to tackle is
+comparatively trivial:
+We want to verify the condition
+$$\max\bigl(\vert a\vert, \vert b\vert\bigr)
+ + C_1\vert w_1\vert + \cdots +C_7\vert w_7\vert < 2^{30}.\eqno(*)$$
+But this proves to be an interesting exercise in ``portable
+\Cee\ programming,'' because we don't want to risk integer overflow.
+Our approach will be to do the
+calculation first in floating point arithmetic, thereby ruling out cases
+that are clearly unacceptable; once that test is passed, we will safely be
+able to test the condition with ordinary integer arithmetic. Floating
+point arithmetic is system dependent, but we will use it carefully so as to
+obtain system-independent results.
+
+@<Check that |wt_vector| is valid@>=
+if (!wt_vector) wt_vector=default_wt_vector;
+else {@+register double flacc;
+ register int *p,*q;
+ register long acc;
+ @<Use floating point arithmetic to check that |wt_vector| isn't
+ totally off base@>;
+ @<Use integer arithmetic to check that |wt_vector| is truly OK@>;
+}
+
+@ The floating-point calculations are facilitated by a routine that
+converts an integer to its absolute value, expressed as a |double|:
+
+@<Private functions@>=
+static double flabs(x)
+ int x;
+{@+if (x>=0) return (double)x;
+ return -((double)x);
+}
+
+@ Although floating point arithmetic is system dependent, we can certainly
+assume that at least sixteen bits of precision are used. This implies that
+the difference between |flabs(x)| and $\vert x\vert$ must be less
+than $2^{14}$. Also,
+if $x$ and $y$ are nonnegative values less than $2^{31}$, the difference between
+their floating-point sum and their true sum must be less than $2^{14}$.
+
+The floating point calculations in the following test will never reject a
+valid weight vector. For if condition $(*)$ holds, the floating-point value of
+$\max(\hbox{|flabs(a)|},\hbox{|flabs(b)|})+C_1*|flabs|(w_1)+\cdots
++C_7*|flabs|(w_7)$ will be less than $2^{30}+(8+C_1+\cdots+C_7)2^{14}$,
+which is less than $2^{30}+2^{29}$.
+
+@<Use float...@>=
+p=wt_vector;
+flacc=flabs(*p++);
+if (flacc<flabs(*p)) flacc=flabs(*p);
+ /* now $|flacc|=\max(\vert a\vert,\vert b\vert)$ */
+for (q=&max_c[0]; q<&max_c[7]; q++)
+ flacc += *q * flabs(*++p);
+if (flacc>=(double)0x60000000) /* this constant is
+ $6\times2^{28}=2^{30}+2^{29}$ */
+ panic(very_bad_specs); /* whoa; the weight vector is way too big */
+
+@ Conversely, if the floating point test just made is passed, the true
+value of the sum will be less than $2^{30}+2^{29}+2^{29}=2^{31}$; hence
+integer overflow will never occur when we make the following more
+refined test:
+
+@<Use int...@>=
+p=wt_vector;
+acc=iabs(*p++);
+if (acc<iabs(*p)) acc=iabs(*p);
+ /* now $|acc|=\max(\vert a\vert,\vert b\vert)$ */
+for (q=&max_c[0]; q<&max_c[7]; q++)
+ acc += *q * iabs(*++p);
+if (acc>=0x40000000)
+ panic(bad_specs); /* the weight vector is a bit too big */
+
+@ @<Private f...@>=
+static long iabs(x)
+ int x;
+{@+if (x>=0) return (long)x;
+ return -((long)x);
+}
+
+@* The input phase. Now we're ready to read \.{words.dat}.
+
+@<Local...@>=
+int c[7]; /* current counts $c_j$ */
+register long wt; /* the weight of the current word */
+char word[5]; /* the current five-letter word */
+int nn=0; /* the number of qualifying words found so far */
+
+@ As we read the words, we will form a linked list of nodes containing
+each qualifying word and its weight, using the memory management routines of
+|gb_graph| to allocate space for 111 nodes at a time. These nodes should be
+returned to available memory later, so we will keep them in a separate area
+under local control.
+
+The nodes start out with |key| and |link| fields, as required by the
+|gb_linksort| routine, which we'll use to sort by weight. The sort key must be
+nonnegative; we obtain it by adding $2^{30}$ to the weight.
+
+@d nodes_per_block 111
+
+@<Type...@>=
+typedef struct node_struct {
+ long key; /* the sort key (weight plus $2^{30}$) */
+ struct node_struct *link; /* links the nodes together */
+ char wd[5]; /* five-letter word
+ (which typically consumes eight bytes, too bad) */
+} node;
+
+@ @<Local...@>=
+node *next_node; /* the next node available for allocation */
+node *bad_node; /* if |next_node=bad_node|, the node isn't really there */
+node *stack_ptr; /* the most recently created node */
+node *cur_node; /* current node being created or examined */
+
+@ @<Private v...@>=
+Area node_blocks; /* the memory area for blocks of nodes */
+
+@ @<Input the qualifying words...@>=
+next_node=bad_node=stack_ptr=NULL;
+if (gb_open("words.dat")!=0)
+ panic(early_data_fault);
+ /* couldn't open |"words.dat"| using GraphBase conventions;
+ |io_errors| tells why */
+do @<Read one word, and put it on the stack if it qualifies@>@;
+ while (!gb_eof());
+if (gb_close()!=0)
+ panic(late_data_fault);
+ /* something's wrong with |"words.dat"|; see |io_errors| */
+
+@ @<Read one...@>=
+{@+register int j; /* position in |word| */
+ for (j=0; j<5; j++) word[j]=gb_char();
+ @<Compute the weight |wt|@>;
+ if (wt>=wt_threshold) { /* it qualifies */
+ @<Install |word| and |wt| in a new node@>;
+ nn++;
+ }
+ gb_newline();
+}
+
+@ @d copy5(y,x) { /* copy five characters from |*x| to |*y| */
+ *(y)=*(x);
+ *((y)+1)=*((x)+1);
+ *((y)+2)=*((x)+2);
+ *((y)+3)=*((x)+3);
+ *((y)+4)=*((x)+4);
+ }
+
+@<Install...@>=
+if (next_node==bad_node) {
+ cur_node=gb_alloc_type(nodes_per_block,@[node@],node_blocks);
+ if (cur_node==NULL)
+ panic(no_room+1); /* out of memory already */
+ next_node=cur_node+1;
+ bad_node=cur_node+nodes_per_block;
+} else cur_node=next_node++;
+cur_node->key=wt+0x40000000;
+cur_node->link=stack_ptr;
+copy5(cur_node->wd,word);
+stack_ptr=cur_node;
+
+@ Recall that |gb_number()| returns 0, without giving an error, if no
+digit is present in the current position of the file being read. This
+implies that the \.{words.dat} file need not include zero counts
+explicitly. Furthermore, we can arrange things so that trailing zero
+counts are unnecessary; i.e., commas can be omitted if all counts
+following them on the current line are zero.
+
+@<Compute the weight...@>=
+{@+register int *p,*q; /* pointers to $C_j$ and $w_j$ */
+ register long c; /* current count */
+ switch (gb_char()) {
+ case '*': wt=wt_vector[0];@+break; /* `common' word */
+ case '+': wt=wt_vector[1];@+break; /* `advanced' word */
+ case ' ': case'\n': wt=0;@+break; /* `unusual' word */
+ default: panic(syntax_error); /* unknown type of word */
+ }
+ p=&max_c[0]; q=&wt_vector[2];
+ do {
+ if (p==&max_c[7])
+ panic(syntax_error+1); /* too many counts */
+ c=gb_number(10);
+ if (c>*p++)
+ panic(syntax_error+2); /* count too large */
+ wt += c * *q++;
+ } while (gb_char()==',');
+}
+
+@* The output phase. Once the input phase has examined all of \.{words.dat},
+we are left with a stack of |nn| nodes containing the qualifying words, starting
+at |stack_ptr|.
+
+The next step is to call |gb_linksort|, which takes the qualifying words
+and distributes them into the 128 lists |gb_sorted[j]|, for |0<=j<128|.
+We can then access the words in order of decreasing weight by reading through
+these lists, starting with |gb_sorted[127]| and ending with |gb_sorted[0]|.
+(See the documention of |gb_linksort| in the |gb_sort| module.)
+
+The output phase therefore has the following general outline:
+
+@<Sort and output...@>=
+gb_linksort(stack_ptr);
+@<Allocate storage for the new graph; adjust |n| if it is zero or too large@>;
+if (gb_alloc_trouble==0 && n) {
+ register int j; /* runs through sorted lists */
+ register node *p; /* the current node being output */
+ nn=n;
+ for (j=127; j>=0; j--)
+ for (p=(node*)gb_sorted[j]; p; p=p->link) {
+ @<Add the word |p->wd| to the graph@>;
+ if (--nn==0) goto done;
+ }
+}
+done:gb_free(node_blocks);
+
+@ The only slightly unusual data structure needed is a set of five hash tables,
+one for each of the strings of four letters obtained by suppressing
+a single letter of a five-letter word. For example, a word like `\.{words}'
+will lead to entries for `\.{\ ords}', `\.{w\ rds}, `\.{wo\ ds}', `\.{wor\ s}',
+and `\.{word\ }', one in each of the hash tables.
+
+@d hash_prime 6997 /* a prime number larger than the total number of words */
+
+@<Type...@>=
+typedef Vertex *hash_table[hash_prime];
+
+@ @<Local...@>=
+Vertex *cur_vertex; /* the current vertex being created or examined */
+char *next_string; /* where we'll store the next five-letter word */
+
+@ @<Private v...@>=
+static hash_table *htab; /* five dynamically allocated hash tables */
+
+@ The weight of each word will be stored in the utility field |u.i| of its
+|Vertex| record. The position in which adjacent words differ will be
+stored in utility field |a.i| of the |Arc| records between them.
+
+@d weight u.i /* weighted frequencies */
+@d loc a.i /* index of difference (0, 1, 2, 3, or 4) */
+
+@(gb_words.h@>=
+#define weight @[u.i@] /* repeat the definitions in the header file */
+#define loc @[a.i@]
+
+@ @<Allocate storage for the new graph...@>=
+if (n==0 || nn<n)
+ n=nn;
+new_graph=gb_new_graph(n);
+if (new_graph==NULL)
+ panic(no_room); /* out of memory before we're even started */
+if (wt_vector==default_wt_vector)
+ sprintf(new_graph->id,"words(%u,0,%ld,%ld)",n,wt_threshold,seed);
+else sprintf(new_graph->id,
+ "words(%u,{%d,%d,%d,%d,%d,%d,%d,%d,%d},%ld,%ld)",
+ n,wt_vector[0],wt_vector[1],wt_vector[2],wt_vector[3],wt_vector[4],
+ wt_vector[5],wt_vector[6],wt_vector[7],wt_vector[8],wt_threshold,seed);
+strcpy(new_graph->format,"IZZZZZIZZZZZZZ");
+cur_vertex=new_graph->vertices;
+next_string=gb_alloc_type(6*n,@[char@],new_graph->data);
+htab=gb_alloc_type(5,@[hash_table@],new_graph->aux_data);
+
+@ @<Add the word...@>=
+{@+register char *q; /* the new word */
+ q=cur_vertex->name=next_string;
+ next_string+=6;
+ copy5(q,p->wd);
+ cur_vertex->weight=p->key-0x40000000;
+ @<Add edges for all previous words |r| that nearly match |q|@>;
+ cur_vertex++;
+}
+
+@ The length of each edge in a |words| graph is set to~1; the
+calling routine can change it later if desired.
+
+@d mtch(i) (*(q+i)==*(r+i))
+@d match(a,b,c,d) (mtch(a)&&mtch(b)&&mtch(c)&&mtch(d))
+@d store_loc_of_diff(k) cur_vertex->arcs->loc=(cur_vertex->arcs-1)->loc=k
+
+@<Add edges for all previous words |r| that nearly match |q|@>=
+{@+register char *r; /* previous word possibly adjacent to |q| */
+ register Vertex **h; /* hash address for linear probing */
+ register long raw_hash; /* five-letter hash code before remaindering */
+ raw_hash=(((((((*q<<5)+*(q+1))<<5)+*(q+2))<<5)+*(q+3))<<5)+*(q+4);
+ for (h=htab[0]+(raw_hash-(*q<<20)) % hash_prime;
+ *h; h==htab[0]? h=htab[1]-1: h--) {
+ r=(*h)->name;
+ if (match(1,2,3,4))
+ gb_new_edge(cur_vertex,*h,1), store_loc_of_diff(0);
+ }
+ *h=cur_vertex;
+ for (h=htab[1]+(raw_hash-(*(q+1)<<15)) % hash_prime;
+ *h; h==htab[1]? h=htab[2]-1: h--) {
+ r=(*h)->name;
+ if (match(0,2,3,4))
+ gb_new_edge(cur_vertex,*h,1), store_loc_of_diff(1);
+ }
+ *h=cur_vertex;
+ for (h=htab[2]+(raw_hash-(*(q+2)<<10)) % hash_prime;
+ *h; h==htab[2]? h=htab[3]-1: h--) {
+ r=(*h)->name;
+ if (match(0,1,3,4))
+ gb_new_edge(cur_vertex,*h,1), store_loc_of_diff(2);
+ }
+ *h=cur_vertex;
+ for (h=htab[3]+(raw_hash-(*(q+3)<<5)) % hash_prime;
+ *h; h==htab[3]? h=htab[4]-1: h--) {
+ r=(*h)->name;
+ if (match(0,1,2,4))
+ gb_new_edge(cur_vertex,*h,1), store_loc_of_diff(3);
+ }
+ *h=cur_vertex;
+ for (h=htab[4]+(raw_hash-*(q+4)) % hash_prime;
+ *h; h==htab[4]? h=htab[5]-1: h--) {
+ r=(*h)->name;
+ if (match(0,1,2,3))
+ gb_new_edge(cur_vertex,*h,1), store_loc_of_diff(4);
+ }
+ *h=cur_vertex;
+}
+
+@* Finding a word. After |words| has created a graph |g|, the user can
+remove the hash tables by calling the |gb_graph| subroutine
+|gb_free(g->aux_data)|. But if the hash tables have not been removed,
+another procedure can be used to find vertices that match or nearly
+match a given word.
+
+The subroutine call |find_word(q,f)| will return a pointer to a vertex
+that matches a given five-letter word~|q|, if that word is in the graph;
+otherwise, it returns |NULL| (i.e., \.{NULL}), after calling |f(v)| for
+each vertex~|v| whose word matches |q| in all but one letter position.
+
+@p Vertex *find_word(q,f)
+ char *q;
+ void (*f)(); /* |*f| should take one argument, of type |Vertex *| */
+{@+register char *r; /* previous word possibly adjacent to |q| */
+ register Vertex **h; /* hash address for linear probing */
+ register long raw_hash; /* five-letter hash code before remaindering */
+ raw_hash=(((((((*q<<5)+*(q+1))<<5)+*(q+2))<<5)+*(q+3))<<5)+*(q+4);
+ for (h=htab[0]+(raw_hash-(*q<<20)) % hash_prime;
+ *h; h==htab[0]? h=htab[1]-1: h--) {
+ r=(*h)->name;
+ if (mtch(0) && match(1,2,3,4))
+ return *h;
+ }
+ @<Invoke |f| on every vertex that is adjacent to word~|q|@>;
+ return NULL;
+}
+
+@ @<Invoke |f| on every vertex that is adjacent to word~|q|@>=
+for (h=htab[0]+(raw_hash-(*q<<20)) % hash_prime;
+ *h; h==htab[0]? h=htab[1]-1: h--) {
+ r=(*h)->name;
+ if (match(1,2,3,4))
+ (*f)(*h);
+}
+for (h=htab[1]+(raw_hash-(*(q+1)<<15)) % hash_prime;
+ *h; h==htab[1]? h=htab[2]-1: h--) {
+ r=(*h)->name;
+ if (match(0,2,3,4))
+ (*f)(*h);
+}
+for (h=htab[2]+(raw_hash-(*(q+2)<<10)) % hash_prime;
+ *h; h==htab[2]? h=htab[3]-1: h--) {
+ r=(*h)->name;
+ if (match(0,1,3,4))
+ (*f)(*h);
+}
+for (h=htab[3]+(raw_hash-(*(q+3)<<5)) % hash_prime;
+ *h; h==htab[3]? h=htab[4]-1: h--) {
+ r=(*h)->name;
+ if (match(0,1,2,4))
+ (*f)(*h);
+}
+for (h=htab[4]+(raw_hash-*(q+4)) % hash_prime;
+ *h; h==htab[4]? h=htab[5]-1: h--) {
+ r=(*h)->name;
+ if (match(0,1,2,3))
+ (*f)(*h);
+}
+
+@* Index. Here is a list that shows where the identifiers of this program are
+defined and used.
diff --git a/support/graphbase/girth.w b/support/graphbase/girth.w
new file mode 100644
index 0000000000..606a354413
--- /dev/null
+++ b/support/graphbase/girth.w
@@ -0,0 +1,308 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{GIRTH}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\let\==\equiv % congruence sign
+
+\prerequisite{GB\_\thinspace RAMAN}
+@* Introduction. This demonstration program uses graphs
+constructed by the |raman| procedure in the |gb_raman| module to produce
+an interactive program called \.{girth}, which computes the girth and
+diameter of a class of Ramanujan graphs.
+
+The girth of a graph is the length of its shortest cycle; the diameter
+is the maximum length of a shortest path between two vertices.
+A Ramanujan graph is a connected, undirected graph in which every vertex
+has degree~|p+1|, with the property that every eigenvalue of its adjacency
+matrix is either $\pm(p+1)$ or has absolute value $\le2\sqrt{\mathstrut p}$.
+
+Exact values for the girth are of interest because the bipartite graphs
+produced by |raman| apparently have larger girth than any other known
+family of regular graphs, even if we consider graphs whose existence
+is known only by non-constructive methods, except for the cubic ``sextet''
+graphs of Biggs, Hoare, and Weiss [{\sl Combinatorica\/ \bf3} (1983),
+153--165; {\bf4} (1984), 241--245].
+
+Exact values for the diameter are of interest because the diameter of
+any Ramanujan graph is at most twice the minimum possible diameter
+of any regular graph.
+
+The program will prompt you for two numbers, |p| and |q|. These should
+be distinct prime numbers, not too large, with |q>2|. A graph is
+constructed in which each vertex has degree~|p+1|. The number of
+vertices is $(q^3-q)/2$, if |p| is a quadratic residue modulo~|q|, or
+$q^3-q$ if |p| is not a quadratic residue. In the latter case the
+graph is bipartite and it is known to have rather large girth.
+
+If |p=2|, the value of |q| is further restricted to be of the form
+$104k+(1,3,9,17,25,27,35,43,49,51,75,81)$. This means that the only
+feasible values of |q| to go with |p=2| are probably 3, 17, and 43;
+the next case, |q=107|, would generate a bipartite graph with
+1,224,936 vertices and 3,675,808 arcs, thus requiring approximately
+113 megabytes of memory (not to mention a nontrivial amount of
+computer time). If you want to compute the girth and diameter
+of Ramanujan graphs for large |p| and/or~|q|, much better methods are
+available based on number theory; the present program is merely a
+demonstration of how to interface with the output of |raman|.
+Incidentally, the graph for |p=2| and |q=43| turns
+out to have 79464 vertices, girth 20, and diameter~22.
+
+The program will examine the graph, compute its girth and its diameter,
+then it will prompt you for another choice of |p| and |q|.
+
+The graphs we work with have the data type \&{Graph}, defined in |gb_graph|.
+
+@f Graph int
+@f Arc int
+@f Vertex int
+
+@ Here is the general layout of this program, as seen by the \Cee\ compiler:
+
+@p
+#include <math.h> /* the system |sqrt| routine is needed */
+#include "gb_graph.h" /* the standard GraphBase data structures */
+#include "gb_raman.h" /* Ramanujan graph generator */
+@#
+@<Global variables@>@;
+main()
+{
+ printf("This program explores the girth and diameter of Ramanujan graphs.\n");
+ printf("The bipartite graphs have q^3-q vertices, and the non-bipartite\n");
+ printf("graphs have half that number. Each vertex has degree p+1.\n");
+ printf("Both p and q should be odd prime numbers;\n");
+ printf(" or you can try p = 2 with q = 17 or 43.\n");
+ while (1) {
+ @<Prompt the user for |p| and |q|; |break| if unsuccessful@>;
+ g=raman(p,q,0,0);
+ if (g==NULL) @<Explain that the graph could not be constructed@>@;
+ else {
+ @<Print the theoretical bounds on girth and diameter of |g|@>;
+ @<Compute and print the true girth and diameter of |g|@>;
+ gb_recycle(g);
+ }
+ }
+}
+
+@ @<Global...@>=
+Graph *g; /* the current Ramanujan graph */
+int p; /* the branching factor (degree minus one) */
+int q; /* cube root of the graph size */
+char buffer[16]; /* place to collect what the user types */
+
+@ @d prompt(s)
+ {@+printf(s);@+fflush(stdout); /* make sure the user sees the prompt */
+ if (fgets(buffer,15,stdin)==NULL) break;@+}
+
+@<Prompt...@>=
+prompt("\nChoose a branching factor, p: ");
+if (sscanf(buffer,"%d",&p)!=1) break;
+prompt("OK, now choose the cube root of graph size, q: ");
+if (sscanf(buffer,"%d",&q)!=1) break;
+
+@ @<Explain that the graph could not be constructed@>=
+printf(" Sorry, I couldn't make that graph (%s).\n",
+ panic_code==very_bad_specs? "q is out of range":
+ panic_code==very_bad_specs+1? "p is out of range":
+ panic_code==bad_specs+5? "q is too big":
+ panic_code==bad_specs+6? "p is too big":
+ panic_code==bad_specs+1? "q isn't prime":
+ panic_code==bad_specs+7? "p isn't prime":
+ panic_code==bad_specs+3? "p is a multiple of q":
+ panic_code==bad_specs+2? "q isn't compatible with p=2":
+ "not enough memory");
+
+@* Bounds. The theory of Ramanujan graphs allows us to predict the
+girth and diameter to within a factor of 2~or~so.
+
+In the first place, we can easily derive an upper bound on the girth
+and a lower bound on the diameter, valid for any regular graph of
+degree~|p+1|. Such a graph has at most $(p+1)p^{k-1}$ points at
+distance~$k$ from any given vertex; this implies a lower bound
+on the diameter~$d$:
+$$1+(p+1)+(p+1)p+(p+1)p^2+\cdots+(p+1)p^{d-1}\;\ge\;n.$$
+Similarly, if the girth $g$ is odd, say $g=2k+1$, the points at
+distance~$\le k$ from any vertex must be distinct, so we have
+$$1+(p+1)+(p+1)p+(p+1)p^2+\cdots+(p+1)p^{k-1}\;\le\;n;$$
+and if $g=2k+2$, at least $p^k$ further points must exist at distance
+$k+1$, because the $(p+1)p^k$ paths of length $k+1$ can end at
+a particular vertex at most $p+1$ times. Thus
+$$1+(p+1)+(p+1)p+(p+1)p^2+\cdots+(p+1)p^{k-1}+p^k\;\le\;n$$
+when the girth is even.
+
+In the following code we let $|pp|=p^{dl}$ and
+$s=1+(p+1)+\cdots+(p+1)p^{dl}$.
+
+@<Compute the ``trivial'' bounds |gu| and |dl| on girth and diameter@>=
+s=p+2;@+dl=1;@+pp=p;@+gu=3;
+while (s<n) {
+ s+=pp;
+ if (s<=n) gu++;
+ dl++;
+ pp*=p;
+ s+=pp;
+ if (s<=n) gu++;
+}
+
+@ When |p>2|, we can use the theory of integral quaternions to derive a lower
+bound on the girth of the graphs produced by |raman|. A path of length~$g$
+from a vertex to itself exists if and only if there is an integral
+quaternion $\alpha=a_0+a_1i+a_2j+a_3k$ of norm $p_g$ such that
+the $a$'s are not all multiples of~$p$, while
+$a_1$, $a_2$, and $a_3$ are multiples of~$q$ and $a_0\not\=a_1\=a_2\=a_3$
+(mod~2). This means we have integers $(a_0,a_1,a_2,a_3)$ with
+$$a_0^2+a_1^2+a_2^2+a_3^2=p^g,$$ satisfying the stated properties
+mod~$q$ and mod~2.
+If $a_1$, $a_2$, and $a_3$ are even, they cannot all be zero so
+we must have $p^g\ge1+4q^2$; if they are odd, we must have
+$p^g\ge4+3q^2$. (The latter is possible only when $g$ is odd and
+$p\bmod4=3$.) Since $n$ is roughly proportional to~$q^3$, this means
+$g$ must be at least about ${2\over3}\log_p n$. Thus, $g$
+isn't too much less than the maximum girth possible in any regular graph,
+which we have shown is at most about $2\log_p n$.
+
+When the graph is bipartite we can, in fact, prove that $g$ is
+approximately ${4\over3}\log_p n$. The bipartite case occurs if and
+only if $p$ is not a quadratic residue modulo~|q|; hence the
+number~$g$ in the previous paragraph must be even, say $g=2r$. Then
+$p^g\bmod4=1$, and $a_0$ must be odd. The congruence $a_0^2\=p^{2r}$
+(mod~$q^2$) implies that $a_0\=\pm p^r$, because all numbers
+relatively prime to $q^2$ are powers of a primitive root. We can
+assume without loss of generality that $a_0=p^r-2mq^2$, where
+$0<m<p^r/q^2$; it follows in particular that $p^r>q^2$. Conversely,
+if $p^r-q^2$ can be written as a sum of three squares
+$b_1^2+b_2^2+b_3^2$, then
+$p^{2r}=(p^r-2q^2)^2+(2b_1q)^2+(2b_2q)^2+(2b_3q)^2$ is a
+representation of the required type. If $p^r-q^2$ is a positive
+integer that cannot be represented as a sum of three squares, a
+well-known theorem of Legendre tells us that $p^r-q^2=4^ts$, where
+$s\=7$ (mod~8). Since $p$ and $q$ are odd, we have $t\ge1$; hence
+$p^r-2q^2$ is odd. If $p^r-2q^2$ is a positive odd integer, Legendre's
+theorem tells us that we can write $2p^r-4q^2=b_1^2+b_2^2+b_3^2$;
+hence $p^{2r}=(p^r-4q^2)^2+ (2b_1q)^2+(2b_2q)^2+(2b_3q)^2$. We
+conclude that the girth is either $2\lceil\log_pq^2\rceil$ or
+$2\lceil\log_p2q^2\rceil$. (This explicit calculation, which makes our
+program for calculating the girth unnecessary or at best redundant in
+the bipartite case, is due to G. A. Margulis and, independently, to
+Biggs and Boshier [{\sl Journal of Combinatorial Theory\/ \bf B49}
+(1990), 190--194].)
+
+A girth of 1 or 2 can occur, since these graphs might have self-loops
+or multiple edges if |p| is sufficiently large.
+
+@<Compute a lower bound |gl| on the girth@>=
+if (bipartite) {@+long b=q*q;
+ for (gl=1,pp=p;pp<=b;gl++,pp*=p) ; /* iterate until $p^g>q^2$ */
+ gl+=gl;
+} else {@+long b1=1+4*q*2, b2=4+3*q*q; /* bounds on $p^g$ */
+ for (gl=1,pp=p;pp<b1;gl++,pp*=p) {
+ if (pp>=b2 && (gl&1) && (p&2)) break;
+ }
+}
+
+@ Upper bounds on the diameter of any Ramanujan graph can be derived
+as shown in the paper by Lubotzky, Phillips, and Sarnak in
+{\sl Combinatorica \bf8} (1988), page~275. (However, a slight correction
+to their proof is necessary---their parameter~$l$ should be~odd
+when $x$ and~$y$ lie in different parts of a bipartite graph.)
+Their argument demonstrates that $p^{(d-1)/2}<2n$ in the
+nonbipartite case and $p^{(d-2)/2}<n$ in the bipartite case; therefore
+we obtain the upper bound $d\le 2\log n+O(1)$, which is about twice the lower
+bound that holds in an arbitrary regular graph.
+
+@<Compute an upper bound |du| on the diameter@>=
+{@+long nn=(bipartite? n: 2*n);
+ double nnp=((double)nn)/sqrt((double)p);
+ long nnn=(long)nnp;
+ if ((double)nnn>nnp) nnn--; /* truncate, don't round */
+ for (du=0,pp=1;pp<=nnn;du+=2,pp*=p) ;
+ if (pp<nn) du++;
+ if (bipartite) du++;
+}
+
+@ @<Print the theoretical bounds on girth and diameter of |g|@>=
+n=g->n;
+if (n==(q+1)*q*(q-1)) bipartite=1;
+else bipartite=0;
+printf("The graph has %d vertices, each of degree %d, and it is %sbipartite.\n",
+ n,p+1,bipartite? "": "not ");
+@<Compute the ``trivial'' bounds |gu| and |dl| on girth and diameter@>;
+printf("Any such graph must have diameter >= %d and girth <= %d;\n",
+ dl,gu);
+@<Compute an upper bound |du| on the diameter@>;
+printf("theoretical considerations tell us that this one's diameter is <= %d",
+ du);
+if (p==2) printf(".\n");
+else {
+ @<Compute a lower bound |gl| on the girth@>;
+ printf(",\nand its girth is >= %d.\n",gl);
+}
+
+@ We had better declare all the variables we've been using so freely.
+
+@<Global...@>=
+int gl,gu,dl,du; /* theoretical bounds */
+long pp; /* power of $p$ */
+long s; /* accumulated sum */
+long n; /* number of vertices */
+char bipartite; /* is the graph bipartite? */
+
+@*Breadth-first search. The graphs produced by |raman| are symmetrical, in
+the sense that there is an automorphism taking any vertex into any
+other; each vertex $V$ and each edge $P$ corresponds to a $2\times2$
+matrix, and the path $P_1P_2\ldots P_k$ leading from vertex~$V$ to
+vertex $VP_1P_2\ldots P_k$ has the same properties as the path leading
+from vertex~$U$ to vertex $UP_1P_2\ldots P_k$. Therefore we can find
+the girth and the diameter by starting at any vertex $v_0$.
+
+We will compute the number of points at distance $k$ from $v_0$ for
+all $k$, by explicitly forming a linked list of all such points.
+Utility field |link| will be used for the links. The lists will
+terminate with a non-null |sentinel| value, so that we can also
+use the condition |link==NULL| to tell if a vertex has been
+encountered before. Another utility field, |dist|, will contain the
+distance from the starting point; and |back| will point to a
+vertex one step closer.
+
+@d link w.v /* the field where we store links, initially |NULL| */
+@d dist v.i /* the field where we store distances, initially 0 */
+@d back u.v /* the field where we store backpointers, initially |NULL| */
+
+@<Compute and print the true girth and diameter of |g|@>=
+printf("Starting at any given vertex, there are\n");
+{@+int k; /* current distance being generated */
+ int c; /* how many we've seen so far at this distance */
+ register Vertex *v; /* current vertex in list at distance $k-1$ */
+ register Vertex *u; /* head of list for distance $k$ */
+ Vertex *sentinel=g->vertices+n; /* nonzero link at end of lists */
+ int girth=999; /* length of smallest cycle found, initially infinite */
+ k=0;
+ u=g->vertices;
+ u->link=sentinel;
+ c=1;
+ while (c) {
+ for (v=u,u=sentinel,c=0,k++;v!=sentinel;v=v->link)
+ @<Place all vertices adjacent to |v| onto list |u|, unless they've
+ been encountered before, increasing |c| whenever the list grows@>;
+ printf("%8d vertices at distance %d%s\n", c, k, c>0? ",": ".");
+ }
+ printf("So the diameter is %d, and the girth is %d.\n",k-1,girth);
+}
+
+@ @<Place all...@>=
+{@+register Arc *a;
+ for (a=v->arcs;a;a=a->next) {@+register Vertex *w;
+ /* vertex adjacent to |v| */
+ w=a->tip;
+ if (w->link==NULL) {
+ w->link=u;
+ w->dist=k;
+ w->back=v;
+ u=w;
+ c++;
+ } else if (w->dist+k<girth && w!=v->back)
+ girth=w->dist+k;
+ }
+}
+
+@* Index. Finally, here's a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/homer.dat b/support/graphbase/homer.dat
new file mode 100644
index 0000000000..8d58699461
--- /dev/null
+++ b/support/graphbase/homer.dat
@@ -0,0 +1,675 @@
+* File "homer.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* $\rm I\Lambda IA\Delta O\Sigma$, by Homer
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 670,795252274)
+AA Aethra, Trojan lady in waiting
+AB Abarbarea, Trojan fountain nymph
+AC Achilles, angry warrior, swift-footed chief of Myrmidons from Phthia
+AD Automedon, charioteer of AC
+AE Aeneas, leader of Dardanians
+AF Aphrodite (Venus), daughter of ZE and DN, roots for Trojans
+AG Agamemnon, king of Argos and Mycenae, leader of Greek forces
+AH Andromache, wife of HT
+AI Anchises, father of AE
+AJ Great Ajax, king of Salamis
+AL Antilochus, son of NE
+AM Artemis (Cynthia/Diana), daughter of ZE and LE, roots for Trojans
+AN Antenor, aged councilor to PR
+AO Agenor, heir of AN, assists AE
+AP Apollo, son of ZE and LE, roots for Trojans
+AR Ares (Mars), son of ZE, roots for Trojans
+AS Atreus, high king, father of AG and ME
+AT Athene (Minerva), daughter of ZE, favors Greeks
+AU Augeias, king in Elis, stables cleaned by HR
+AX Little Ajax, king of Locris, handiest with a spear
+AZ Aegaeon, hundred-armed giant, brother of CR
+BL Bellerophon, king of Lycia after killing CM, 2F, 2G
+BO Boreas, the north wind
+BR Briseis, prize in AC harem
+CA Calchas, wise prophet
+CH Chryses, priest of AP
+CI Charis, wife of HP
+CL Clymene, Trojan lady in waiting, cow-eyed
+CM Chimera, monster with head of lioness and tail of snake
+CN Chiron, centaur, instructor of 97 and AC
+CR Cronus (Saturn), father of HD, PO, ZE
+CS Chryseis, daughter of CH
+CT Castor, brother of HL, tamer of horses
+DE Death, twin brother of SL
+DI Diomedes, king of middle Argos, Tiryns, and Aegina
+DM Demeter (Ceres), goddess with beautiful hair, mother of PP
+DN Dione, consort of ZE
+DP Deiphobus, son of PR and HC
+DT Dionysus (Bacchus), god of wine
+EA Euryalus, lieutenant of DI
+EB Eurybates, herald of AG
+EE Eeriboea, stepmother of EF and OT
+EF Ephialtes, giant, brother of OT
+EM Eurymedon, Greek charioteer
+EN Enyo (Bellona), goddess of war
+EO Eos (Aurora), rosy-fingered and saffron-robed goddess of dawn
+EP Eurypylus, leader of forty ships from Thessaly
+ER Erinnyes (Furies), goddesses of vengeance
+EU Eurus, the east wind
+FD False Dream, messenger of ZE
+FY Phylus, son of AU, horseman favored by ZE
+GL Glaucus, comrade and squire of SA, grandson of BL
+GR Graces, handmaidens of AF
+GS Greek soldiers, collectively
+HA Hours (Horae), goddesses of the seasons
+HB Hebe, daughter of ZE and HE, goddess of youth
+HC Hecuba, wife of PR, queen of Troy
+HD Hades (Pluto), king of the underworld
+HE Hera (Juno), wife of ZE, favors Greeks
+HL Helen, wife of ME, brought to Troy by PS
+HM Hermes (Mercury), son of ZE, slightly favors the Greeks
+HN Helenus, son of PR, soothsayer
+HO Homer, the poet
+HP Hephaestus (Vulcan), crippled son of ZE and HE, favors Greeks
+HR Heracles (Hercules), heroic strong man
+HT Hector, eldest son of PR and HC, brilliant commander of Trojan army
+IA Idaeus, Trojan herald
+ID Idomeneus, king of Crete
+IR Iris, golden-winged Olympian messenger
+LA Laodice, loveliest daughter of PR and HC
+LE Leto (Latona), mother of AM and AP
+LT Leitus, leader of Boeotians
+LY Lycaon, brother of PS
+MC Ate, goddess of mischief, eldest daughter of ZE
+ME Menelaus, brother of AG, king of Sparta
+MG Meges, son of FY, flotilla leader from western islands
+MO Moira, personification of Fate
+MR Meriones, comrade and squire of ID
+MT Menestheus, Athenian leader, renowned chariot-fighter
+MU Muses, nine sisters who like to sing
+NE Nestor, venerable king of Pylus and Dorium
+NI Night, goddess of nighttime
+NO Notus, the south wind
+NR Nereids, sisters of TH
+OC Oceanus, father of all streams
+OD Odysseus (Ulysses), crafty king of Ithaca
+OG Olympian gods, collectively
+OT Otus, giant, brother of EF
+PA Patroclus, righthand man of AC
+PB Peneleos, leader of Boeotians
+PC Pelops, charioteer god
+PD Polydamus, Trojan prince, son of 0N
+PE Peleus, father of AC
+PH Podarge, a harpy (snatcher)
+PL Polites, son of PR
+PN Pandarus, son of LY, archer who breaks truce
+PO Poseidon (Neptune), king of the sea, favors Greeks
+PP Persephone (Proserpina), wife of HD, queen of nether world
+PR Priam, king of Troy, son of 1K
+PS Paris (Alexander), son of PR and friend of AF
+PT Prothoenor, Boeotian chief
+PU Polydeuces (Pollux), twin brother of CT, boxer
+PX Phoenix, king of Dolopians, tutor and foster father of AC
+RA Axius, god of river in Macedonia
+RH Rhea, consort of CR, mother of ZE, HE, PO, HD
+RO Robots, golden handmaidens fabricated by HP
+RU Rumor, goddess and servant of ZE
+SA Sarpedon, son of ZE and 2E, leader of the Lycians
+SE Semele, mother of DT
+SF Strife, twin of AR
+SI Simoeis, river god, tributary of XA
+SL Sleep, twin brother of DE
+SP Spercheius, tireless river god
+ST Sthenelus, lieutenant of DI
+TA Talthybius, herald of AG
+TE Telamon, father of AJ and TU
+TH Thetis, sea nymph, mother of AC
+TI Themis, fair-cheeked goddess of law
+TL Tlepolemus, son of HR and 9J, king of Rhodes
+TM Thrasymedes, son of NE
+TR Thersites, ugliest man in Greek army
+TS Trojan soldiers, collectively
+TT Tethys, wife of OC
+TU Teucer, half brother of AJ
+TY Thyestes, sheep breeder, brother of AS
+WI Aeolus, lord of winds
+XA Xanthus, son of ZE, god of the river Scamander
+XB Xanthus and Balius, AC's divine horses, sired by ZF
+ZE Zeus (Jove/Jupiter), king of the gods
+ZF Zephyr, the west wind
+01 Archelochus, son of AN, lieutenant of AE
+02 Acamas, son of AN, lieutenant of AE
+03 Adrestus, son of 05, co-leader of Adresteians
+04 Amphius, son of 05, co-leader of Adresteians
+05 Merops, king of Percote, soothsayer
+06 Asius, leader of Hellespontian forces
+07 Hippothous, twin brother of 08, co-leader of Pelasgians
+08 Pylaeus, twin brother of 07, co-leader of Pelasgians
+09 Peirous, chief of Thracians, killed by 9K
+0A Euphemus, leader of Ciconian spearmen
+0B Pyraechmes, leader of Paeonian archers
+0C Pylaemenes, leader of Paphlagonian forces
+0D Odius, co-leader of Halizonian forces
+0E Epistrophus, co-leader of Halizonian forces
+0F Chromius, co-leader of Mysian forces
+0G Ennomus, augur and co-leader of Mysian forces
+0H Phorcys, co-leader of Phrygian forces
+0I Ascanius, godlike co-leader of Phrygian forces
+0J Mesthles, brother of 0K, co-leader of Maeonian forces
+0K Antiphus, brother of 0J, co-leader of Maeonian forces
+0L Nastes, brother of 0M, co-leader of Carian forces
+0M Amphimachus, vain brother of 0L, co-leader of Carians
+0N Panthous, Trojan elder, formerly priest at Delphi
+0O Thymoetes, Trojan elder
+0P Lampus, brother of PR
+0Q Clytius, brother of PR
+0R Hicetaon, brother of PR
+0S Ucalegon, Trojan elder
+0T Otreus, king of Phrygia
+0U Mygdon, king of Phrygia
+0V Echepolus, killed by AL
+0W Simoeisius, killed by AJ
+0X Democoon, bastard son of PR, killed by OD
+0Y Phegeus, son of 10, killed by DI
+0Z Idaeus, brother of 0Y, saved by HP
+10 Dares, noble priest of HP in Troy
+11 Phaestus, son of Maeonian nobleman, speared by ID
+12 Scamandrius, Trojan archer trained by AM, speared by ME
+13 Phereclus, Trojan shipbuilder, killed by MR
+14 Theano, wife of AN, priestess of AT
+15 Pedaeus, son of AN but not 14, killed by MG
+16 Hypsenor, son of Trojan priest, killed by EP
+17 Astynous, Trojan killed by DI
+18 Hypeiron, Trojan killed by DI
+19 Abas, brother of 1A, killed by DI
+1A Polyeidus, son of Trojan soothsayer, killed by DI
+1B Xanthus, brother of 1C, killed by DI
+1C Thoon, brother of 1B, killed by DI
+1D Echemmon, son of PR, killed by DI
+1E Chromius, son of PR, killed by DI
+1F Tros, ancient king of Troy
+1G Ganymede, son of 1F, made cupbearer to OG by ZE
+1H Deicoon, friend of AE, killed by AG
+1I Mydon, 0C's driver, killed by AL
+1J Amphius, fighter from Paesus, killed by AJ
+1K Laomedon, king of Troy, father of PR, killed by HR
+1L Hesione, daughter of 1K, rescued by HR
+1M Coeranus, Lycian speared by OD
+1N Alastor, Lycian speared by OD
+1O Chromius, Lycian speared by OD
+1P Alcandrus, Lycian speared by OD
+1Q Halius, Lycian speared by OD
+1R Noemon, Lycian speared by OD
+1S Prytanis, Lycian speared by OD
+1T Pelagon, attendant of SA
+1U Acamas, Thracian commander, killed by AJ
+1V Axylus, popular nobleman in suburban Troy, killed by DI
+1W Calysius, charioteer of 1V, killed by DI
+1X Dresus, Trojan killed by EA
+1Y Opheltius, Trojan killed by EA
+1Z Aesepus, son of 21 and AB, killed by EA
+20 Pedasus, twin brother of 1Z, killed by EA
+21 Bucolion, illegitimate eldest son of 1K
+22 Astyalus, Trojan killed by 94
+23 Pidytes, warrior from Percote, killed by OD
+24 Aretaon, Trojan soldier killed by TU
+25 Ablerus, Trojan soldier killed by AL
+26 Elatus, soldier from Pedasus, killed by AG
+27 Phylacus, Trojan soldier killed by LT
+28 Melanthius, Trojan soldier killed by EP
+29 Anteia, wife of 82
+2A Iobates, ancient king of Lycia, father of 29 and 2B
+2B Philonoe, wife of BL
+2C Isander, son of BL and 2B
+2D Hippolochus, son of BL and 2B, father of GL
+2E Laodameia, daughter of BL and 2B
+2F Solymi, Lycian tribe
+2G Amazons, warlike community of women
+2H Trojan noblewomen, assembled by HC
+2I Eetion, king of Cilicia, father of AH
+2J Scamandrius, infant son of HT and AH, nicknamed Astyanax
+2K Eniopeus, HT's charioteer, killed by DI
+2L Archeptolemus, 2K's replacement
+2M Agelaus, Trojan warrior killed by DI
+2N Orsilochus, Trojan warrior shot by TU
+2O Ormenus, Trojan warrior shot by TU
+2P Ophelestes, Trojan warrior shot by TU
+2Q Daetor, Trojan warrior shot by TU
+2R Chromius, Trojan warrior shot by TU
+2S Lycophontes, Trojan warrior shot by TU
+2T Amopaon, Trojan warrior shot by TU
+2U Melanippus, Trojan warrior shot by TU
+2V Gorgythion, son of PR, shot by TU
+2W Cebriones, half-brother of HT, 2L's replacement
+2X Dolon, rich, swift-footed, ugly Trojan
+2Y Rhesus, Thracian king, murdured in sleep by DI
+2Z Hippocoon, cousin of 2Y
+30 Mestor, deceased son of PR
+31 Polybus, son of AN
+32 Bienor, Trojan commander killed by AG
+33 Oileus, charioteer of 32, killed by AG
+34 Antiphus, son of PR, killed by AG
+35 Isus, illegitimate son of PR, killed by AG
+36 Antimachus, Trojan councillor
+37 Peisander, son of 36, killed by AG
+38 Hippolochus, son of 36, killed by AG
+39 Iphidamus, son of AN and 14, killed by AG
+3A Cisses, father of 14, guardian of 39
+3B Coon, eldest son of AN, killed by AG after wounding him
+3C Thymbraeus, Trojan warrior killed by DI
+3D Molion, charioteer of 3C, killed by OD
+3E Hippodamus, Trojan warrior killed by OD
+3F Hypeirochus, Trojan warrior killed by OD
+3G Agastrophus, Trojan warrior killed by DI
+3H Deiopites, Trojan warrior killed by OD
+3I Thoon, Trojan warrior killed by OD
+3J Ennomus, Trojan warrior killed by OD
+3K Chersidamas, Trojan warrior killed by OD
+3L Charops, Trojan warrior, brother of 3M, killed by OD
+3M Socus, wealthy Trojan warrior, killed by OD
+3N Doryclus, illegitmate son of PR, killed by AJ
+3O Pandocus, Trojan warrior killed by AJ
+3P Lysander, Trojan warrior killed by AJ
+3Q Pyrasus, Trojan warrior killed by AJ
+3R Pylartes, Trojan warrior killed by AJ
+3S Apisaon, Trojan warrior killed by EP
+3T Alcathous, brother-in-law of AE, killed by ID
+3U Troilus, deceased son of PR
+3V Asteropaeus, leader of the Paeonians
+3W Adamas, son of 06, killed by MR
+3X Iamenus, fighter with 06
+3Y Orestes, fighter with 06, killed by 93
+3Z Thoon, fighter with 06, killed by AL
+40 Oenomaus, fighter with 06
+41 Damasus, Trojan warrior killed by 94
+42 Pylon, Trojan warrior killed by 94
+43 Ormenus, Trojan warrior killed by 94
+44 Antiphates, Trojan warrior killed by 93
+45 Menon, Trojan warrior killed by 93
+46 Iamenus, Trojan warrior killed by 93
+47 Epicles, comrade of SA, killed by AJ
+48 Imbrius, husband of 49, killed by TU
+49 Medesicaste, illegitimate daughter of PR
+4A Cassandra, prophetess, daughter of PR
+4B Othryoneus, suitor of 4A, killed by ID
+4C Hippodameia, talented eldest daughter of AI
+4F Peisander, Trojan warrior killed by ME
+4G Harpalion, son of 0C, killed by MR
+4H Phalces, Trojan warrior, killed by AL
+4I Orthaeus, Trojan warrior
+4J Polyphetes, Trojan warrior
+4K Palmys, Trojan warrior
+4L Ascanius, Trojan warrior
+4M Morys, Trojan warrior killed by MR
+4N Satnius, Trojan warrior killed by AX
+4O Ilioneus, Trojan warrior killed by PB
+4P Hyrtius, Trojan warrior killed by AJ
+4Q Mermerus, Trojan warrior killed by AL
+4R Hippotion, Trojan warrior killed by MR
+4S Prothoon, Trojan warrior killed by TU
+4T Periphetes, Trojan warrior killed by TU
+4U Hyperenor, son of 0N, Trojan warrior killed by ME
+4V Caletor, son of 0Q, killed by AJ
+4W Cleitus, Trojan warrior killed by TU
+4X Astynous, charioteer for PD
+4Y Laodamas, Trojan warrior killed by AJ
+4Z Croesmus, Trojan warrior killed by MG
+A0 Dolops, son of 0P, killed by ME
+B0 Melanippus, neighber of PR, killed by AL
+C0 Areilycus, Trojan warrior killed by PA
+D0 Thoas, Trojan warrior killed by ME
+E0 Amphiclus, Trojan warrior killed by MG
+F0 Atymnius, friend of SA, Trojan warrior killed by AL
+G0 Maris, friend of SA, Trojan warrior killed by TM
+H0 Amisodarus, father of F0 and G0
+I0 Cleobolus, Trojan warrior killed by AX
+J0 Lycon, Trojan warrior killed by PB
+K0 Erymas, Trojan warrior killed by ID
+L0 Pronous, Trojan warrior killed by PA
+M0 Thestor, Trojan warrior killed by PA
+N0 Euryalus, Trojan warrior killed by PA
+O0 Erymas, Trojan warrior killed by PA
+P0 Amphoterus, Trojan warrior killed by PA
+Q0 Epaltes, Trojan warrior killed by PA
+R0 Tlepolemus, Trojan warrior killed by PA
+S0 Echius, Trojan warrior killed by PA
+T0 Pyris, Trojan warrior killed by PA
+U0 Ipheus, Trojan warrior killed by PA
+V0 Evippus, Trojan warrior killed by PA
+W0 Polymelus, Trojan warrior killed by PA
+X0 Thrasymelus, charioteer of SA, killed by PA
+Y0 Sthenelaus, Trojan warrior killed by PA
+Z0 Laogonus, Trojan warrior killed by MR
+A1 Adrestus, Trojan warrior killed by PA
+B1 Autonous, Trojan warrior killed by PA
+C1 Echeclus, Trojan warrior killed by PA
+D1 Perimus, Trojan warrior killed by PA
+E1 Epistor, Trojan warrior killed by PA
+F1 Melanippus, Trojan warrior killed by PA
+G1 Elasus, Trojan warrior killed by PA
+H1 Mulius, Trojan warrior killed by PA
+I1 Pylartes, Trojan warrior killed by PA
+J1 Euphorbus, son of 0N, killed by ME after wounding PA
+K1 Medon, Trojan leader
+L1 Thersilochus, Trojan leader
+M1 Deisenor, Trojan leader
+N1 Apisaon, Trojan warrior killed by 7R
+O1 Aretus, son of PR, killed by AD
+P1 Podes, son of 2I, killed by ME
+Q1 Ilus, son of 1F, ancient king of Troy
+R1 Assaracus, son of 1F, grandfather of AE
+S1 Erichtonius, richest man alive, father of 1F
+T1 Iphition, Trojan warrior killed by AC
+U1 Demoleon, son of AN, killed by AC
+V1 Hippodamus, driver of U1, killed by AC
+W1 Polydorus, youngest and favorite son of PR, killed by AC
+X1 Dryops, Trojan warrior killed by AC
+Y1 Demuchus, Trojan warrior killed by AC
+Z1 Loagonus, Trojan warrior killed by AC
+A2 Dardanus, brother of Z1, killed by AC
+B2 Tros, son of 1N, Trojan warrior killed by AC
+C2 Mulius, Trojan warrior killed by AC
+D2 Echeclus, son of AO, Trojan warrior killed by AC
+E2 Deucalion, Trojan warrior killed by AC
+F2 Rhigmus, Trojan warrior killed by AC
+G2 Areithous, driver of F2, killed by AC
+H2 Eetion, guest-friend of PR
+I2 Laothoe, concubine of PR
+J2 Pelegon, father of 3V, son of RA and K2
+K2 Periboea, mother of J2
+L2 Thersilochus, charioteer from Paeonia killed by AC
+M2 Mydon, charioteer from Paeonia killed by AC
+N2 Astypylus, charioteer from Paeonia killed by AC
+O2 Mnesus, charioteer from Paeonia killed by AC
+P2 Thrasius, charioteer from Paeonia killed by AC
+Q2 Aenius, charioteer from Paeonia killed by AC
+R2 Ophelestes, charioteer from Paeonia killed by AC
+S2 Altes, king of the Leleges, father of I2
+T2 Agathon, son of PR
+U2 Pammon, son of PR
+V2 Antiphonus, son of PR
+W2 Hippothous, son of PR
+X2 Dius, arrogant son of PR
+51 Melas, brother of 82
+52 Agrius, brother of 82
+53 Niobe, queen of Thebes
+54 Oedipus, king of Thebes
+55 Mecisteus, father of EA
+56 Epeius, huge Greek warrior, champion boxer
+57 Actor, brother of AU
+58 Laodocus, comrade of AL
+59 Coeranus, charioteer of MR, killed by HT
+5A Moliones, twin brothers, purported sons of 57
+5B Leiocritus, Greek warrior killed by AE
+5C Bathycles, wealthy Myrmidon, killed by GL
+5D Epeigeus, Myrmidon leader killed by HT
+5E Alcimedon, Myrmidon leader
+5F Peisander, Myrmidon leader
+5G Eileithyia, daughter of HE, goddess of childbirth
+5H Phylas, father of 5J
+5I Echecles, married 5J after 5K was born
+5J Polymele, singer and dancer
+5K Eudorus, Myrmidon leader, son of HM and 5J
+5L Borus, putative father of 5O
+5M Polydorus, javelin-thrower once beaten by NE
+5N Polydora, sister of AC
+5O Menestheus, Myrmidon leader, son of 5N and SP
+5P Periphetes, son of 5Q
+5Q Copreus, herald of 7U
+5R Otus, comrade of MG, killed by PD
+5S Schedius, Greek warrior killed by HT
+5T Lycophron, squire of AJ, killed by HT
+5U Deiochus, Greek warrior killed by PS
+5V Iasus, Athenian leader killed by AE
+5W Archesilaus, friend of MT, killed by HT
+5X Phyleus, javelin-thrower once beaten by NE
+5Y Iphiclus, runner once beaten by NE
+5Z Promachus, Greek warrior killed by 02
+60 Areilycus, Greek warrior killed by PD
+61 Ancaeus, wrestler once beaten by NE
+62 Alcmene, mother of HR
+63 Clytomedes, boxer once beaten by NE
+64 Europa, mother of 65 and 66
+65 Rhadamanthus, brother of 66
+66 Minos, ancient king of Crete
+67 Perseus, Greek hero
+68 Danae, mother of 67, had beautiful ankles
+69 Dia, mother of 6A
+6A Peirithous, son of ZE and 69, king of the Lapiths
+6B Noemon, comrade of AL
+6C Echepolus, subject of AG who avoids the war
+6D Hypsipyle, wife of Jason
+6E Janos, leader of the Argonauts
+6F Deipyle, mother of DI
+6G Dracius, lieutenant of MG
+6H Amphion, lieutenant of MG
+6I Bias, lieutenant of MT
+6J Pheidas, lieutenant of MT
+6K Polyidus, seer from Corinth
+6L Euchenor, son of 6K, killed by PS
+6M Mecisteus, companion of AL, killed by PD
+6N Hypsenor, Greek warrior slain by DP
+6O Stichius, lieutenant of MT, killed by HT
+6P Alcmaon, Greek warrior killed by SA
+6Q Pandion, bow-bearer of TU
+6R Thootes, Greek herald
+6S Menoetius, father of PA
+6T Moliones, twin sons of PO
+6U Mulius, husband of 6V, killed by NE
+6V Agamede, eldest daughter of AU
+6W Neleus, king of Pylos, father of NE
+6X Itymoneus, Elean cattleman killed by NE
+6Y Hecamede, female slave presented by AC to NE
+6Z Hipponous, Greek warrior killed by HT
+70 Orus, Greek warrior killed by HT
+71 Aesymnus, Greek warrior killed by HT
+72 Agelaus, Greek warrior killed by HT
+73 Opheltius, Greek warrior killed by HT
+74 Dolops, Greek warrior killed by HT
+75 Opites, Greek warrior killed by HT
+76 Autonous, Greek warrior killed by HT
+77 Asaeus, Greek warrior killed by HT
+78 Cinyras, king of Cyprus
+79 Tithonus, son of 1K, mortal consort of EO
+7A Molus, father of MR
+7B Amphidamas, Argonaut from Cythera
+7C Autolycus, sly grandfather of OD
+7D Iphis, slave girl captured by Achilles on Scyros
+7E Diomede, slave girl captured by Achilles on Lesbos
+7F Marpessa, had beautiful ankles
+7G Idas, strongest man of his day
+7H Cleopatra, wife of 7J, daughter of 7G and 7F
+7I Althea, wife of 82, curses 7J
+7J Meleager, son of 82 and 7I
+7K Clytia, beautiful slave girl of 7L
+7L Amyntor, father of PX
+7M Odius, Greek herald
+7N Iphianassa, daughter of AG
+7O Laodice, daughter of AG
+7P Chrysothemis, daughter of AG
+7Q Orestes, son of AG, student deferred from draft
+7R Lycomedes, Greek captain of 100 spearmen
+7S Deipyrus, Greek captain of 100 spearmen, killed by HN
+7T Aphareus, Greek captain of 100 spearmen, killed by AE
+7U Eurystheus, king of Mycenae, made HR labor
+7V Echius, father of 6M
+7W Ereuthalion, favorite squire of 7X
+7X Lycurgus, Arcadian warrior, killer of 7Y
+7Y Areithous, king of Arne in Thrace
+7Z Iphinous, Greek warrior slain by GL
+80 Eioneus, Greek from Magnesia, slain by HT
+81 Menesthius, son of 7Y, killed by PS
+82 Oeneus, king of Calydon
+83 Proetus, king of Tiryns, overlord of BL
+84 Glaucus, son of 85, father of BL
+85 Sisyphus, crafty son of WI
+86 Clysonomus, boy killed in quarrel by young PA
+87 Lycurgus, king of the Edonians
+88 Periphas, huge fighter, bravest of the Aetolians
+89 Oresbius, Boeotian landowner, slain by HT
+8A Helenus, Greek fighter, slain by HT
+8B Trechus, Aetolian fighter, slain by HT
+8C Orestes, Greek charioteer, slain by HT
+8D Teuthras, Greek from Magnesia, slain by HT
+8E Anchialus, veteran Greek fighter slain by HT
+8F Menesthes, veteran Greek fighter dispatched by HT
+8G Orsilochus, twin brother of 8H, lopped down by AE
+8H Crethon, twin brother of 8G, lopped down by AE
+8I Euneus, king of Lemnos, son of 6E and 6D
+8J Alcimus, friend of AC
+8K Melanippus, Greek leader
+8L Deipylus, companion of ST
+8M Leucus, companion of OD
+8N Popyphontes, Theban warrior, killed by 8R
+8O Maeon, Theban warrior, spared by 8R
+8P Eteocles, brother of 8Q
+8Q Polyneices, king of Thebes
+8R Tydeus, king of Calydon, son of 82, father of DI
+8T Bias, Pylian commander
+8U Haemon, Pylian commander
+8V Chromius, Pylian commander
+8W Alastor, Pylian commander
+8X Pelagon, Pylian commander
+8Y Daedalus, Athenian architect
+8Z Ariadne, daughter of 66
+90 Eurynome, daughter of OC
+91 Prothous, commander of Magnesian forces
+92 Guneus, king of Cyphus, leader of Thessailian contingent
+93 Leonteus, co-leader with 94 of Thessalian contingent
+94 Polypoetes, son of 6A, co-leader of Thessalian contingent
+95 Machaon, physician and co-leader of Thessalian contingent
+96 Podaleirius, physician and co-leader of Thessalian contingent
+97 Asclepius, famous physician, father of 95 and 96
+98 Medon, step-brother of AX, replaced 99 as leader of Thessalian contingent
+99 Philoctetes, famous archer bitten by a snake
+9A Eumelus, leader of Thessalian contingent
+9B Podarces, brother of 9C, leader of Thessalian contingent
+9C Protesilaus, the first Greek to land and the first casualty
+9D Epistrophus, brother of 9E, slain by AC
+9E Mynes, spearman slain by AC
+9F Antiphus, grandson of HR, leader of troops from Dodecanese islands
+9G Pheidippus, brother of 9F, leader of troops from Dodecanese islands
+9H Nireus, Symian leader, handsomest Greek excluding AC
+9I Licymnius, uncle of HR, murdered by TL
+9J Astyocheia, captured at Ephyra by HR
+9K Thoas, leader of Aetolians
+9L Polyxeinus, leader of an Epeian flotilla
+9M Diores, leader of an Epeian flotilla, killed by 09
+9N Thalpius, leader of an Epeian flotilla
+9O Amphimachus, son of Cteatus, leader of an Epeian flotilla
+9P Agapenor, king of Arcadians
+9Q Thamyris, Thracian bard
+9R Erechtheus, ancient ruler of Athens
+9S Elephenor, leader of the long-haired Abantes
+9T Epistrophus, son of Iphitus, Phocian leader
+9U Schedius, son of Iphitus, Phocian leader
+9V Astyoche, mother of 9X and 9W
+9W Ialmenus, son of AR and 9V, leader of Minyans
+9X Ascalaphus, twin brother of 9W
+9Y Clonius, Boeotian leader slain by AO
+9Z Arcesilaus, Boeotian leader
+
+1:CH,AG,ME,GS;AP,CH;HE,AC;AC,AG,CA;HE,AT;AT,AC;AT,OG;NE,AG,AC;CS,OD
+&:TA,EB,PA,AC,BR;TH,PO;AC,2I;AC,TH,PE;TH,AZ;AZ,ZE;CS,OD,CH;EO;ZE,OG
+&:TH,ZE;ZE,HE;HE,HP;HP,OG;HP,ZE
+2:ZE,FD;FD,AG;EO,OG;AG,NE;RU,GS;HP,ZE;ZE,HM;HM,PC;PC,AS;AS,TY;TY,AG
+&:AG,GS;NO;EU;ZF;HE,AT;AT,OD;OD,EB;OD,GS;TR,OD,AC;TR,GS;OD,TR;OD,AT,GS
+&:CA,GS;NE,GS,AG;PS,HL;AG,NE,ID,AJ,AX,DI,OD,ME;AT,GS;MU,HO;PB,LT,9Z,PT,9Y
+&:9W,9X,AR,9V;9U,9T;AX;9S;9R,AT;AJ;DI,ST,EA;AG;ME;NE;MU,9Q;9P;9O,9N,9M,9L
+&:9K;ID;MG,OD;FY,AU;AU,HR;HR,9J;TL,9I;9H;9G,9F;AC,BR;AC,9E,9D;9C,9B;99
+&:9B,9A,98,96,95,EP,94,93,92;97;91;IR,PR;IR,HT;AE,01,02;AI,AF;PN,AP;03,04,05
+&:06;07,08;02,09,0A;0B;RA;0C;0D,0E;0F,0G;0H,0I;0J,0K;0L,0M;0M,AC;SA,GL
+3:PS,ME;HT,PS;PS,HL;AG,GS;HT,GS,TS;ME,GS,TS;AG,TA;IR,HL
+&:HL,AA,CL,PR,0N,0O,0P,0Q,0R,0S,AN;PR,0T,0U;AG;AN,OD,ME;AJ;ID,ME,HL;CT,PU
+&:IA,PR;ZE;PR,AN,AG;HT,OD;PS,LY;PS,ME,AF;AF,HL,AA,CL;AF,HL,PS
+4:ZE,OG;OG,HB;ZE,HE,AT;AT,PN,ME;AG,ME;AG,TA;TA,95;97,CN;AG,EM;AG,GS;AG,ID,MR
+&:AG,AJ,AX;AG,NE,8X,8W,8V,8U,8T;AG,MT,OD;AG,DI,ST;8R,8Q;8R,8P,AT,8O,8N;AT,GS
+&:AR,TS;SF,GS,TS;AL,0V,9S;9S,AO;AJ,0W;34,AJ,8M;OD,0X;HT;AP,TS;AT,GS;09,9M;9K,09
+5:AT,DI;0Y,0Z,10;0Y,0Z,DI;0Z,HP;AT,AR;AG,0D;11,ID;ME,12;12,AM;AT,13;13,MR
+&:14,15,AN;15,MG;EP,16;DI,PN;DI,ST;DI,AT;DI,17;DI,18;DI,19,1A;DI,1B,1C
+&:DI,1D,1E;AE,PN;LY,PN;ST,DI;ZE,1F;ZE,1G;AI,AE;DI,PN,AE;AF,AI;AF,AE;ST,8L
+&:DI,AF;AP,AE;AF,GR;IR,AF;AF,AR;AF,DN;EF,OT,AR;EE,HM;HM,AR;HR,HE;HR,HD
+&:HD,AP;HR,OG;AT,HE,ZE;ZE,AF;DI,AP,AE;AM,LE,AE;AP,AR,SF;SA,HT;HT,TS;TS,GS
+&:TS,AE;DI,OD,AJ,AX;AG,1H;AE,8G,8H;ME,AR;ME,AL,AE;ME,AL,8G,8H;ME,AL,0C,1I
+&:HT,TS,AR,EN;HT,8E,8F;AJ,1J;AJ,TS;TL,SA;HR,1L;HR,1K;ZE,SA;OD,AT;OD,1M
+&:OD,1N;OD,1O;OD,1P;OD,1Q;OD,1R;OD,1S;HT,OD;SA,HT;SA,1T;HT,GS;HT,8D;HT,8C
+&:HT,8B;HT,8A;HT,89;HE,AT;HE,HB;HE,AT,HA;HE,ZE;AF,AP;HE,DI,GS;AT,DI,ST
+&:AT,8R;AT,DI,AR;AR,88;AR,ZE,AP;HB,AR
+6:GS,TS;AJ,1U;DI,1V,1W;EA,1X;EA,1Y;EA,1Z,20;1Z,20,AB,21;94,22;OD,23;TU,24
+&:AL,25;AG,26;LT,27;EP,28;ME,03,AG;NE,GS;HN,HT,AE;HT,TS;GL,DI;87,DT;DT,TH
+&:OG,87;85,WI;85,84;84,BL;ZE,83,BL;29,83,BL;2A,BL;EO,2A;BL,CM;BL,2F;BL,2G
+&:2A,BL,2B;2B,BL,2C,2D,2E;ZE,2E;2E,SA;AR,2C,2F;AM,2E;2D,GL;82,BL;ZE,GL
+&:HT,HC,LA;HC,2H,14,AT;HT,PS,HL;HT,AH,2I;HT,AH,2J;AC,2I;AJ,AX,ID,AG,ME,DI;PS,HT
+7:PS,81;HT,80;GL,7Z;AT,AP,HN;HT,TS;AG,GS;HT,TS,GS;ME,GS;AG,ME;NE,GS;NE,PE
+&:AR,7Y;7X,7Y;7X,7W;NE,7W;AG,DI,AJ,AX,ID,MR,EP,9K,OD;AJ,GS;AJ,HT;AP,HT
+&:AJ,HT,TA,IA;AG,AJ;AG,NE;AN,PS,PR;IA,AG,ME,DI;IA,PR;PO,ZE;EO;PO,AP,1K;6D,6E,8I
+8:EO;ZE,OG;AT,ZE;GS,TS;ID,AG,AJ,AX;NE,PS;NE,HT;DI,OD;DI,NE,EM,ST;DI,HT,2K
+&:HT,2L;HT,TS;HE,PO;HE,AG;AG,GS;DI,2M;AG,ME,AJ,AZ,ID,MR,EP,TU;TU,2N;TU,2O;TU,2P
+&:TU,2Q;TU,2R;TU,2S;TU,2T;TU,2U;AG,TU;TE,TU;TU,2V;HT,TU;HT,2W;AJ,TU,6M,8W
+&:HT,GS;HE,AT;7U,HR,HD;HA,AT,HE;ZE,IR;IR,HE,AT;ZE,PO;ZE,AT,HE;HT,TS;PO,AP,1K
+9:AG,DI,NE;TM,9X,9W,MR,7T,7S,7R;NE,AG;7Q;7P,7O,7N;HD;PX,AJ,OD,7M,EB,AC,PA
+&:AD,AD,PA;PE,AC;BR;TH;PX,7L,7K;7L,HD,PP;PX,PE;82,AM;7I,7J;7I,HD,PP,ER
+&:7J,7H;7G,AP,7F;82,7J;AC,7E;PA,7D;AG,OD,DI
+10:AG,ME;AG,NE;NE,OD,DI,ME,ID,AJ,MR,TM,AX,AG;7L,7C;7C,7B;7B,7A;AT,OD,DI
+&:HT,2X;2X,OD,DI;DI,2Y;AP,2Z
+11:EO,79;SF,GS;AG,78;AG,HE,AT;HT,PD,AE,31,AO,02;HT,TS;TS,GS;SF;OG;AF,AP
+&:AG,32;AG,33;AG,34,35;AC,34,35;AC,PR;36,PS;AG,37,38;ZE,HT,IR;MU;39,3A
+&:AG,39;AG,3B;3A,3B,HD;AG,GS;HT,TS;HT,77;HT,76;HT,75;HT,74;HT,73;HT,72
+&:HT,71;HT,70;HT,6Z;DI,OD,3C,3D;DI,03,04;OD,3E;OD,3F;DI,3G;DI,HT;AP,HT
+&:PS,DI;DI,ST;OD,TS;OD,3H;OD,3I;OD,3J;OD,3K;OD,3L;AT,OD;OD,3M;ME,AJ,OD
+&:AJ,3N;AJ,3O;AJ,3P;AJ,3Q;AJ,3R;PS,95;ID,NE;NE,95;HT,2W;EP,AJ;EP,3S;PS,EP
+&:AC,PA;EM,NE,95;6Y,NE,95;6Y,AC;NE,95,PA;NE,6X;NE,6W,HR;AT,NE;NE,6U
+&:6U,6V;NE,6T;PO,5A;5A,57;NE,OD,6S,AC,PA,PE;PA,EP;CN,PA;96
+12:PA,EP;PO,AP,ZE;HT,GS;PD,HT,2W;PS,3T,AO;HN,DP,06;AE,01,02;SA,GL,3V
+&:06,93,94,3W,3X,3Y,3Z,40;94,41;94,42;94,43;93,44;93,45;93,46;93,3Y;PD,HT
+&:HT,TS;GS,TS;GS,AJ,AX;ZE,SA;SA,GL;MT,6R;6R,AJ,AX;AJ,TU,6Q,MT;AJ,47;TU,GL
+&:SA,6P;AJ,TU,SA,ZE;SA,TS,MT,GS;ZE,HT,TS
+13:ZE;PO,AJ,AX;PO,TU,LT,PB,9K,7S,MR,AL;GS,HT;DP,MR;TU,48;48,49;48,PR;HT,TU,9O
+&:AJ,HT;6O,MT;PO,ID;ID,MR;4B,4A,PR;4B,ID;06,ID,AL;DP,ID,6N;AL,6M,8W,6N;ID,3T,PO
+&:AI,4C,3T;DP,AE,PS,AO,ID,9X,7T,7S,MR,AL;ID,40;DP,9X;OG;DP,MR;DP,PL;AE,7T
+&:AL,3Z;3W,AL;3W,MR;HN,7S;ME,HN;HN,AO;ME,4F;4G,ME;MR,4G;4G,PS;0C,4G;PS,6L
+&:6K,6L;HT,AX,9B,MT;MT,6O,6J,6I;MG,6G,6H;9B,98;AJ,AX,TS;PD,HT
+&:HT,PS,PD,2W,4H,4I,4J,4K,4L;AJ,HT,TS,GS
+14:NE,95;6Y;TM;NE,DI,OD,AG;51,52,82;82,8R;8R,6F;PO,AG;HP;AT;HE,AF;HE,RH,OC,TT
+&:HE,SL;HE,HR;ZE,OG;SL,NI;SL,GR;HE,ZE;ZE,69,6A;ZE,68,67;ZE,64,65;ZE,64,66
+&:ZE,SE,DT;ZE,62,HR;ZE,DM,PP;ZE,LE,AP,AM;ZE,SL;SL,PO;PO,GS;DI,OD;HT,AJ
+&:PD,AE,AO,SA,GL,HT;AX,4N;PD,60;AJ,PD,01;02,5Z;PB,02;PB,4O;MU;AJ,4P
+&:AL,4H;AL,4Q;MR,4M;MR,4R;TU,4S;TU,4T;ME,4U;AX,TS
+15:ZE,HE;PO,GS;TS,HT;HE,HR;ZE,HR;HE,OG;HE,TI;HE,AR,AT;HE,AP,IR;ZE,IR;IR,PO
+&:PO,ZE,HD,RH,CR;ER;ZE,AP;AP,HT;9K;AJ,ID,EU,MG,HT,AP,TS;HP,ZE;HT,6O;HT,5W
+&:AE,98;AE,5V;PD,6M;PL,7V;AO,9Y;5U,PS;NE;PA,EP;HT,AJ;AJ,4V;HT,5T;5T,AJ;TU,4W
+&:PD,4X;TU,HT;AJ,TU;HT,TS;AJ,GS;HT,5S;AJ,4Y;PD,5R;MG,PD,AP;MG,4Z;A0,MG;ME,A0
+&:HT,B0;ME,AL;AL,B0;HT,AL;5Q,HR;5Q,7U;HT,5P;NE,GS;AT;AJ;GS,TS
+16:PA,AC;ZE;MU;HT,AJ;CN,PE;PA,AD,XB;ZF,PH,XB;5L,PE,5N;SP,5N,5O;HM,5J,5K
+&:5K,5G;5I,5J,5H;5H,5K;5O,5K,5F,PX,5E,AC;TH;AC,ZE;PA,0B;PA,C0;ME,D0;MG,E0
+&:AL,F0;TM,G0;H0,CM;AX,I0;PB,J0;MR,02;ID,K0;AJ,HT;PA,HT;PA,L0;PA,M0;PA,N0
+&:PA,O0;PA,P0;PA,Q0;PA,R0;PA,S0;PA,T0;PA,U0;PA,V0;PA,W0;SA,PA;HE,ZE;PA,X0;AD
+&:SA,GL;GL,AP;GL,PD,AG,AE,HT;PA,AJ,AX;5D,PE,TH;5D,HT;PA,Y0;GL,5C;MR,Z0;AE,MR
+&:PA,MR;ZE,AP;AP,SA;SL,DE,SA;PA,XB;ZE,PA;PA,AD;PA,A1;PA,B1;PA,C1;PA,D1;PA,E1
+&:PA,F1;PA,G1;PA,H1;PA,I1;PA,AP;AP,HT;HT,2W,PA;EU,NO;AP,PA;J1,PA;HT,PA
+17:ME,4U;ME,J1;AP,HT;ME,AJ,PA;GL,HT;OG,PE,XB;PE,AC,XB
+&:HT,0J,GL,K1,L1,3V,M1,07,0H,0F,0G,AJ,ME;AX,ID,MR,AJ,TS;07,PA,AJ;HT,AJ,9U
+&:0H,07,AJ;AP,AE;AE,TS;AE,5B;7R,N1;3V,AJ;AL,TM;AC;GS,TS;AD,XB;ZE,XB;5E,AD
+&:HT,AE,0F,O1;AD,O1;HT,AD;AX,AD;ZE,AT;AT,ME;HT,P1;ME,P1;AP,HT;PD,PB;HT,LT
+&:ID,HT,59;MR,ID;AJ,MR,AX,ME;ME,AL;AL,58;ME,TM;ME,MR,AJ,AX;HT,AE,GS
+18:AC,AL;TH,NR;TH,AC;HE,HR;HT,AE,AJ,AX,PA;HE,IR;IR,AC;AT,AC;PD,HT;AC,PA
+&:TH,HP,CI;TH,90,HP;HP,RO,TH;AG,AC,BR;AC,PA;AP,PA,HT;8Y,8Z
+19:EO,OC;TH,AC,PA;AC,GS,DI,OD,AG;AG,3B;AM,BR;ZE,MO,ER;ZE,HE,MC;HE,7U,62
+&:OD,AC,AG;OD,AL,TM,MG,9K,MR,7R,8K,BR;TA,AG;AG,GS,AC;BR,PA;AG,ME,NE,ID,PX,AC,PA
+&:ZE,AT;AT,AC;CN,PE;AD,8J,XB;AD,AC,XB;HE,XB;XB,ER
+20:ZE,TI;TI,OG;HP,ZE;PO,ZE;HE,AT,PO,HM,HP;AR,AP,AM,LE,XA,AF;GS,TS,SF;AP,PO
+&:AT,AR;AM,HE;HM,LE;HP,XA;HD;AP,AE;AE,AC;ZE,AE;AT,AC;AE,AF;MO,AC;AT,TS
+&:HR,1L;AE,AC;AC,ZE,AT;OG,AE;S1,BO;1F,1G,Q1,R1;OG,1G;1K,79,0P,0Q,0R
+&:AE,AI;PO,HE;PO,AC;PO,AE;AC,GS;HT,TS;AP,HT;AC,T1;AC,U1,V1;AC,W1;AC,HT
+&:AP,HT;AT,AC;AC,X1;AC,Y1;AC,Z1,A2;AC,B2;AC,C2;AC,D2;AC,E2;AC,F2,G2
+21:AC,TS;AC,LY,8I;H2,8I;I2,PR,W1;I2,PR,LY;XA,AC;3V,J2;J2,RA,K2;XA,3V;AC,3V
+&:OC,ZE;AC,L2,M2,N2,O2,P2,Q2,R2;XA,AP;PO,AT,AC;XA,SI;HE,HP;XA,HP;NO,ZF;BO
+&:HP,XA,HE;ZE;AR,AT;DI,AR;HE,AR;AR,AF;HE,AT;AT,AF,AR;PO,AP,1K;ZE,1K;AP,AM
+&:HE,AM;HM,LE;AM,ZE;PR,TS;AP,TS;AP,AO;AO,AC
+22:TS;HT,CS;AP,AC;PR,HT;PR,I2,S2;HC,HT,PR;HT,AC;ZE,OG;AT,ZE;AP,HT;AT,AC
+&:AT,HT;HT,HD;GS,HT;AC,XB,HT;HC,PR;AH,HT,AF;2I,HT;2J,HT
+23:AC,GS,TH;AC,PA,HT;AC,AG;86,PA;6S,PA;PE,PA,AC;EO,GS;AG,MR;AP,AF,HT;AC,IR
+&:IR,ZF,BO,NO,EU;BO,ZF,AC,PA;AC,AG,GS;PO,PE,XB;9A,DI,ME,AL,MR;6C,AG;NE,AL
+&:AP,DI;AT,DI;AT,9A;ID,AX,AC;ST,DI;AC,9A;AC,AL;AC,3V;AM,9A;TA,ME;ME,AL;ME,6B
+&:MR;AC,NE;NE,63;NE,61;NE,5Y;NE,5X,5M;NE,5A;56,EA;DI,EA;55,54;AJ,OD;8I,LY,PA
+&:AJ,OD,AL;AT,OD;AT,AJ;AG,MR;AG,TA
+24:AC,HT;AP,HT;HE,AT,AF,PS;PS,HL;PO,HE,AT;AP,OG;MO;HE,AP;ZE,HE;AC,TH;ZE,IR
+&:AT,HE,TH,OG;ZE,TH;IR,PR;PR,HC;PR,HN,PS,T2,U2,V2,PL,DP,W2,X2;30,3U,HT;PR,IA
+&:PR,ZE;ZE,HM;HM,PR,IA;AC,AD,8J;PR,AC;AC,IA;AC,PA;53,AP,AM;AC,BR;HM,PR,IA,HT
+&:4A,TS,AH,HC,HT,PR,IA;AH,HT;HC,HT;HL,HT;EO
+* End of file "homer.dat"
diff --git a/support/graphbase/huck.dat b/support/graphbase/huck.dat
new file mode 100644
index 0000000000..a1171fbbc6
--- /dev/null
+++ b/support/graphbase/huck.dat
@@ -0,0 +1,123 @@
+* File "huck.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* Huckleberry Finn, by Mark Twain
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 118,822615693)
+AB Abner Shackleford, friend of PW
+AP Aunt Polly, aunt who raises TS
+AS Aunt Sally Phelps, sister of AP
+AT Ab Turner, undertaker's assistant
+BD Bud Grangerford, cousin of BK
+BE Betsy, slave of RG
+BG Bob Grangerford, eldest son of CG and RG
+BH Buck Harkness, incites lynch mob
+BI Bill, thief wants to shoot TU
+BK Buck Grangerford, youngest son of CG and RG
+BM Brother Marples, friend of AS and SP
+BN Ben Rucker, friend of PW
+BO Boggs, town drunk
+BP Brer Penrod, friend of AS and SP
+BR Ben Rogers, member of TS's gang
+BS Baldy Shepherdson, kills BU in feud
+BT Bessie Thatcher, on boat with JT
+BU Burton, neighbor of SP
+CG Colonel Saul Grangerford, quality gentleman
+CS Colonel Sherburn, store owner who kills BO
+DH Deacon Lot Hovey, friend of PW
+DR Doctor Robinson, skeptical doctor
+DU The Duke, thespian swindler
+HF Huckleberry Finn, free spirit and narrator
+HI Hines, husky debunker
+HS Harney Shepherdson, young member of clan feuding with CG
+HT Brer Hightower, friend of AS and SP
+HW Harvey Wilks, English `dissentering minister'
+JG Joe Grangerford, cousin of BK
+JH Joe Harper, member of TS's gang
+JI Jimmy, young member of SP household
+JK Jack, slave of CG assigned to HF
+JL Judith Loftus, woman not fooled by HF
+JM Jim, runaway slave of MW
+JN John, on skiff with MP
+JO Joanna (the harelip), youngest niece of PW
+JP Jake Packard, thief wants to drown TU
+JT Judge Thatcher, prominent man in HF's village
+JY Johnny, JM's son
+KI The King, distinguished rapscallion
+LB Levi Bell, lawyer and friend of PW
+LI Lize, slave to AS
+LZ 'Lizabeth, JM's daughter
+MA Mathilda Angelina Araminta Phelps, daughter of AS and SP
+MC Miss Charlotte Grangerford, eldest daughter of CG and RG
+MH Mrs. Hotchkiss, friend of AS and SP
+MJ Mary Jane Wilks, redheaded and `full of sand'
+MP Mr. Parker, vigilante
+MR Mary, cousin of TS
+MS Miss Sophia Grangerford, second daughter of CG and RG
+MW Miss Watson, unmarried sister of WD
+NT Nat, slave of SP who feeds JM
+OD Old Doctor, doctor who treats TS
+PA Pap, ne'er-do-well father of HF
+PW Peter Wilks, recently dead man
+RG Rachel Grangerford, wife of CG
+RH Reverend Hobson, Baptist preacher
+SD Sister Damrell, friend of AS and SP
+SI Sister Dunlap, friend of AS and SP
+SP Silas Phelps, cotton farmer married to AS
+SR Sister Ridgeway, friend of AS and SP
+SS Sid Sawyer, quiet half-brother of TS
+SU Sister Utterback, friend of AS and SP
+SW Susan Wilks, sister of MJ and JO
+TB Tommy Barnes, little member of TS's gang
+TC Tim Collins, `young jake' en route to Ryo Janeero
+TF Townfolk, crowd of people
+TG Tom Grangerford, second son of CG and RG
+TP Thomas Franklin Benjamin Jefferson Elexander Phelps, son of AS and SP
+TS Tom Sawyer, adventurous friend of HF
+TU Jim Turner, tied-up thief
+WB Widow Bartley, friend of PW
+WD Widow Douglas, `allowed she would sivilize HF'
+WW William Wilks, deaf and dumb brother of HW and PW
+
+1:TS,HF;JT;WD,HF,MW
+2:JM,TS,HF;TS,HF,JH,BR,TB
+3:WD,MW,HF;TS,HF,JH,BR;PA
+4:WD,HF,MW;HF,JT;HF,JM;HF,PA
+5:PA,HF;PA,JT;JT,WD;JT,HF
+6:JT,PA;PA,HF;JT,HF;PA,WD
+7:PA,HF
+8:PA,JT,BT,JH,TS,AP,SS,MR;JM,HF;JM,MW;MW,WD
+9:JM,HF
+10:JM,HF
+11:HF,JL;PA,JT;JM,HF
+12:JM,HF;TU,JP,BI
+13:BI,JP;JM,HF
+14:JM,HF
+15:JM,HF
+16:JM,HF;HF,MP,JN
+17:HF,CG,BG,TG,RG,BK,MC,MS,BE
+18:HF,CG,BG,TG,RG,BK,MC,MS;BK,HF,HS;BS,BD;HF,JM,JK;MS,HS;BK,JG
+19:HF,JM,KI,DU
+20:HF,JM,KI,DU;KI,TF
+21:HF,JM,KI,DU;BO,CS,TF
+22:CS,BH,TF;HF,KI,DU
+23:KI,DU,TF;HF,KI,DU,JM;JM,JY;JM,LZ
+24:HF,KI,DU,JM;KI,DU,TF;KI,DU,HF,TC;PW,HW
+25:KI,DU,MJ,SW,JO,TF,PW;KI,DU,BN,AB,DH,WB;KI,DU,HF;TF,AB,DR,MJ,SW,JO
+26:KI,DU,MJ,HF,SW;HF,JO,MJ,SW
+27:HF,PW;PW,MJ;WB,KI,DU,TF,PW,HF,RH
+28:HF,MJ;HF,SW,JO;HW,WW,TF
+29:KI,DU,HW,WW,TF,DR,LB,HI,HF,AT;HI,TC;HF,JM
+30:HF,JM,KI,DU
+31:HF,JM;HF,DU,KI
+32:AS,LI,HF,SP
+33:HF,TS;HF,SP;AS,JI;JI,LI;AS,SP,TS;JM,SP,BU;BU,TF;TF,KI,DU
+34:TS,HF,JM,NT
+35:TS,HF
+36:TS,HF,JM,NT
+37:TS,HF,AS,SP,MA,LI;TS,HF,NT,JM
+38:TS,HF,JM
+39:TS,HF,AS;AS,TP;AS,SP;TS,HF,JM
+40:TS,HF;HF,AS,TF;TF,HF,JM,TS
+41:HF,OD;HF,SP,AS,MH,SD,SU,BP,SI,HT,BM,SR
+42:HF,AS,SP,TS,OD,JM,TF;AS,HF,TS,AP,SP;MW
+43:HF,TS,AP,AS,SP,JM;PA,JM
+* End of file "huck.dat"
diff --git a/support/graphbase/jean.dat b/support/graphbase/jean.dat
new file mode 100644
index 0000000000..e647931406
--- /dev/null
+++ b/support/graphbase/jean.dat
@@ -0,0 +1,442 @@
+* File "jean.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* Les Mis\'erables, by Victor Hugo
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 437,131840947)
+AZ Anzelma, daughter of TH and TM
+BA Bahorel, `Friends of the ABC' cutup
+BB Babet, tooth-pulling bandit of Paris
+BJ Brujon, notorious criminal
+BL Blacheville, Parisian student from Montauban
+BM Monsieur Bamatabois, idler of M-- sur M--
+BO Bossuet (Lesgle), `Friends of the ABC' klutz
+BR Brevet, convict in the galleys with JV
+BS Bruneseau, explorer and mapper of the sewers of Paris
+BT Baroness of T--, friend of GI
+BU Madame Burgon, new landlady at Gorbeau House
+BZ Boulatruelle, former convict and road mender in Montfermeil
+CC Cochepaille, convict in the galleys with JV
+CH Champmathieu, accused thief mistaken for JV
+CL Countess de L\^o, distant relative of MY
+CM Combeferre, `Friends of the ABC' guide
+CN Chenildieu, convict in the galleys with JV
+CO Cosette, daughter of FN and FT
+CR Courfeyrac, `Friends of the ABC' center
+CV Cravatte, mountain bandit
+DA Dahlia, lover of LI
+EN Enjolras, `Friends of the ABC' chief
+EP Eponine, daughter of TH and TM
+FA Fameuil, Parisian student from Limoges
+FE Feuilly, `Friends of the ABC' political idealist
+FF Fauchelevent, aged notary of M-- sur M--
+FN Fantine, lover of FT
+FT F\'elix Tholomy\`es, Parisian student from Toulouse
+FV Favourite, lover of BL
+GA Gavroche, young urchin living at Gorbeau House
+GE G\'eborand, retired merchant of D--
+GG G--, former member of National Convention
+GI Monsieur Luke Esprit Gillenormand, grand bourgeois
+GP George Pontmercy, father of MA and son-in-law of GI
+GR Gribier, new gravedigger at cemetery
+GT Grantaire, `Friends of the ABC' skeptic
+GU Gueulemer, Herculean bandit of Paris
+HL Madame Hucheloup, keeper of Corinth Inn
+IS Isabeau, baker
+JA Javert, police officer of M-- sur M--
+JD Jondrette, father of GA
+JL Jacquin Labarre, innkeeper of La Croix de Calbas
+JO Joly, `Friends of the ABC' medic
+JP Jean Prouvaire, `Friends of the ABC' poet
+JU Judge of Douai, judge at the court trying CH
+JV Jean Valjean, thief of bread
+LI Listolier, Parisian student from Cahors
+LL Old woman 2, landlady of JV in Paris at Gorbeau House
+LP Louis Philippe, Orleans King of France
+MA Marius, grandson of GI
+MB Mademoiselle Baptistine, sister of MY
+MC Marquis de Champtercier, ultra-royalist miser
+ME Madame Magloire, housekeeper to MY
+MG Madamoiselle Gillenormand, unmarried daughter of GI
+MI Mother Innocent, prioress of Convent of Petite Rue Picpus
+MM Monsieur Mabeuf, prefect of church
+MN Magnon, servant of GI
+MO Montparnasse, genteel bandit of Paris
+MP Madame Pontmercy, younger daughter of GI
+MR Madame de R--, Marquise de R--
+MT Marguerite, old lady who teaches FN to live poor
+MV Madamoiselle Vaubois, friend of MG
+MY Monsiuer Charles Fran\c{c}ois Bienvenu Myriel, Bishop of D--
+NP Napoleon, Emperor of France
+PG Petit Gervais, a small boy in D--
+PL Mother Plutarch, maid of MM
+PO Old woman 1, portress of JV in M-- sur M--
+QU Claquesous, night-like bandit of Paris
+SC Monsieur Scaufflaire, keeper of horses and chaises in M-- sur M--
+SN Count ***, `philosophic' senator
+SP Sister Perp\'etue, stout nun at infirmary in M-- sur M--
+SS Sister Simplice, saintly nun at infirmary in M-- sur M--
+TG Lieutenant Theodule Gillenormand, soldier and grandnephew of GI
+TH Th\'enardier, sergeant of Waterloo and keeper of a chophouse
+TM Madame Th\'enardier, wife of TH
+TS Toussaint, servant of JV at Rue Plumet
+VI Madame Victurnien, snoop in M-- sur M--
+XA Child 1, son of TH sold to MN
+XB Child 2, son of TH sold to MN
+ZE Zephine, lover of FA
+
+1.1.1:MY,NP;MY,MB
+1.1.2:MY,ME;ME,MB
+1.1.3:MY
+1.1.4:MY,ME;MY,CL;MY,GE;MY,MC;MY,MB
+1.1.5:MY,MB,ME
+1.1.6:ME,MY
+1.1.7:MY,CV;MY,MB,ME
+1.1.8:SN,MY
+1.1.9:MB
+1.1.10:MY,GG
+1.1.11:MY
+1.1.12:MY
+1.1.13:MY
+1.1.14:MY,SN
+1.2.1:JL,JV;JV,MT;MR,JV
+1.2.2:ME,MB,MY
+1.2.3:ME,MB,MY,JV
+1.2.4:MY,JV,MB;MY,JV,MB,ME
+1.2.5:MY,ME,JV
+1.2.6:JV,IS
+1.2.7:JV
+1.2.8
+1.2.9:JV
+1.2.10:JV
+1.2.11:JV
+1.2.12:MY,ME;MY,JV
+1.2.13:PG,JV
+1.3.1
+1.3.2:FT,LI,FA,BL
+1.3.3:FT,LI,FA,BL,FV,DA,ZE,FN
+1.3.4:FT,LI,FA,BL,FV,DA,ZE,FN
+1.3.5
+1.3.6:BL,FV;FV,DA
+1.3.7:FT
+1.3.8:FT,LI,FA,BL,FV,DA,ZE,FN
+1.3.9:FV,DA,ZE,FN
+1.4.1:TM,FN;TH,TM,FN
+1.4.2
+1.4.3:CO;TH;TM
+1.5.1:JV
+1.5.2:JV
+1.5.3:JV
+1.5.4:MY
+1.5.5:JA
+1.5.6:FF,JV,JA
+1.5.7:FF
+1.5.8:VI;FN
+1.5.9:VI;MT,FN
+1.5.10:MT,FN
+1.5.11
+1.5.12:BM,FN,JA
+1.5.13:FN,JA;FN,JA,JV;JA,JV;JV,FN
+1.6.1:JV,FN
+1.6.2:JV,JA
+1.7.1:SP,SS;JV,SS;JV,FN
+1.7.2:JV,SC
+1.7.3:JV
+1.7.4:JV,PO
+1.7.5:JV
+1.7.6:SS,FN
+1.7.7:JV
+1.7.8:JV
+1.7.9:JV,JU,CH,BM
+1.7.10:JU,CH,BR,CN,CC,JV,BM
+1.7.11:JV,BR,CN,CC,JU,CH
+1.8.1:SS,JV;JV,FN
+1.8.2:JV,FN
+1.8.3:JV,FN,JA
+1.8.4:JV,FN;JV,JA;JA,FN,JV;JA,JV
+1.8.5:JV,PO;FN,SP,SS;JV,SS;PO,JA;JA,SS
+2.1.1
+2.1.2
+2.1.3
+2.1.4:NP
+2.1.5
+2.1.6
+2.1.7:NP
+2.1.8:NP
+2.1.9:NP
+2.1.10:NP
+2.1.11
+2.1.12
+2.1.13
+2.1.14
+2.1.15
+2.1.16
+2.1.17
+2.1.18
+2.1.19:TH,GP
+2.2.1:JV
+2.2.2:TH,BZ
+2.2.3
+2.3.1:CO
+2.3.2:TH,TM
+2.3.3:TM,CO
+2.3.4:TM,CO
+2.3.5:CO
+2.3.6:JV,CO
+2.3.7:CO,JV
+2.3.8:TM,JV;CO,TM;JV,TM;JV,TH,TM;TH,TM;EP,AZ;EP,TM;TM,CO;TH,JV
+2.3.9:TM,JV;TH,JV
+2.3.10:TH,JV
+2.3.11
+2.4.1:CO,JV
+2.4.2:CO,JV
+2.4.3:CO,JV;JV,LL
+2.4.4:LL,JV,CO
+2.4.5:JA,JV;JV,CO;JV,LL
+2.5.1:CO,JV
+2.5.2:CO,JV
+2.5.3:CO,JV
+2.5.4:CO,JV
+2.5.5:CO,JV
+2.5.6:CO,JV
+2.5.7:CO,JV
+2.5.8:JV,FF
+2.5.9:JV,FF
+2.5.10:JA,TH;JA,LL;JA,JV
+2.6.1
+2.6.2
+2.6.3
+2.6.4
+2.6.5
+2.6.6
+2.6.7:MI
+2.6.8
+2.7.1
+2.7.2
+2.7.3
+2.7.4
+2.7.5
+2.7.6
+2.7.7
+2.7.8
+2.8.1:JV,FF
+2.8.2:FF,MI
+2.8.3:FF,MI
+2.8.4:FF,JV;JV,CO
+2.8.5:GR,FF
+2.8.6:JV
+2.8.7:FF,GR;FF,JV
+2.8.8:FF,MI,JV
+2.8.9:FF,JV
+3.1.1
+3.1.2
+3.1.3
+3.1.4
+3.1.5
+3.1.6
+3.1.7
+3.1.8:JD,BU;GA,BU
+3.2.1:GI
+3.2.2:GI
+3.2.3:GI
+3.2.4:GI
+3.2.5:GI
+3.2.6:GI,MN
+3.2.7:GI
+3.2.8:MG,MP;MG,MV;MG,TG;MG,GI,MA
+3.3.1:BT,GI;MG,GI,MA
+3.3.2:GP,MP;MG,MA
+3.3.3:BT,MA
+3.3.4:GI,MA;MA,GP
+3.3.5:MA,MM;GI,MA,MG
+3.3.6:MA
+3.3.7:TG,MG;TG,MA
+3.3.8:GI,MG;GI,MA;GI,MG
+3.4.1:EN;CM;JP;FE;CR;BA;BO;JO;GT
+3.4.2:MA,BO;MA,BO,CR
+3.4.3:CR,MA;EN,CR,MA
+3.4.4:GT,BO;JO,BA
+3.4.5:CR,EN,MA,CM
+3.4.6:CR,MA
+3.5.1:MA
+3.5.2:MA
+3.5.3:MA
+3.5.4:MM,PL
+3.5.5:MM
+3.5.6:GI,MG;GI,TG
+3.6.1:MA,CO;MA,JV,CO
+3.6.2:MA,JV,CO
+3.6.3:MA,CO
+3.6.4:MA
+3.6.5:MA
+3.6.6:MA,CO;MA,CO,FT
+3.6.7:MA
+3.6.8:MA,CO
+3.6.9:MA
+3.7.1
+3.7.2
+3.7.3:GU;BB;QU;MO
+3.7.4
+3.8.1:MA
+3.8.2:MA
+3.8.3:MA
+3.8.4:MA,TH
+3.8.5:MA
+3.8.6:TH
+3.8.7:TH,EP;TH,TM
+3.8.8:TH,JV,CO
+3.8.9:TH,JV
+3.8.10:MA
+3.8.11:MA,EP
+3.8.12:TH,TM
+3.8.13:MA
+3.8.14:MA,JV
+3.8.15:CR,BO
+3.8.16:TH,TM,EP,AZ
+3.8.17:TH,TM
+3.8.18:TH,TM,JV
+3.8.19:TH,TM,JV
+3.8.20:TH,BB,GU,QU;TH,JV;TH,QU;TH,BB,GU,QU,JV,TM;TH,JV;TH,TM;TH,JA
+3.8.21:TH,JA,BB;TM,TH,JA;JA,BB,GU,QU,MO;JA,JV
+3.8.22:BU,GA
+4.1.1
+4.1.2
+4.1.3:LP
+4.1.4:LP
+4.1.5
+4.1.6:EN,CM,CR,GT
+4.2.1:MA
+4.2.2
+4.2.3:MM,EP
+4.2.4:MA,EP
+4.3.1:JV
+4.3.2:JV
+4.3.3
+4.3.4:JV,CO
+4.3.5:JV,CO
+4.3.6:CO,MA
+4.3.7:JV,CO
+4.3.8:JV,CO
+4.4.1:JV,CO
+4.4.2:MM,PL;MO,JV
+4.5.1:CO,TG
+4.5.2:JV,CO
+4.5.3:CO,TS
+4.5.4:MA
+4.5.5:CO
+4.5.6:CO,MA
+4.6.1:TM,MN
+4.6.2:GA,XA,XB;GA,MO;GA,XA,XB
+4.6.3:BB,BJ,GU,TH;BB,BJ,GU,TH,GA
+4.7.1
+4.7.2
+4.7.3
+4.7.4
+4.8.1:CO,MA
+4.8.2:CO,MA
+4.8.3:MA,CR;MA,CO;MA,EP
+4.8.4:EP,BB,BJ,GU,TH,QU,MO
+4.8.5
+4.8.6:MA,CO
+4.8.7:GI,MG;GI,MA
+4.9.1:JV
+4.9.2:MA,CR;MA,EP
+4.9.3:MM,PL
+4.10.1
+4.10.2
+4.10.3
+4.10.4
+4.10.5
+4.11.1:GA
+4.11.2:GA
+4.11.3:GA
+4.11.4:CM,GA,CR,BA
+4.11.5:CM,CR,BA,MM
+4.11.6:CR,EP
+4.12.1:HL
+4.12.2:BO,JO,GT,HL
+4.12.3:GA,BA,CR,BO,EN,FE,JO,GT,JP
+4.12.4:BA,CR,HL,GA,EN
+4.12.5:CR,EN
+4.12.6:EN,CM,CR,JP,FE,BO,JO,BA
+4.12.7:EN,JA;GA,JA;EN,JA
+4.12.8:QU,EN;EN,CM,JP
+4.13.1:MA
+4.13.2
+4.13.3:MA
+4.14.1:EN,CM,GA;EN,CM,CR,BO,JO,BA,GA,FE,MM
+4.14.2:MM
+4.14.3:EN,JA;CR,EN,JP;CM,JO,BA,BO,GA,MA
+4.14.4:MA
+4.14.5:MA,CR,CM,BO,GA,EN;EN,JA
+4.14.6:MA,EP
+4.14.7:MA,GA
+4.15.1:JA,CO,TS;JV,TS
+4.15.2:JV,GA
+4.15.3:JV
+4.15.4:GA
+5.1.1
+5.1.2:EN,CM,CR,FE,JO,BO
+5.1.3:EN
+5.1.4:EN,CM,MA;MA,JV,EN
+5.1.5:EN
+5.1.6:EN,JA;EN,JA,JV
+5.1.7:EN,BO,CR,CM;EN,BO,CR,CM,GA
+5.1.8:MA,GA;EN,CM
+5.1.9:EN,JV
+5.1.10:CO
+5.1.11:EN,GA;BO,JV
+5.1.12:EN
+5.1.13:EN,CR
+5.1.14:CR,BO;BO,EN
+5.1.15:GA,CR
+5.1.16:XA,XB
+5.1.17:EN,CM,CR
+5.1.18:EN,CM,BO,CR,FE;EN,JV;JV,JA
+5.1.19:JV,JA;MA,EN
+5.1.20
+5.1.21:EN,MA,CR,BO,FE,CM,JO
+5.1.22:EN
+5.1.23:EN,GT
+5.1.24:JV,MA
+5.2.1
+5.2.2
+5.2.3:BS
+5.2.4:BS
+5.2.5
+5.2.6
+5.3.1:JV,MA
+5.3.2:JV,MA
+5.3.3:JA,TH
+5.3.4:JV,MA
+5.3.5:JV,MA
+5.3.6:JV,MA
+5.3.7:JV,MA
+5.3.8:JV,TH
+5.3.9:JV,JA
+5.3.10:JV,JA
+5.3.11:JV,JA
+5.3.12:GI,MA
+5.4.1:JA
+5.5.1:BZ
+5.5.2:MA
+5.5.3:MA,GI
+5.5.4:CO,MA,GI,JV,MG
+5.5.5:JV
+5.5.6:GI,MA,CO
+5.5.7:MA,JV
+5.5.8:MA,JV
+5.6.1:MA,GI;MA,CO;TH,AZ
+5.6.2:MA,CO,JV,GI,MG
+5.6.3:JV
+5.7.1:MA,JV;MA,JV,CO;MA,JV
+5.7.2:MA
+5.8.1:JV,CO
+5.8.2:JV,CO
+5.8.3:JV,CO
+5.8.4:JV
+5.9.1:MA,CO
+5.9.2:JV
+5.9.3:JV
+5.9.4:MA,TH;MA,CO
+5.9.5:JV,CO,MA
+5.9.6
+* End of file "jean.dat"
diff --git a/support/graphbase/ladders.w b/support/graphbase/ladders.w
new file mode 100644
index 0000000000..4c715feeb3
--- /dev/null
+++ b/support/graphbase/ladders.w
@@ -0,0 +1,405 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{LADDERS}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisites{GB\_WORDS}{GB\_\thinspace DIJK}
+@* Introduction. This demonstration program uses graphs
+constructed by the |gb_words| module to produce
+an interactive program called \.{ladders}, which finds shortest paths
+between two given five-letter words of English.
+
+The program assumes that \UNIX\ conventions are being used. Some code in
+sections listed under `\UNIX\ dependencies' in the index may need to change
+if this program is ported to other operating systems.
+
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+To run the program under \UNIX, say `\.{ladders} \<options>', where \<options>
+consists of zero or more of the following specifications in any order:
+
+{\narrower
+\def\\#1 {\smallskip\noindent
+ \hbox to 6em{\tt#1\hfill}\hangindent 8em\hangafter1 }
+\\-v Verbosely print all words encountered during the shortest-path computation,
+ showing also their distances from the goal word.
+\\-a Use alphabetic distance instead of considering adjacent words to be one
+ unit apart; for example, the alphabetic distance from `\.{words}' to
+ `\.{woods}' is~3, because `\.r' is three places from `\.o' in the
+ alphabet.
+\\-f Use distance based on frequency (see below), instead of considering
+ adjacent words to be one unit apart. This option is ignored if \.{-a}
+ has been specified or if \.{-r} has been specified.
+\\-h Use a lower-bound heuristic to shorten the search (see below). This option
+ is ignored if option \.{-f} has been selected.
+\\-e Echo the input to the output (useful if input comes from a file instead
+ of from the terminal).
+\\-n\<number> Limit the graph to the |n| most common English words, where |n| is
+ the given \<number>.
+\\-r\<number> Limit the graph to \<number> randomly selected words. This option
+ is incompatible with~\.{-n}.
+\\-s\<number> Use \<number> instead of 0 as the seed for random numbers, to get
+ different random samples or to explore words of equal frequency in
+ a different order.
+\smallskip}
+\noindent Option \.{-f} assigns a cost of 0 to the most common words and a
+cost of 16 to the least common words; a cost between 0 and~16 is assigned to
+words of intermediate frequency. The word ladders found will then have
+minimum total cost by this criterion.
+\smallskip
+Option \.{-h} attempts to focus the search by giving priority to words that
+are near the goal. (More precisely, it modifies distances between adjacent
+words by using a heuristic function $\\{hh}(v)$, which would be the shortest
+possible distance between |v| and the goal if every five-letter combination
+happened to be an English word.) The |gb_dijk| module explains more about
+such heuristics; this option is most interesting to watch when used in
+conjunction with \.{-v}.
+
+@ The program will prompt you for a starting word. If you simply type \<return>,
+it exits; otherwise you should enter a five-letter word (with no uppercase
+letters) before typing \<return>.
+
+Then the program will prompt you for a goal word. If you simply type
+\<return> at this point, it will go back and ask for a new starting word;
+otherwise you should specify another five-letter word.
+
+Then the program will find and display an optimal word ladder from the start
+to the goal, if there is a path from one to the other
+that changes only one letter at a time.
+
+And then you have a chance to start all over again, with another starting word.
+
+The start and goal words need not be present in the program's graph of
+``known'' words. They are temporarily added to that graph, but removed
+again whenever new start and goal words are given. If the \.{-f} option is
+being used, the cost of the goal word will be 20 when it is not in the
+program's dictionary.
+
+@ We use the data types \&{Vertex}, \&{Arc}, and \&{Graph}
+defined in |gb_graph|.
+
+@f Vertex int
+@f Arc int
+@f Graph int
+
+@ Here is the general layout of this program, as seen by the \Cee\ compiler:
+@^UNIX dependencies@>
+
+@p
+#include <ctype.h> /* system file for character types */
+#include "gb_graph.h" /* the standard GraphBase data structures */
+#include "gb_words.h" /* routines for five-letter word graphs */
+#include "gb_dijk.h" /* routines for shortest paths */
+@#
+@<Global variables@>@;
+@<Subroutines@>@;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{
+ @<Scan the command line options@>;
+ @<Set up the graph of words@>;
+ while(1) {
+ @<Prompt for starting word and goal word; |break| if none given@>;
+ @<Find a minimal ladder from |start| to |goal|, if one exists,
+ and print it@>;
+ }
+}
+
+@* Parsing the options. Let's get the \UNIX\ command-line junk out of the
+way first, so that we can concentrate on meatier stuff. Our job in this part
+of the program is to see if the default value zero of external variable
+|verbose| should change, and/or if the default values of any of the following
+internal variables should change:
+
+@<Global variables@>=
+char alph=0; /* nonzero if the alphabetic distance option is selected */
+char freq=0; /* nonzero if the frequency-based distance option is selected */
+char heur=0; /* nonzero if the heuristic search option is selected */
+char echo=0; /* nonzero if the input-echo option is selected */
+unsigned n=0; /* maximum number of words in the graph (0 means infinity) */
+char rand=0; /* nonzero if we will ignore the weight of words */
+long seed=0; /* seed for random number generator */
+
+@ @<Scan the command line options@>=
+while (--argc) {
+@^UNIX dependencies@>
+ if (strcmp(argv[argc],"-v")==0) verbose=1;
+ else if (strcmp(argv[argc],"-a")==0) alph=1;
+ else if (strcmp(argv[argc],"-f")==0) freq=1;
+ else if (strcmp(argv[argc],"-h")==0) heur=1;
+ else if (strcmp(argv[argc],"-e")==0) echo=1;
+ else if (sscanf(argv[argc],"-n%u",&n)==1) rand=0;
+ else if (sscanf(argv[argc],"-r%u",&n)==1) rand=1;
+ else if (sscanf(argv[argc],"-s%ld",&seed)==1) ;
+ else {
+ fprintf(stderr,"Usage: %s [-v][-a][-f][-h][-e][-nN][-rN][-sN]\n",argv[0]);
+ return -2;
+ }
+}
+if (alph || rand) freq=0;
+if (freq) heur=0;
+
+@*Creating the graph. The GraphBase |words| procedure will produce the
+five-letter words we want, organized in a graph structure.
+
+@d quit_if(x,c)
+ if (x) {
+ fprintf(stderr,
+ "Sorry, I couldn't build a dictionary (trouble code %d)!\n",c);
+ return c;
+ }
+
+@<Set up the graph of words@>=
+g=words(n,(rand? zero_vector: NULL), 0,seed);
+quit_if(g==NULL,panic_code);
+@<Confirm the options selected@>;
+@<Modify the edge lengths, if the |alph| or |freq| option was selected@>;
+@<Modify the priority queue algorithm, if unequal edge lengths are possible@>;
+
+@ @<Glob...@>=
+Graph *g; /* graph created by |words| */
+int zero_vector[9]; /* weights to use when ignoring all frequency information */
+
+@ The actual number of words may be decreased to the size of the GraphBase
+dictionary, so we wait until the graph is generated before confirming
+the user-selected options.
+
+@<Confirm the options selected@>=
+if (verbose) {
+ if (alph) printf("(alphabetic distance selected)\n");
+ if (freq) printf("(frequency-based distances selected)\n");
+ if (heur) printf("(lowerbound heuristic will be used to focus the search)\n");
+ if (rand) printf("(random selection of %d words with seed %d)\n",g->n,seed);
+ else printf("(the graph has %d words)\n",g->n);
+}
+
+@ The edges in a |words| graph normally have length 1, so we must change them
+if the user has selected |alph| or |freq|. The character position in which
+adjacent words differ is recorded in the |loc| field of each arc. The
+frequency of a word is stored in the |weight| field of its vertex.
+
+@d a_dist(k) (*(p+k)<*(q+k)? *(q+k)-*(p+k): *(p+k)-*(q+k))
+
+@<Modify the edge lengths, if the |alph| or |freq| option was selected@>=
+if (alph) {@+register Vertex *u;
+ for (u=g->vertices+g->n-1; u>=g->vertices; u--) {@+register Arc *a;
+ register char *p=u->name;
+ for (a=u->arcs; a; a=a->next) {register char *q=a->tip->name;
+ a->len = a_dist(a->loc);
+ }
+ }
+} else if (freq) {@+register Vertex *u;
+ for (u=g->vertices+g->n-1; u>=g->vertices; u--) {@+register Arc *a;
+ for (a=u->arcs; a; a=a->next)
+ a->len = freq_cost(a->tip);
+ }
+}
+
+@ The default priority queue algorithm of |dijkstra| is quite efficient
+when all edge lengths are~1. Otherwise we will change it to the
+alternative method that works best for edge lengths less than~128.
+
+@<Modify the priority queue algorithm...@>=
+if (alph || freq || heur) {
+ init_queue=init_128;
+ delete_min=delete_from_128;
+ enqueue=enqueue_128;
+ requeue=requeue_128;
+}
+
+@ The frequency has been computed with the default weights explained in the
+documentation of |words|; it is usually less than $2^{16}$.
+A word whose frequency is 0 costs~16; a word whose frequency is 1 costs~15;
+a word whose frequency is 2 or 3 costs~14; and the costs keeps decreasing
+by~1 as the frequency doubles, until we get down to a cost of~0.
+
+@<Sub...@>=
+int freq_cost(v)
+ Vertex *v;
+{@+register long acc=v->weight; /* the frequency, to be shifted right */
+ register k=16;
+ while (acc) k--, acc>>=1;
+ return (k<0? 0: k);
+}
+
+@* Minimal ladders. The guts of this program is a routine to compute shortest
+paths between two given words, |start| and |goal|.
+
+The |dijkstra| procedure does this, in any graph with nonnegative arc lengths.
+The only complication we need to deal with here is that |start| and |goal|
+might not themselves be present in the graph. In that case we want to add
+them, albeit temporarily.
+
+The conventions of |gb_graph| allow us to do the desired augmentation
+by creating a new graph |gg| whose vertices are borrowed from~|g|. The
+graph~|g| has space for two more vertices (actually for four), and any
+new memory blocks allocated for the additional arcs present in~|gg| will
+be freed later by the operation |gb_recycle(gg)| without confusion.
+
+@<Glob...@>=
+Graph *gg; /* clone of |g| with possible additional words */
+char start[6], goal[6];
+ /* \.{words} dear to the user's \.{heart}, plus |'\0'| */
+Vertex *uu, *vv; /* start and goal vertices in |gg| */
+
+@ @<Find a minimal ladder from |start| to |goal|...@>=
+@<Build the amplified graph |gg|@>;
+@<Let |dijkstra| do the hard work@>;
+@<Print the answer@>;
+@<Remove all traces of |gg|@>;
+
+@ @<Build the amplified graph |gg|@>=
+gg=gb_new_graph(0);
+quit_if(gg==NULL,20); /* out of memory */
+gg->vertices = g->vertices;
+gg->n = g->n;
+@<Put the |start| word into |gg|, and let |uu| point to it@>;
+@<Put the |goal| word into |gg|, and let |vv| point to it@>;
+if (gg->n==g->n+2) @<Check if |start| is adjacent to |goal|@>;
+quit_if(gb_alloc_trouble,21); /* out of memory */
+
+@ The |find_word| procedure returns |NULL| if it can't find the given word
+in the graph just constructed by |words|. In that case it has applied its
+second argument to every adjacent word. Hence the program logic here
+does everything needed to add a new vertex to~|gg| when necessary.
+
+@<Put the |start| word into |gg|, and let |uu| point to it@>=
+(gg->vertices+gg->n)->name = start; /* a tentative new vertex */
+uu=find_word(start,plant_new_edge);
+if (!uu)
+ uu = gg->vertices + gg->n++; /* recognize the new vertex and refer to it */
+
+@ @<Put the |goal|...@>=
+if (strncmp(start,goal,5)==0) vv=uu; /* avoid inserting a word twice */
+else {
+ (gg->vertices+gg->n)->name = goal; /* a tentative new vertex */
+ vv=find_word(goal,plant_new_edge);
+ if (!vv)
+ vv = gg->vertices + gg->n++; /* recognize the new vertex and refer to it */
+}
+
+@ @<Sub...@>=
+void plant_new_edge(v)
+ Vertex *v;
+{@+Vertex *u=gg->vertices+gg->n; /* the new edge runs from |u| to |v| */
+ gb_new_edge(u,v,1);
+ if (alph)
+ u->arcs->len=(u->arcs-1)->len=alph_dist(u->name,v->name);
+ else if (freq) {
+ u->arcs->len=20; /* adjust the arc length from |v| to |u| */
+ (u->arcs-1)->len=freq_cost(v); /* adjust the arc length from |u| to |v| */
+ }
+}
+
+@ The |alph_dist| subroutine calculates the alphabetic distance between
+arbitrary five-letter words, whether they are adjacent or not.
+
+@<Sub...@>=
+int alph_dist(p,q)
+ register char *p, *q;
+{
+ return a_dist(0)+a_dist(1)+a_dist(2)+a_dist(3)+a_dist(4);
+}
+
+@ There's a bug in the above logic that could be embarrassing,
+although it will come up only when a user is trying to be clever: The
+|find_word| routine knows only the words of~|g|, so it will fail to
+make any direct connection between |start| and |goal| if they happen
+to be adjacent to each other yet not in the original graph. We had
+better fix this, or else the ladder program will look stupid.
+
+@<Check if |start|...@>=
+if (hamm_dist(start,goal)==1) {
+ gg->n--; /* temporarily pretend |vv| hasn't been added yet */
+ plant_new_edge(uu); /* make |vv| adjacent to |uu| */
+ gg->n++; /* and recognize it again */
+}
+
+@ The Hamming distance between words is the number of character positions
+in which they differ.
+
+@d h_dist(k) (*(p+k)==*(q+k)? 0: 1)
+
+@<Sub...@>=
+int hamm_dist(p,q)
+ register char *p, *q;
+{
+ return h_dist(0)+h_dist(1)+h_dist(2)+h_dist(3)+h_dist(4);
+}
+
+@ OK, now we've got a graph in which |dijkstra| can operate.
+
+@<Let |dijkstra| do the hard work@>=
+if (!heur) min_dist=dijkstra(uu,vv,gg,NULL);
+else if (alph) min_dist=dijkstra(uu,vv,gg,alph_heur);
+else min_dist=dijkstra(uu,vv,gg,hamm_heur);
+
+@ @<Sub...@>=
+long alph_heur(v)
+ Vertex *v;
+{@+return alph_dist(v->name,goal);@+}
+@#
+long hamm_heur(v)
+ Vertex *v;
+{@+return hamm_dist(v->name,goal);@+}
+
+@ @<Glob...@>=
+long min_dist; /* length of the shortest ladder */
+
+@ @<Print the answer@>=
+if (min_dist<0) printf("Sorry, there's no ladder from %s to %s.\n",start,goal);
+else print_dijkstra_result(vv);
+
+@ Finally, we have to clean up our tracks. It's easy to remove all arcs
+from the new vertices of~|gg| to the old vertices of~|g|; it's a bit
+more tricky to remove the arcs from old to new. The loop here will also
+remove arcs properly between start and goal vertices, if they both
+belong to |gg| not~|g|.
+
+@<Remove all traces of |gg|@>=
+for (uu=g->vertices+gg->n-1; uu>=g->vertices+g->n; uu--) {@+register Arc *a;
+ for (a=uu->arcs; a; a=a->next) {
+ vv=a->tip; /* now |vv->arcs==a-1|, since arcs for edges come in pairs */
+ vv->arcs=vv->arcs->next;
+ }
+ uu->arcs=NULL; /* we needn't clear |uu->name| */
+}
+gb_recycle(gg); /* the |gg->data| blocks disappear, but |g->data| remains */
+
+@* Terminal interaction. We've finished doing all the interesting things;
+only one minor part of the program still remains to be written.
+
+@<Prompt for...@>=
+putchar('\n'); /* make a blank line for visual punctuation */
+restart: /* if we try to avoid this label,
+ the |break| command will be broken */
+if (prompt_for_five("Starting",start)!=0) break;
+if (prompt_for_five(" Goal",goal)!=0) goto restart;
+
+@ @<Sub...@>=
+int prompt_for_five(s,p)
+ char *s; /* string used in prompt message */
+ register char *p; /* where to put a string typed by the user */
+{@+register char *q; /* current position to store characters */
+ register int c; /* current character of input */
+ while (1) {
+ printf("%s word: ",s);
+ fflush(stdout); /* make sure the user sees the prompt */
+ q=p;
+ while (1) {
+ c=getchar();
+ if (c==EOF) return -1; /* end-of-file */
+ if (echo) putchar(c);
+ if (c=='\n') break;
+ if (!islower(c)) q=p+5;
+ else if (q<p+5) *q=c;
+ q++;
+ }
+ if (q==p+5) return 0; /* got a good five-letter word */
+ if (q==p) return 1; /* got just \<return> */
+ printf("(Please type five lowercase letters and RETURN.)\n");
+ }
+}
+
+@* Index. Finally, here's a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/miles.dat b/support/graphbase/miles.dat
new file mode 100644
index 0000000000..66c9d725c7
--- /dev/null
+++ b/support/graphbase/miles.dat
@@ -0,0 +1,701 @@
+* File "miles.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* Revised mileage data for highways in the United States and Canada, 1949
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 696,92046153)
+Youngstown, OH[4110,8065]115436
+Yankton, SD[4288,9739]12011
+966
+Yakima, WA[4660,12051]49826
+1513 2410
+Worcester, MA[4227,7180]161799
+2964 1520 604
+Wisconsin Dells, WI[4363,8977]2521
+1149 1817 481 595
+Winston-Salem, NC[3610,8025]131885
+927 729 2742 1289 494
+Winnipeg, MB[4988,9715]564473
+1611 686 1833 1446 550 1279
+Winchester, VA[3919,7816]20217
+1510 290 826 466 2641 1197 250
+Wilmington, NC[3424,7792]139238
+390 1823 214 1139 765 2956 1500 637
+Wilmington, DE[3975,7555]70195
+466 168 1618 430 934 299 2749 1305 345
+Williston, ND[4815,10362]13336
+1820 2027 1712 428 1813 888 2035 1061 663 1481
+Williamsport, PA[4125,7700]33401
+1718 172 567 201 1516 491 832 369 2647 1203 239
+Williamson, WV[3768,8228]5219
+504 1610 544 452 378 1408 240 724 843 2539 1071 353
+Wichita Falls, TX[3390,9849]94201
+1179 1500 1313 1574 1363 1432 1252 1246 1044 1848 1887 724 1284
+Wichita, KS[3769,9734]279835
+308 1002 1270 1068 1344 1360 1220 944 1192 748 1618 1774 416 1054
+Wheeling, WV[4007,8072]43070
+1017 1247 269 255 1513 327 589 203 1311 416 627 605 2442 998 85
+West Palm Beach, FL[2672,8005]63305
+1167 1550 1432 965 1249 2375 1160 718 1048 2175 760 1515 1459 3280 1794 1252
+Wenatchee, WA[4742,12032]17257
+3250 2390 1783 1948 2487 2595 1009 2697 2904 2589 1394 2690 1765 2912 117 1461
+2358
+Weed, CA[4142,12239]2879
+622 3229 2678 1842 1850 2717 2898 1473 2981 3128 2880 1858 2935 2213 3213 505
+1752 2659
+Waycross, GA[3122,8235]19371
+2947 2890 360 820 1192 1097 605 904 2015 828 386 703 1815 413 1155 1127
+2920 1434 899
+Wausau, WI[4496,8964]32426
+1240 2198 1725 1600 708 841 1138 805 913 848 1015 1222 907 646 1008 111
+1230 1777 509 676
+Waukegan, IL[4236,8783]67653
+244 1000 2260 1933 1360 468 757 1023 565 673 1056 775 982 667 854 768
+170 990 1985 551 436
+Watertown, SD[4490,9711]15649
+601 393 1549 1824 1351 1909 1058 572 880 1155 1263 534 1365 1572 1257 394
+1358 433 1580 1403 156 1026
+Watertown, NY[4398,7592]27861
+1366 776 1016 1128 2999 2698 1473 471 1404 1634 738 234 1795 358 791 425
+1574 715 935 302 2750 1306 386
+Waterloo, IA[4250,9234]75985
+1008 373 253 305 1178 2007 1714 1538 700 537 833 795 905 857 1007 1214
+899 658 1000 212 1222 1766 298 668
+Waterbury, CT[4155,7305]103266
+1190 278 1548 958 1198 1034 3164 2880 1366 512 1527 1757 750 285 2003 206
+672 373 1801 636 1117 98 2932 1488 522
+Washington, DC[3889,7703]638432
+315 962 434 1320 730 970 719 2936 2652 1051 268 1285 1489 435 210 1775
+109 357 73 1573 321 889 408 2704 1260 300
+Warren, PA[4185,7914]12146
+326 428 769 291 1127 537 777 976 2760 2459 1321 198 1165 1395 465 172
+1582 305 663 273 1380 563 696 490 2511 1067 118
+Walla Walla, WA[4607,11833]25618
+2452 2645 2873 1707 2691 1344 1926 1718 2796 500 238 3156 2383 1650 1763 2480
+2588 1002 2690 2897 2582 1387 2683 1758 2905 132 1454 2351
+Waco, TX[3155,9714]101261
+1958 1452 1484 1799 921 1703 1043 1096 1226 1005 2026 2152 1330 1287 471 204
+1174 1540 1507 1593 1308 1427 1415 1227 1132 1892 2082 887 1338
+Vincennes, IN[3868,8753]20857
+892 2120 572 692 934 463 811 836 278 518 722 2347 2176 1082 424 627
+854 375 677 1300 751 827 620 1101 615 433 1025 2228 727 461
+Victoria, TX[2881,9701]50695
+1031 223 2104 1593 1578 1893 1144 1842 1266 1257 1349 1038 2114 2334 1330 1428
+694 411 1288 1681 1707 1687 1366 1521 1638 1319 1351 1986 2228 1110 1479
+Vicksburg, MS[3235,9088]25434
+530 556 419 2274 1110 1067 1382 890 1361 1138 800 1000 586 2361 2457 921
+945 705 511 800 1198 1663 1176 889 1010 1494 808 908 1475 2398 1000 996
+Vancouver, BC[4927,12312]414281
+2675 2505 2422 2359 409 2705 2898 3126 1960 2944 1597 2179 1971 3136 710 246
+3496 2636 2029 2164 2733 2841 1255 2943 3150 2835 1640 2936 2011 3158 277 1707
+2604
+Valley City, ND[4692,9801]7774
+1518 1327 1461 943 1238 1265 1225 1418 1646 500 1464 195 699 491 1658 1745
+1272 2018 1156 767 1075 1253 1361 357 1463 1670 1355 278 1456 531 1678 1324
+351 1124
+Valdosta, GA[3083,8328]37596
+1648 3126 542 975 712 961 2773 1039 782 1097 1168 1191 1539 990 1230 63
+2903 2880 386 883 1164 1053 655 967 2005 891 449 766 1805 476 1145 1190
+2897 1424 962
+Utica, NY[4311,7523]75632
+1157 1461 2941 1358 1839 808 1700 2688 282 389 201 1005 83 1363 773 1013
+1094 2996 2695 1439 462 1401 1631 711 207 1818 283 746 391 1616 681 932
+225 2747 1303 383
+Uniontown, PA[3990,7973]14510
+417 862 1221 2701 1014 1497 493 1356 2448 189 207 458 765 444 1123 533
+773 799 2746 2455 1146 69 1086 1316 294 210 1578 267 524 134 1376 386
+692 551 2507 1063 116
+Tyler, TX[3235,9530]70508
+1222 1566 827 1229 2402 285 326 758 134 2001 1318 1350 1665 884 1569 1040
+980 1166 871 2088 2186 1206 1153 469 238 1040 1406 1537 1459 1174 1293 1396
+1093 1074 1758 2125 885 1204
+Twin Falls, ID[4256,11447]26209
+1583 2101 2351 2355 1105 819 1856 1686 1702 1540 418 2115 2291 2521 1367 2354
+1184 1620 1558 2378 645 648 2738 2033 1232 1345 2074 2253 888 2336 2483 2235
+1316 2290 1573 2568 542 1112 2014
+Tuscaloosa, AL[3321,8757]75211
+1998 524 820 1162 387 1356 2772 239 750 483 658 2416 943 828 1143 861
+1194 1207 750 950 415 2557 2526 773 778 807 707 561 972 1713 937 656
+771 1515 569 858 1236 2540 1069 829
+Tupelo, MS[3426,8871]23905
+126 1872 486 813 1157 483 1230 2646 230 744 380 620 2290 909 891 1206
+735 1160 1081 624 824 511 2486 2400 869 744 681 662 624 997 1587 1000
+747 834 1389 663 732 1299 2414 943 795
+Tulsa, OK[3616,9591]360919
+535 661 1415 343 1047 1362 1018 891 2219 522 603 585 380 1833 1126 1246
+1488 564 1365 702 754 869 1046 2003 1973 1404 978 190 269 960 1231 1227
+1305 1261 1181 1058 1106 775 1579 1957 564 1015
+Tucson, AZ[3222,11097]330537
+1065 1520 1565 1049 1064 2101 2416 1879 1664 1841 1337 1009 1642 962 1457 2180
+2300 2542 1552 2419 1521 1772 1822 1923 1131 1687 2258 2032 1015 858 2017 2285
+1571 2359 2221 2235 1915 2104 1763 2633 1581 1365 2069
+Trinidad, CO[3717,10451]9663
+707 561 1085 1170 882 701 1501 1816 1516 1003 1701 974 857 1046 667 1300
+1580 1700 1942 901 1819 860 1146 1161 1560 1470 1502 1895 1432 449 463 1421
+1685 922 1759 1809 1635 1254 1641 1113 2033 1424 704 1469
+Trenton, NJ[4023,7477]92124
+1807 2407 1353 1060 997 2384 1519 315 247 951 1511 2991 1236 1747 799 1653
+2738 354 169 146 1055 322 1413 823 1063 888 3029 2745 1220 375 1392 1622
+604 182 1868 60 526 228 1666 490 982 239 2797 1353 393
+Traverse City, MI[4476,8563]15516
+844 1439 2039 1021 881 952 1935 1247 561 731 1167 852 2370 1057 1524 501
+1363 2117 558 751 932 591 673 828 359 435 1177 2580 2124 1537 496 1024
+1290 643 697 1170 796 1053 695 949 841 518 956 2176 889 460
+Toronto, ON[4365,7938]599217
+435 460 1620 2220 1180 1006 1053 2116 1380 373 296 1200 1228 2708 1182 1657
+626 1514 2455 195 509 497 772 238 1130 540 780 1159 2761 2462 1504 373
+1205 1449 640 306 1557 478 846 456 1336 746 699 521 2514 1070 288
+Topeka, KS[3905,9567]115266
+1051 870 1238 586 1186 232 647 773 1239 575 932 1247 1130 659 2032 701
+835 477 612 1657 1011 1131 1373 374 1250 470 603 679 1153 1884 1786 1513
+863 171 479 852 1116 995 1190 1258 1066 826 1072 585 1464 1781 332 900
+Toledo, OH[4165,8354]354635
+775 287 290 554 1344 1944 893 719 766 1848 1093 271 504 913 960 2440
+895 1370 339 1227 2187 268 461 686 504 507 862 272 512 923 2493 2194
+1283 206 929 1162 358 407 1317 506 768 405 1115 556 431 721 2246 802
+170
+Texarkana, TX[3343,9405]31271
+957 534 1244 1111 1383 740 1135 314 385 431 1622 136 1086 1430 782 1180
+2441 240 418 622 270 2040 1182 1214 1529 802 1433 991 844 1030 826 2127
+2225 1161 1017 465 277 904 1270 1516 1323 1086 1157 1347 971 938 1622 2164
+853 1068
+Terre Haute, IN[3947,8741]61125
+671 291 487 578 443 751 1056 1656 602 438 541 1684 807 445 760 770
+904 2383 614 1084 58 941 2102 524 644 886 429 763 797 225 465 780
+2329 2137 1140 376 641 871 415 629 1261 703 822 579 1062 633 384 977
+2189 694 413
+Tampa, FL[2795,8245]271523
+1003 981 1146 1354 1414 1400 1130 1715 2078 1242 707 589 2579 1026 1056 1349
+233 1881 3353 741 1144 945 1144 2997 1231 961 1276 1401 1383 1772 1223 1463
+264 3012 3107 217 1077 1388 1252 869 1159 2238 1070 628 958 2038 670 1375
+1369 3121 1650 1162
+Tallahassee, FL[3045,8428]81548
+245 796 736 939 1109 1226 1193 1033 1470 1833 997 462 344 2334 781 919
+1232 82 1674 3108 496 899 738 899 2752 1108 864 1179 1184 1266 1543 1016
+1256 145 2857 2862 431 919 1143 1007 688 1042 2031 973 531 841 1831 554
+1171 1272 2876 1405 1001
+Tacoma, WA[4724,12243]158501
+3014 3259 2295 2302 2352 1919 2620 2282 2903 1562 1666 2095 2552 2678 680 2263
+2613 2853 3035 1430 175 2536 2366 2334 2220 270 2617 2810 3038 1872 2856 1509
+2091 1883 3048 535 183 3408 2548 1912 2025 2645 2753 1167 2855 3062 2747 1552
+2848 1923 3070 138 1619 2516
+Syracuse, NY[4305,7615]170105
+2802 1195 1312 709 1379 453 1196 249 684 251 1765 2365 1311 1106 1125 2300
+1515 373 51 1120 1410 2890 1307 1788 757 1649 2637 231 363 248 954 71
+1312 722 962 1057 2945 2644 1402 417 1350 1580 667 163 1767 287 720 354
+1565 644 881 272 2696 1252 332
+Swainsboro, GA[3260,8234]7602
+952 2986 250 369 714 819 821 1091 1054 1075 791 1552 1916 1002 479 388
+2316 864 694 989 168 1596 3074 579 1090 656 998 2734 871 622 937 1116
+1023 1487 927 1167 105 2940 2828 465 715 1158 1090 500 799 1953 731 344
+598 1749 308 1086 1030 2858 1372 794
+Sumter, SC[3392,8035]24890
+187 805 2969 410 507 715 929 732 1151 907 1017 624 1654 2064 1104 590
+499 2376 1017 557 842 328 1577 3057 732 1243 674 1151 2794 724 455 770
+1117 876 1479 889 1129 265 3021 2811 597 592 1250 1206 416 652 1932 564
+157 451 1732 185 1059 863 2863 1393 665
+Stroudsburg, PA[4099,7519]5148
+666 829 182 2871 1072 1172 744 1388 525 1231 391 815 69 1800 2400 1346
+1065 1002 2371 1524 316 178 993 1479 2959 1241 1752 792 1658 2706 290 211
+167 1023 253 1381 791 1031 930 3016 2713 1262 371 1385 1615 609 124 1836
+105 568 231 1634 521 950 255 2765 1321 357
+Stockton, CA[3796,12129]149779
+2909 2793 2678 2838 818 2595 2840 2222 1865 2386 1777 2654 2473 2922 1329 848
+1745 2224 2295 637 1826 2639 2889 2641 1742 993 2099 1831 2240 1764 783 2653
+2829 3057 1923 2892 1777 2168 2157 2685 283 905 3020 2571 1674 1588 2610 2791
+1525 2874 2950 2773 1953 2795 2135 3106 788 1675 2552
+Stevens Point, WI[4452,8957]22970
+2174 998 1096 1134 929 1900 1223 1430 432 997 479 646 747 462 1030 1166
+1824 836 791 917 1575 1133 740 980 1197 508 1988 967 1382 485 1193 1735
+744 937 1165 272 983 410 211 33 1207 2215 1742 1567 675 809 1105 772
+880 865 982 1189 874 663 975 78 1197 1794 523 643
+Steubenville, OH[4036,8062]26400
+675 2567 356 614 740 392 2548 944 1102 391 1032 206 878 348 496 365
+1447 2047 993 759 793 2029 1168 72 443 908 1156 2636 960 1443 439 1302
+2383 173 272 500 700 446 1058 468 708 845 2674 2390 1192 25 1032 1262
+294 238 1513 317 589 206 1311 441 627 593 2442 998 60
+Sterling, CO[4062,10322]11385
+1308 933 1299 1650 1633 1573 1579 1441 1591 1836 952 927 1127 488 1395 1214
+1663 278 977 675 1129 1255 761 889 1375 1630 1612 727 1580 1149 1045 959
+855 1179 1394 1570 1798 664 1633 596 909 922 1635 1406 1338 1995 1306 485
+651 1334 1532 662 1615 1740 1509 990 1554 876 1847 1303 440 1293
+Staunton, VA[3815,7907]21857
+1525 266 914 2790 324 367 505 447 2787 748 867 595 1064 454 1082 549
+744 319 1651 2197 1193 741 678 2252 1200 210 484 673 1395 2875 917 1428
+608 1334 2622 366 150 465 939 518 1297 707 944 610 2897 2629 957 248
+1235 1339 285 294 1752 259 350 93 1550 197 866 558 2681 1237 326
+Springfield, OH[3992,8381]72563
+401 1132 189 532 2397 542 624 694 514 2405 812 1019 202 868 127 689
+414 412 549 1258 1858 804 600 639 1859 1004 243 565 786 1013 2493 796
+1279 250 1138 2240 325 442 684 557 568 915 325 565 799 2504 2247 1156
+174 843 1073 250 427 1370 501 660 377 1168 448 484 777 2299 855 211
+Springfield, MO[3722,9329]133116
+607 996 726 796 695 1942 1149 972 880 1114 2149 865 1110 405 374 696
+244 983 824 1156 727 1262 199 403 529 1469 471 850 1165 886 867 2243
+460 762 388 539 1887 929 1049 1291 454 1168 678 557 728 914 2114 1997
+1272 781 278 468 763 1034 1203 1108 1082 984 1034 914 622 1382 2011 540
+818
+Springfield, MA[4210,7259]152319
+1336 735 516 1803 551 1151 3062 208 821 988 228 3026 1230 1327 937 1580
+677 1420 475 910 197 1989 2589 1535 1257 1194 2524 1716 509 181 1148 1634
+3114 1433 1944 979 1850 2861 450 366 56 1176 258 1531 944 1184 1085 3169
+2868 1417 563 1574 1804 801 322 1991 257 723 424 1787 687 1103 50 2920
+1474 556
+Springfield, IL[3980,8965]100054
+1053 335 323 716 809 512 375 2088 865 842 821 829 2178 885 1106 143
+622 394 381 670 489 872 950 1550 532 438 564 1550 758 566 880 873
+793 2266 614 1035 168 874 1967 644 765 1007 310 883 683 222 408 883
+2194 2020 1243 497 535 801 536 750 1150 824 949 700 951 754 316 1097
+2072 559 534
+Spokane, WA[4767,11741]171300
+1853 2701 1830 2080 2462 1171 2223 1575 914 2546 2644 2661 2477 325 2695 2940
+1970 2058 2027 1619 2295 1957 2578 1335 1563 1806 2233 2359 538 2019 2288 2528
+2713 1105 413 2290 2175 2009 1985 160 2292 2485 2713 1547 2531 1184 1766 1558
+2723 660 167 3083 2223 1616 1781 2320 2428 842 2530 2737 2422 1227 2523 1598
+2745 219 1294 2191
+South Bend, IN[4168,8625]109727
+1881 257 824 591 211 593 983 346 333 2242 667 803 831 598 2206 938
+1145 188 859 148 638 414 260 700 1207 1807 788 626 705 1704 995 411
+649 912 814 2294 802 1272 246 1129 2041 413 607 834 358 650 716 126
+366 922 2349 2048 1282 354 792 1057 451 549 1171 652 866 545 969 654
+285 868 2100 656 312
+Sioux Falls, SD[4354,9673]81343
+640 1278 580 1460 561 839 1221 522 982 441 1745 1305 1399 1393 1236 1603
+1426 1671 715 874 786 353 1054 862 1337 786 1447 585 964 1090 1182 923
+1047 1287 1445 312 1691 1021 1165 748 942 1438 1051 1244 1472 289 1290 117
+535 427 1455 1822 1445 1815 982 471 779 1077 1187 647 1289 1496 1181 489
+1282 399 1504 1497 82 950
+Sioux City, IA[4249,9639]82003
+88 589 1361 492 1407 473 788 1170 464 931 475 1699 1254 1326 1305 1185
+1686 1338 1583 627 786 735 265 1003 822 1286 703 1364 497 876 1002 1136
+835 996 1236 1357 394 1774 933 1077 660 854 1521 1000 1193 1421 231 1239
+205 484 458 1367 1776 1528 1727 931 383 691 1004 1136 730 1238 1433 1130
+561 1222 437 1453 1580 67 899
+Shreveport, LA[3251,9375]205820
+859 947 915 2106 678 1619 434 922 1103 976 1086 1053 1913 1427 918 765
+1431 2350 682 927 727 73 1013 607 1300 1167 1422 788 1151 386 387 425
+1670 99 1140 1482 728 1253 2489 186 357 674 233 2088 1236 1253 1568 875
+1485 1064 900 1086 772 2175 2273 1107 1071 528 325 958 1324 1589 1362 1075
+1196 1420 994 994 1661 2212 926 1122
+Sherman, TX[3364,9661]30413
+216 709 797 967 1898 711 1712 376 983 1224 768 1172 1030 1705 1525 1089
+979 1490 2142 896 1141 781 160 1072 449 1359 1200 1532 580 975 217 545
+591 1462 135 1226 1541 942 1103 2281 400 386 764 163 1880 1305 1374 1667
+758 1544 914 933 1063 986 1967 2065 1321 1157 343 117 1064 1410 1411 1483
+1246 1317 1270 1131 969 1758 2004 759 1194
+Sheridan, WY[4480,10696]15146
+1218 1425 693 635 1275 704 1180 2095 1133 1474 1856 470 1617 1028 1291 1940
+2019 1980 1871 1029 1998 2243 1320 1362 1421 915 1689 1446 1972 661 1238 1102
+1536 1662 660 1339 1682 1922 2019 676 1117 1593 1495 1348 1305 864 1686 1879
+2107 924 1925 618 1170 1011 2042 1300 871 2402 1617 912 1101 1692 1822 502
+1924 2121 1816 903 1910 1034 2139 923 651 1585
+Seminole, OK[3523,9668]8590
+1113 127 312 582 670 883 1814 627 1628 292 899 1218 678 1088 931 1688
+1441 1123 1021 1406 2083 985 1230 697 249 988 327 1275 1116 1448 549 1008
+95 554 679 1403 253 1142 1457 1031 976 2222 489 513 680 290 1821 1221
+1341 1583 659 1460 787 849 964 1065 1950 1981 1410 1073 216 180 1055 1326
+1284 1400 1280 1276 1143 1125 870 1674 1945 632 1110
+Selma, AL[3242,8702]26684
+745 1747 656 442 1087 1174 760 2444 649 1237 614 682 721 1340 836 1002
+2355 1045 476 323 1168 2763 259 504 596 496 809 858 1096 1007 1040 1230
+1593 746 211 85 2083 541 863 1205 302 1441 2857 256 767 538 675 2501
+986 871 1186 946 1214 1291 816 1035 330 2617 2611 688 821 892 767 604
+1015 1798 980 633 814 1600 565 943 1279 2625 1154 872
+Sedalia, MO[3871,9323]20927
+710 393 1046 477 549 386 474 513 1743 257 1289 115 558 951 639 747
+593 1920 1100 999 934 1065 2062 961 1206 356 489 647 157 927 746 1107
+726 1309 298 499 625 1382 586 801 1116 982 768 2156 575 863 345 640
+1800 880 1000 1242 339 1119 582 479 626 996 2027 1910 1356 732 294 567
+720 985 1116 1059 1106 935 936 938 515 1333 1924 453 769
+Seattle, WA[4760,12233]493846
+2038 2739 2093 999 2152 2360 1656 1573 2176 295 2148 2996 2125 2375 2757 1451
+2518 1870 848 2841 2939 2956 2772 30 2990 3235 2265 2312 2322 1914 2590 2252
+2873 1572 1696 2101 2528 2654 690 2273 2583 2823 3008 1400 145 2546 2376 2304
+2230 280 2587 2780 3008 1842 2826 1479 2061 1853 3018 565 153 3378 2518 1911
+2035 2615 2723 1137 2825 3032 2717 1522 2818 1893 3040 148 1589 2486
+Scranton, PA[4141,7567]88117
+2816 1078 1054 1419 1915 1503 1417 1229 1280 642 2521 843 229 1127 520 333
+1625 331 973 2884 42 691 838 140 2846 1081 1198 722 1363 500 1209 349
+784 111 1778 2378 1324 1074 1011 2346 1499 303 154 1006 1454 2934 1250 1761
+770 1633 2681 248 248 192 998 211 1356 766 1006 943 2991 2688 1288 346
+1363 1593 597 93 1811 147 605 240 1609 530 925 276 2740 1296 332
+Scottsbluff, NB[4187,10366]14156
+1666 1343 702 1403 769 344 885 1081 483 529 1024 1048 869 1844 789 1179
+1572 126 1349 958 1262 1691 1696 1636 1620 1373 1654 1899 1004 1018 1168 571
+1436 1255 1704 404 1073 758 1192 1318 724 1011 1421 1671 1675 657 1461 1249
+1171 1022 981 1142 1435 1611 1839 705 1674 561 950 941 1698 1369 1215 2058
+1353 568 777 1392 1573 566 1656 1803 1555 919 1610 917 1888 1266 459 1334
+Schenectady, NY[4282,7395]67972
+1742 191 2894 1187 1220 1528 1993 1612 1553 1307 1358 720 2599 951 106 1236
+636 499 1701 485 1051 2960 175 841 1004 126 2924 1247 1347 831 1501 575
+1318 374 809 217 1887 2487 1433 1228 1177 2422 1637 457 78 1168 1532 3012
+1416 1910 879 1771 2759 344 386 126 1076 152 1434 844 1084 1105 3067 2766
+1437 502 1472 1702 751 247 1889 277 743 406 1687 696 1003 150 2818 1374
+454
+Savannah, GA[3208,8109]141634
+996 1726 847 3034 1024 413 1111 2070 1069 855 1395 1483 898 2739 911 976
+970 754 516 1663 751 1191 2768 821 156 94 961 3064 254 351 808 909
+866 1181 1063 1132 779 1642 2006 1092 569 478 2406 954 705 998 172 1672
+3152 669 1147 750 1088 2824 880 610 925 1206 1032 1574 984 1224 109 3030
+2906 441 726 1248 1180 550 808 2029 719 277 607 1827 319 1143 1018 2948
+1462 811
+Sault Sainte Marie, MI[4649,8435]14448
+1268 899 1293 874 2142 903 1147 1258 1355 1357 1310 810 779 400 1847 646
+1000 981 539 866 1265 618 379 2484 916 1144 1211 774 2172 1329 1536 583
+1254 412 973 525 170 966 1502 2151 1163 1021 1092 1847 1390 683 821 1303
+742 2260 1197 1667 641 1520 2007 680 863 1022 607 763 737 454 352 1313
+2487 2014 1673 618 1136 1432 770 819 1060 918 1180 817 839 968 423 1046
+2066 861 582
+Sarasota, FL[2734,8253]48868
+1589 404 1397 1952 1251 3288 1259 557 1283 2296 1194 980 1636 1724 1198 2993
+1159 1380 1163 1072 920 1889 1155 1483 2893 1225 560 422 1365 3312 298 53
+1056 1034 1199 1407 1467 1453 1183 1768 2131 1295 760 642 2632 1079 1109 1402
+286 1934 3406 794 1197 998 1197 3050 1284 1014 1329 1454 1436 1825 1276 1516
+317 3065 3160 198 1130 1441 1305 922 1212 2291 1123 681 1011 2091 723 1428
+1422 3174 1703 1215
+Santa Rosa, CA[3844,12272]83320
+3010 2547 2885 3023 1325 2947 876 1983 2472 1805 1354 1822 2030 1762 1808 2305
+945 2151 3125 2050 2460 2853 1362 2630 2237 126 2972 2910 2795 2901 846 2712
+2957 2285 1982 2449 1840 2717 2536 2985 1400 965 1862 2341 2412 700 1943 2702
+2952 2758 1805 1021 2216 1948 2303 1881 814 2716 2892 3120 1986 2955 1840 2231
+2220 2802 314 936 3137 2634 1772 1705 2673 2854 1588 2937 3067 2836 2016 2891
+2198 3169 819 1738 2615
+Santa Fe, NM[3568,10595]48953
+1254 1810 1695 1685 2063 590 1954 1549 885 1272 605 827 622 830 896 979
+1383 1370 1126 2165 841 1434 1805 471 1623 1359 1137 1976 1710 1595 1941 1539
+1512 1757 1232 782 1520 762 1796 1615 1983 193 523 662 1141 1212 859 743
+1677 1992 1558 1196 1678 1016 827 1218 681 1277 1756 1876 2118 1094 1995 1053
+1339 1354 1602 1399 1507 1937 1608 591 505 1593 1861 1088 1935 1867 1811 1447
+1712 1306 2209 1401 897 1645
+Santa Barbara, CA[3442,11970]74414
+953 396 2709 2612 2584 2962 1365 2853 1199 1784 2171 1504 1394 1521 1732 1802
+1848 2282 1265 2025 3064 1758 2333 2704 1371 2522 2277 366 2875 2609 2494 2840
+1169 2411 2656 2131 1681 2419 1661 2695 2514 2882 1146 607 1561 2040 2111 871
+1642 2576 2891 2457 1938 1344 1915 1590 2117 1543 1134 2655 2775 3017 2026 2894
+1880 2247 2260 2501 634 1256 2836 2507 1490 1407 2492 2760 1759 2834 2766 2710
+2165 2611 2238 3108 1139 1778 2544
+Santa Ana, CA[3376,11787]204023
+128 850 489 2606 2518 2481 2859 1271 2750 1220 1681 2068 1401 1300 1418 1626
+1708 1754 2179 1286 1922 2961 1655 2230 2601 1277 2419 2183 372 2772 2506 2391
+2737 1190 2308 2553 2028 1578 2316 1558 2592 2411 2779 1043 504 1458 1937 2008
+843 1539 2473 2788 2354 1844 1365 1812 1487 2014 1440 1144 2552 2672 2914 1924
+2791 1786 2144 2166 2398 655 1277 2733 2404 1387 1301 2389 2657 1670 2731 2663
+2607 2071 2508 2135 3005 1160 1684 2441
+San Jose, CA[3734,12188]629546
+395 294 1160 102 2916 2564 2791 3040 1342 2964 905 1991 2378 1711 1371 1728
+1936 1779 1825 2322 971 2168 3142 1965 2477 2870 1379 2647 2254 80 2989 2816
+2701 2918 875 2618 2863 2302 1888 2466 1857 2734 2553 3002 1353 871 1768 2247
+2318 717 1849 2719 2969 2664 1822 1050 2122 1854 2320 1787 840 2733 2909 3137
+2003 2972 1857 2248 2237 2708 340 962 3043 2651 1697 1611 2690 2871 1605 2954
+2973 2853 2033 2818 2215 3186 845 1755 2632
+San Francisco, CA[3778,12242]678974
+47 434 341 1199 55 2955 2538 2830 3014 1316 2938 870 1974 2417 1750 1345
+1767 1975 1753 1799 2296 936 2142 3116 2004 2451 2844 1353 2621 2228 84 2963
+2855 2740 2892 840 2657 2902 2276 1927 2440 1831 2708 2527 2976 1391 910 1807
+2286 2357 691 1888 2693 2943 2703 1796 1015 2161 1893 2294 1826 805 2707 2883
+3111 1977 2946 1831 2222 2211 2747 305 927 3082 2625 1736 1650 2664 2845 1579
+2928 3012 2827 2007 2857 2189 3160 810 1729 2606
+Sandusky, OH[4145,8271]31360
+2493 2519 2341 2444 1545 2502 1198 466 840 521 1221 456 2373 669 809 1010
+1472 1094 1035 786 837 201 2078 433 627 718 128 410 1180 162 530 2439
+481 706 815 399 2403 938 1145 313 980 54 800 341 344 511 1369 1969
+915 728 766 1901 1116 227 450 912 1011 2491 917 1392 361 1250 2238 214
+417 642 555 453 913 323 563 920 2546 2245 1280 162 954 1184 332 363
+1368 463 742 361 1166 530 482 667 2297 853 125
+San Diego, CA[3271,11715]875538
+2355 524 485 90 213 877 579 2554 2537 2429 2873 1347 2764 1310 1695 2016
+1415 1376 1398 1574 1750 1830 2193 1376 1936 2975 1651 2244 2615 1318 2433 2210
+462 2786 2487 2339 2751 1280 2256 2501 2042 1558 2330 1572 2606 2425 2793 1070
+423 1472 1943 1988 919 1487 2487 2802 2302 1920 1455 1760 1432 2028 1385 1227
+2566 2686 2928 1938 2805 1862 2158 2208 2346 745 1367 2681 2418 1401 1281 2403
+2671 1746 2745 2644 2621 2147 2522 2149 3019 1250 1751 2455
+San Bernardino, CA[3411,11731]118794
+130 2297 450 411 54 152 806 505 2562 2464 2437 2815 1217 2706 1236 1637
+2024 1357 1246 1374 1582 1654 1700 2135 1257 1878 2917 1611 2186 2557 1223 2375
+2129 388 2728 2462 2347 2693 1206 2264 2509 1984 1534 2272 1514 2548 2367 2735
+999 460 1414 1893 1964 789 1495 2429 2744 2310 1790 1381 1768 1443 1970 1396
+1097 2508 2628 2870 1878 2747 1732 2100 2112 2354 671 1293 2689 2360 1343 1257
+2345 2613 1616 2687 2619 2563 2017 2464 2090 2961 1176 1630 2397
+San Antonio, TX[2942,9850]786023
+1330 1319 1412 1780 1741 1374 1477 728 1835 1272 1659 1222 1933 1073 1795 2277
+821 832 471 1397 344 390 1030 1118 1291 2077 1054 2009 720 1300 1493 947
+1464 1340 1718 1817 1308 1155 1811 2267 974 1219 1103 432 1389 793 1676 1543
+1812 759 896 561 777 815 1587 314 1518 1862 1050 1414 2406 576 113 1054
+181 2005 1614 1643 1958 1102 1865 1219 1276 1307 1113 2001 2235 1405 1449 647
+339 1336 1702 1609 1752 1441 1586 1591 1384 1313 2051 2129 1063 1500
+San Angelo, TX[3146,10044]73240
+218 1168 1157 1418 1618 1579 1212 1315 510 1673 1425 1666 1308 1936 869 1818
+2059 801 895 414 1193 326 453 925 1013 1291 1873 1035 2035 700 1307 1519
+743 1487 1339 1556 1843 1371 1218 1814 2049 1127 1372 1105 455 1396 713 1683
+1524 1838 555 734 503 840 878 1369 354 1541 1865 1181 1309 2188 639 331
+1073 228 1787 1629 1669 1984 1067 1868 1114 1257 1372 1225 1839 2017 1558 1472
+542 234 1359 1725 1405 1778 1528 1612 1486 1426 1278 2077 1911 958 1518
+Salt Lake City, UT[4076,11188]163697
+1133 1351 681 811 1731 762 788 735 829 623 771 2414 1801 2236 2252 554
+2176 926 1212 1876 1167 583 1226 1434 991 1037 1534 747 1380 2354 1296 1689
+2082 591 1859 1466 708 2201 2206 2146 2130 916 2116 2361 1514 1386 1678 1069
+1946 1765 2214 646 816 1179 1699 1816 236 1347 1931 2181 2162 1127 1055 1620
+1450 1532 1304 654 1945 2121 2349 1215 2184 1069 1460 1449 2206 832 884 2540
+1863 1018 1109 1902 2083 935 2166 2313 2065 1354 2120 1427 2398 778 967 1844
+Salisbury, MD[3837,7560]16429
+2269 1832 1773 2787 2845 565 3031 3057 2831 2934 2035 3040 1045 1021 641 377
+1759 250 2928 1159 950 1500 2027 1537 1383 1341 1392 755 2633 924 360 1208
+601 346 1718 420 1085 2977 208 486 661 390 2958 895 992 803 1377 609
+1290 581 899 163 1858 2459 1405 1049 958 2439 1482 358 386 813 1566 3046
+1197 1708 851 1616 2793 408 196 309 1110 461 1468 878 1118 750 3084 2800
+1082 427 1444 1652 631 275 1923 103 388 255 1721 406 1037 402 2852 1408
+448
+Salinas, CA[3667,12165]80479
+3104 846 1542 1704 374 448 2577 105 58 358 236 1123 160 2879 2622 2754
+3098 1400 3022 963 1954 2341 1674 1429 1691 1899 1837 1883 2380 1029 2195 3200
+1928 2503 2874 1437 2692 2312 138 3045 2779 2664 2976 933 2581 2826 2301 1851
+2524 1831 2792 2611 3052 1316 834 1731 2210 2281 775 1812 2746 3027 2627 1880
+1108 2085 1817 2287 1750 898 2791 2945 3187 2061 3030 1915 2306 2295 2671 398
+1020 3006 2677 1660 1574 2662 2929 1663 3004 2936 2880 2091 2781 2273 3244 903
+1813 2690
+Salina, KS[3884,9761]41843
+1715 1407 977 629 734 1398 1456 917 1739 1752 1442 1545 646 1748 1516 1084
+1298 1435 481 1326 1824 274 967 303 825 430 615 316 404 755 1529 498
+1537 353 806 1199 398 995 757 1685 1348 1268 1208 1313 1829 1218 1463 604
+552 892 123 1168 987 1355 467 1070 277 756 882 1149 556 1049 1364 1239
+680 1942 792 781 594 558 1567 1128 1248 1490 485 1367 485 720 774 1267
+1794 1696 1625 980 87 395 969 1233 981 1307 1375 1183 877 1189 696 1581
+1691 329 1017
+Salida, CO[3853,10600]44870
+527 1293 1918 489 712 916 976 1047 1427 1234 1252 1020 1123 227 1243 1925
+1526 1771 1945 367 1837 1415 799 1387 678 604 737 945 727 793 1242 1178
+995 2047 807 1317 1710 271 1506 1197 1172 1859 1779 1681 1823 1405 1627 1872
+1129 897 1387 650 1656 1475 1866 157 706 690 1210 1327 725 858 1560 1874
+1673 998 1544 1131 1014 1119 824 1143 1639 1759 2001 925 1877 867 1170 1185
+1717 1313 1345 2052 1491 529 620 1494 1744 865 1818 1889 1694 1238 1714 1137
+2091 1267 711 1528
+Salem, OR[4494,12303]89233
+1328 1752 722 3042 839 1972 2190 995 1069 2504 629 664 979 958 1462 635
+3235 2279 3009 3025 1327 2949 241 1985 2686 2006 1136 2065 2273 1734 1710 2307
+432 2152 3127 2072 2462 2855 1364 2632 2007 607 2974 2979 2919 2903 211 2937
+3182 2287 2225 2450 1842 2719 2389 2987 1485 1455 2018 2475 2601 603 2186 2704
+2954 2958 1537 386 2459 2289 2305 2143 295 2718 2894 3122 1965 2957 1616 2198
+1990 2981 324 353 3341 2636 1835 1948 2675 2856 1274 2939 3086 2838 1659 2893
+2030 3171 236 1710 2617
+Saint Paul, MN[4495,9310]270230
+1807 1002 591 2112 1258 1266 1200 1249 1929 2025 703 2028 2054 1983 2077 1171
+2037 1629 535 1366 1224 758 1146 1670 486 1137 806 828 905 1022 275 244
+506 1375 488 1326 601 705 1087 739 848 200 1974 1171 1269 1291 1102 1700
+1369 1576 599 949 652 521 920 618 1203 978 1639 711 926 1052 1375 1031
+913 1153 1343 308 1788 1061 1291 638 1068 1535 917 1110 1338 195 1156 210
+391 183 1353 2015 1542 1713 848 658 966 945 1053 665 1155 1362 1047 463
+1148 223 1370 1594 326 816
+Saint Louis, MO[3862,9019]453085
+567 2152 966 441 2134 973 1379 935 952 1817 1875 483 2141 2167 1861 1964
+1065 2150 1105 748 857 1001 869 892 2194 192 575 527 1213 611 576 538
+626 358 1899 102 1103 235 372 761 806 561 477 2087 914 827 767 879
+2224 811 1052 170 520 461 324 748 591 921 893 1489 432 364 490 1549
+656 615 930 819 868 2312 530 933 153 774 1967 694 814 1056 373 933
+739 324 510 829 2194 2066 1189 546 474 701 528 799 1225 873 934 749
+1030 748 418 1147 2091 605 583
+Saint Joseph, MO[3977,9484]76691
+309 436 1852 691 196 1911 1227 1079 798 840 1594 1652 736 1841 1867 1638
+1741 842 1850 1390 888 1166 1254 569 1146 1898 142 841 397 911 496 613
+246 334 559 1603 304 1356 227 626 1019 506 815 561 1787 1168 1134 1076
+1132 1928 1092 1337 446 540 697 85 973 792 1175 663 1266 302 630 756
+1249 622 869 1183 1113 640 2016 687 882 462 659 1667 948 1068 1310 289
+1186 451 525 594 1138 1894 1770 1498 800 256 564 835 1053 976 1127 1241
+1003 807 1057 500 1400 1791 313 837
+Saint Joseph, MI[4210,8648]9622
+562 361 509 2308 1245 757 2381 789 1535 1294 1313 2137 2195 230 2297 2323
+2181 2284 1385 2306 1242 387 932 751 1025 675 2179 516 786 886 1278 970
+937 592 643 44 1884 259 853 594 245 627 984 379 336 2243 700 837
+875 629 2209 982 1189 213 881 182 640 416 230 734 1209 1809 791 651
+731 1705 1017 444 680 956 817 2297 827 1294 271 1133 2044 444 641 862
+361 654 719 129 369 966 2350 2051 1326 388 794 1060 485 582 1174 686
+902 578 972 688 288 897 2103 659 343
+Saint Johnsbury, VT[4442,7202]7150
+910 1442 1189 1412 3213 2133 1623 3286 547 2440 2124 2121 3003 3061 709 3202
+3228 3047 3150 2251 3211 1467 1019 1163 193 1930 380 3082 1375 1404 1716 2181
+1800 1741 1495 1546 906 2787 1139 190 1424 824 683 1889 678 1239 3148 359
+1008 1175 310 3112 1417 1414 1019 1689 763 1506 494 929 384 2075 2675 1621
+1416 1361 2610 1825 650 259 1335 1720 3200 1600 2098 1067 1959 2947 534 553
+241 1264 293 1622 1032 1272 1272 3255 2954 1604 695 1660 1890 944 440 2051
+444 910 590 1830 874 1191 188 3006 1562 642
+Saint Cloud, MN[4557,9417]42566
+1487 584 490 639 75 1766 1010 599 2084 1333 1238 1208 1313 1901 2031 778
+2000 2026 1955 2049 1179 2009 1701 568 1439 1299 730 1221 1629 555 1209 865
+787 974 1091 283 223 581 1334 560 1401 670 780 1162 745 923 275 1946
+1246 1344 1363 1177 1659 1441 1648 671 1018 727 548 995 664 1278 986 1647
+780 998 1124 1334 1100 988 1228 1415 233 1747 1130 1360 710 1137 1494 992
+1185 1413 267 1231 169 466 258 1425 1974 1501 1785 923 666 974 1020 1128
+590 1230 1437 1122 392 1223 298 1445 1553 305 891
+Saint Augustine, FL[2989,8132]11985
+1540 1359 1081 1253 944 1468 3096 1821 1382 2775 837 2310 1327 1174 2458 2450
+1035 2851 2812 2502 2605 1706 2906 236 1428 196 1192 1813 1043 3133 1111 445
+1179 2157 1090 876 1482 1570 1037 2838 998 1172 1029 911 712 1750 947 1322
+2789 1017 352 220 1157 3163 200 183 895 930 1038 1268 1259 1292 975 1664
+2027 1161 626 530 2493 975 901 1194 155 1773 3251 690 1099 837 1099 2911
+1076 806 1121 1293 1228 1664 1115 1355 115 3051 3005 245 922 1307 1201 720
+1004 2130 915 473 803 1930 515 1270 1214 3035 1549 1007
+Saginaw, MI[4343,8394]77508
+1178 766 779 187 749 548 696 2495 1432 944 2568 749 1722 1481 1485 2324
+2382 194 2484 2510 2368 2471 1572 2493 1339 272 1006 659 1212 634 2366 703
+926 1073 1465 1157 1109 779 830 205 2071 446 760 781 267 594 1171 346
+523 2430 665 872 961 534 2396 1079 1286 387 1053 140 827 285 150 694
+1396 1996 978 815 871 1892 1189 411 581 1053 999 2484 991 1466 435 1320
+2231 408 601 782 548 523 906 316 556 1063 2537 2238 1423 346 981 1247
+498 547 1272 646 908 545 1051 696 475 806 2290 846 310
+Sacramento, CA[3859,12149]275741
+2390 2836 1906 3108 2203 1747 2047 1934 560 1140 1645 185 2937 668 1603 1765
+435 509 2399 94 127 419 413 1184 103 2940 2444 2815 2920 1222 2844 801
+1880 2402 1735 1251 1752 1960 1659 1705 2202 867 2048 3022 1947 2357 2750 1259
+2527 2134 47 2869 2840 2725 2798 771 2642 2887 2182 1912 2346 1737 2614 2433
+2882 1297 895 1792 2271 2342 597 1873 2599 2849 2688 1702 946 2146 1878 2200
+1811 736 2613 2789 3017 1883 2852 1737 2128 2117 2732 236 858 3067 2531 1669
+1635 2570 2751 1485 2834 2981 2733 1913 2788 2095 3066 741 1635 2512
+Rutland, VT[4361,7297]18436
+3005 737 1273 1384 103 836 1339 1086 1309 3110 2030 1520 3183 458 2337 2021
+2018 2900 2958 606 3099 3125 2944 3047 2148 3108 1478 977 1077 90 1827 277
+2979 1272 1301 1613 2078 1697 1638 1392 1443 805 2684 1036 134 1321 721 580
+1786 575 1136 3045 256 922 1085 207 3009 1328 1428 916 1586 660 1403 452
+887 298 1972 2572 1518 1313 1258 2507 1722 547 156 1249 1617 3097 1497 1995
+964 1856 2844 431 467 168 1161 224 1519 929 1169 1186 3152 2851 1518 592
+1557 1787 841 337 1974 358 824 487 1772 777 1088 135 2903 1459 539
+Roswell, NM[3340,10453]39676
+2114 1313 1566 1567 1217 2217 1379 836 1028 1209 1658 423 640 1252 2001 819
+320 538 902 892 1511 1328 1289 946 1049 196 1383 1671 1721 1546 2029 727
+1920 1745 879 1133 539 984 506 691 934 1017 1377 1566 1120 2129 793 1400
+1728 601 1589 1394 1266 1942 1595 1456 1907 1735 1373 1618 1198 666 1489 756
+1776 1609 1949 323 469 596 1051 1096 1055 604 1643 1958 1419 1234 1874 877
+651 1181 515 1473 1722 1842 2084 1122 1961 1091 1342 1392 1463 1528 1703 1798
+1574 585 389 1556 1827 1245 1901 1752 1777 1485 1635 1333 2175 1597 935 1611
+Rocky Mount, NC[3594,7780]41283
+1786 697 2936 808 576 1367 783 837 1204 899 1292 3041 1865 1340 2932 261
+2268 1575 1512 2615 2673 624 3008 2969 2659 2762 1863 3039 784 1080 380 616
+1758 478 2962 1089 689 1276 2059 1282 1122 1370 1426 803 2667 900 596 1065
+592 232 1705 462 1119 2946 441 225 400 593 2992 634 731 779 1122 668
+1223 719 958 399 1792 2255 1257 788 697 2438 1221 397 619 552 1600 3080
+936 1447 746 1355 2827 536 230 545 1144 664 1502 912 1152 489 3083 2834
+821 466 1343 1397 386 440 1957 339 127 263 1755 151 1071 638 2886 1437
+510
+Rock Springs, WY[4159,10923]19458
+2072 825 2141 864 1526 2127 1042 2244 1339 883 1183 1070 969 402 783 1042
+2073 196 1097 1301 859 989 1535 958 984 913 1007 629 967 2266 1605 2040
+2056 358 1980 1056 1016 1717 1038 387 1122 1330 795 841 1338 776 1184 2158
+1103 1493 1886 395 1663 1270 904 2005 2010 1950 1934 1046 1968 2213 1318 1282
+1482 873 1750 1569 2018 559 994 1050 1506 1632 368 1243 1735 1985 1989 931
+1185 1516 1399 1336 1209 784 1749 1925 2153 1019 1988 873 1264 1253 2012 1011
+943 2372 1667 866 1005 1706 1887 785 1970 2117 1869 1158 1924 1231 2202 908
+771 1648
+Rockford, IL[4227,8910]139712
+1192 963 1277 980 2056 367 1148 418 1083 180 456 296 343 2146 1098 652
+2234 929 1388 1217 1237 2035 2093 374 2150 2176 2079 2182 1267 2159 1306 473
+1034 895 878 817 2013 439 821 809 1098 893 872 412 463 177 1718 194
+997 517 376 758 837 519 181 2096 842 939 971 773 2043 1049 1253 267
+816 323 538 591 410 874 1074 1707 714 610 736 1548 952 584 824 1023
+651 2131 786 1229 315 1056 1878 588 781 1009 181 827 545 72 214 1033
+2188 1885 1393 519 692 983 616 724 1008 826 1033 718 806 819 122 1041
+1937 479 487
+Rochester, NY[4316,7761]241741
+694 1855 606 1828 291 2719 446 1170 1098 394 550 1053 800 1023 2824 1744
+1234 2897 441 2051 1735 1732 2614 2672 323 2813 2839 2658 2761 1862 2822 1375
+686 974 213 1541 205 2693 986 1081 1327 1792 1411 1352 1106 1157 519 2398
+750 316 1035 435 460 1500 313 850 2759 247 818 965 88 2723 1208 1325
+630 1300 374 1117 161 596 316 1686 2286 1232 1027 1061 2221 1436 328 135
+1133 1331 2811 1228 1709 678 1570 2558 158 376 336 875 133 1233 643 883
+1070 2866 2565 1415 338 1271 1501 605 166 1688 338 733 367 1486 657 802
+360 2617 1173 253
+Rochester, MN[4402,9246]57890
+961 267 1066 1229 1205 1246 1930 633 1388 152 1349 446 402 487 80 1883
+998 587 2108 1195 1262 1180 1215 1925 2021 640 2024 2050 1979 2073 1167 2033
+1549 553 1298 1161 754 1083 1746 452 1057 772 875 871 988 271 240 443
+1451 408 1253 567 642 1024 735 785 204 1970 1108 1203 1211 1039 1776 1289
+1496 519 915 589 487 857 636 1140 974 1635 677 846 972 1407 997 850
+1090 1263 385 1864 1005 1257 558 1034 1611 854 1047 1275 115 1093 278 328
+201 1273 2047 1618 1633 785 650 946 881 990 742 1092 1299 984 543 1085
+166 1303 1670 322 753
+Roanoke, VA[3727,7994]100220
+1018 548 752 1861 216 1647 668 2725 629 624 1156 771 626 994 726 1081
+2830 1685 1167 2793 434 2057 1437 1412 2476 2534 463 2819 2830 2520 2623 1724
+2828 832 901 428 587 1547 421 2751 918 640 1137 1847 1143 1022 1159 1215
+592 2456 691 604 926 381 88 1500 334 908 2765 412 280 417 535 2781
+663 779 570 983 489 1050 637 774 407 1619 2116 1118 660 597 2227 1119
+277 572 585 1389 2869 836 1347 573 1253 2616 454 238 553 933 606 1291
+701 941 522 2872 2623 869 316 1200 1258 213 382 1746 347 293 181 1544
+109 860 646 2675 1221 385
+Richmond, VA[3754,7745]219214
+168 1127 486 861 1994 120 1815 577 2858 688 696 1265 663 721 1127 859
+1190 2963 1818 1300 2961 306 2190 1605 1580 2644 2702 504 2952 2978 2688 2791
+1892 2961 904 960 500 496 1680 358 2860 1051 782 1305 1959 1311 1190 1273
+1324 688 2565 824 476 1094 513 112 1633 342 1017 2898 321 345 512 473
+2890 754 851 703 1151 548 1183 599 838 279 1752 2284 1286 828 765 2360
+1287 277 499 672 1498 2978 1004 1515 706 1421 2725 416 110 425 1042 544
+1400 810 1050 609 3005 2732 941 346 1333 1426 381 320 1855 219 247 143
+1653 225 969 518 2784 1340 390
+Richmond, IN[3983,8489]41349
+565 432 590 499 324 1429 646 1336 785 2293 293 898 728 888 211 562
+308 653 2398 1253 742 2439 665 1625 1243 1236 2122 2180 191 2387 2413 2166
+2269 1370 2396 1059 536 775 700 1115 584 2323 494 687 835 1415 919 864
+727 787 167 2028 259 799 543 64 457 1068 253 480 2333 606 643 681
+578 2353 799 1006 138 804 175 625 462 394 613 1194 1794 740 562 602
+1795 940 307 629 773 961 2441 746 1221 190 1074 2188 389 506 748 505
+632 863 273 513 783 2440 2195 1143 238 779 1009 292 491 1318 565 709
+441 1116 495 432 841 2247 794 275
+Richfield, UT[3877,11209]5482
+1700 2265 2132 1408 2187 1526 342 2337 827 2471 701 1860 2318 1384 2574 1673
+1138 1438 1412 1003 497 1023 808 2365 164 1141 1359 534 664 1869 795 813
+588 682 631 804 2422 1947 2268 2388 700 2284 1090 1271 1884 1175 729 1234
+1442 1137 1183 1670 911 1441 2492 1304 1764 2157 689 1953 1612 733 2306 2265
+2178 2266 1080 2124 2369 1584 1394 1816 1120 2084 1903 2313 654 652 1187 1707
+1824 400 1355 2007 2315 2170 1273 1219 1628 1458 1591 1312 818 2081 2206 2448
+1353 2320 1215 1598 1595 2214 874 1048 2549 1938 1026 1117 1966 2191 1099 2265
+2372 2141 1500 2186 1565 2536 942 1113 1973
+Rhinelander, WI[4564,8942]7873
+1636 558 1095 986 260 928 273 1294 1197 1433 1214 2158 504 1400 262 1283
+414 653 569 227 2028 1226 815 2336 1163 1490 1424 1366 2153 2249 608 2252
+2278 2207 2301 1395 2261 1561 319 1269 1129 982 1051 1891 685 1094 1023 1049
+1122 1145 499 468 411 1596 467 1231 787 610 992 963 753 92 2198 1076
+1174 1212 1007 1921 1301 1508 510 1089 557 738 789 402 1108 1202 1863 928
+883 1009 1596 1225 818 1058 1275 495 2009 1059 1408 563 1285 1756 822 1015
+1243 364 1027 431 289 59 1285 2236 1763 1645 753 882 1190 850 958 824
+1060 1267 952 603 1053 170 1275 1815 550 721
+Reno, NV[3952,11981]100756
+2019 571 2154 2719 2586 1791 2580 1917 725 2797 1225 2866 139 2251 2748 1767
+2969 2064 1608 1908 1795 537 1010 1506 324 2798 529 1545 1763 470 600 2260
+233 266 517 541 1096 242 2852 2305 2727 2781 1083 2705 778 1741 2314 1647
+1112 1664 1872 1520 1566 2063 787 1909 2883 1817 2218 2611 1120 2388 1995 186
+2730 2735 2637 2659 748 2554 2799 2043 1824 2207 1598 2475 2294 2743 1167 930
+1700 2183 2254 458 1785 2460 2710 2600 1563 923 2058 1869 2061 1723 627 2474
+2650 2878 1744 2713 1598 1989 1978 2644 303 827 2979 2392 1539 1547 2431 2612
+1346 2695 2842 2594 1774 2649 1956 2927 710 1496 2373
+Regina, SA[5042,10465]162613
+1458 943 1211 1437 1974 1865 861 1807 1127 973 2076 1433 2093 1597 1391 2249
+709 2170 1293 1095 1344 784 1260 1053 1109 1775 2042 1047 1593 1797 1728 1858
+1487 1691 1717 1782 1871 1276 1700 2410 1179 2148 2008 754 1930 1123 1235 1917
+1412 628 1539 1708 849 766 1290 828 1269 2110 1322 1489 1871 850 1632 984
+1637 1955 2051 2072 1886 1153 2150 2357 1380 1635 1436 1114 1676 1289 1987 1110
+1759 1346 1706 1832 1000 1665 1697 1937 2124 476 1241 1782 1858 1419 1635 988
+1701 1894 2122 976 1914 653 1175 967 2134 1459 995 2494 1632 1196 1468 1729
+1837 188 1939 2146 1831 399 1932 1007 2154 1047 782 1600
+Red Bluff, CA[4018,12224]9490
+1564 198 2217 769 2352 2917 2784 1989 2778 2115 923 2995 1423 3064 131 2449
+2946 1965 3166 2262 1806 2106 1993 429 1208 1704 293 2996 727 1734 1896 566
+640 2458 200 235 550 529 1294 209 3050 2503 2925 2979 1281 2903 670 1939
+2512 1845 1310 1862 2070 1718 1764 2261 736 2107 3081 2015 2416 2809 1318 2586
+2193 178 2928 2933 2835 2857 640 2752 2997 2241 2022 2405 1796 2673 2492 2941
+1365 1026 1898 2381 2452 656 1983 2658 2908 2798 1761 815 2256 2009 2259 1921
+605 2672 2848 3076 1942 2911 1796 2187 2176 2842 105 727 3177 2590 1737 1745
+2629 2810 1544 2893 3040 2792 1963 2847 2154 3125 610 1694 2571
+Reading, PA[4033,7593]78686
+2871 1917 2673 1038 2243 543 249 345 1071 281 804 1948 369 1879 328 2812
+624 945 1208 431 657 1105 851 1133 2917 1796 1285 2982 160 2144 1776 1750
+2665 2723 440 2906 2932 2709 2812 1913 2915 1153 896 749 247 1634 109 2803
+1037 978 1378 1902 1462 1360 1216 1267 630 2508 802 265 1086 479 257 1593
+295 960 2852 72 594 761 249 2833 1003 1100 681 1321 484 1168 421 774
+87 1737 2337 1283 998 935 2314 1457 251 250 921 1441 2921 1174 1685 729
+1591 2668 274 139 214 985 320 1343 753 993 858 2959 2675 1190 305 1322
+1552 542 115 1798 57 496 164 1596 454 912 307 2727 1283 321
+Ravenna, OH[4116,8124]11987
+348 2541 1570 2343 691 1943 246 413 405 723 272 457 1618 533 1581 558
+2482 280 1012 861 661 322 807 554 786 2587 1498 987 2660 473 1814 1488
+1470 2367 2425 93 2576 2602 2411 2514 1615 2585 1220 552 816 473 1304 363
+2456 739 842 1080 1555 1164 1092 869 920 282 2161 504 575 788 182 337
+1263 80 613 2522 388 682 805 351 2486 981 1167 384 1038 140 870 307
+430 418 1439 2039 986 765 799 1984 1174 136 402 954 1094 2574 966 1449
+431 1308 2321 144 325 552 638 405 996 406 646 910 2629 2328 1257 105
+1024 1255 352 270 1451 370 660 270 1249 506 565 619 2380 936 34
+* End of file "miles.dat"
diff --git a/support/graphbase/miles_span.w b/support/graphbase/miles_span.w
new file mode 100644
index 0000000000..d743d3fd9b
--- /dev/null
+++ b/support/graphbase/miles_span.w
@@ -0,0 +1,1659 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{MILES\_\thinspace SPAN}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+
+\prerequisite{GB\_\thinspace MILES}
+@* Minimum spanning trees.
+A classic paper by R. L. Graham and Pavol Hell about the history of
+algorithms to find the minimum-length spanning tree of a graph
+[{\sl Annals of the History of Computing \bf7} (1985), 43--57]
+describes three main approaches to that problem. Algorithm~1,
+``two nearest fragments,'' repeatedly adds a shortest edge that joins
+two hitherto unconnected fragments of the graph; this algorithm was
+first published by J.~B. Kruskal in 1956. Algorithm~2, ``nearest
+neighbor,'' repeatedly adds a shortest edge that joins a particular
+fragment to a vertex not in that fragment; this algorithm was first
+published by V. Jarn\'{\i}k in 1930. Algorithm~3, ``all nearest
+fragments,'' repeatedly adds to each existing fragment the shortest
+edge that joins it to another fragment; this method, seemingly the
+most sophisticated in concept, also turns out to be the oldest,
+being first published by Otakar Bor{\accent23u}vka in 1926.
+
+The present program contains simple implementations of all three
+approaches, in an attempt to make practical comparisons of how
+they behave on ``realistic'' data. One of the main goals of this
+program is to demonstrate a simple way to make machine-independent
+comparisons of programs written in \Cee, by counting memory
+references or ``mems.'' In other words, this program is intended
+to be read, not just performed.
+
+The author believes that mem counting sheds considerable light on
+the problem of determining the relative efficiency of competing
+algorithms for practical problems. He hopes other researchers will
+enjoy rising to the challenge of devising algorithms that find minimum
+spanning trees in significantly fewer mem units than the algorithms
+presented here, on problems of the size considered here.
+
+Indeed, mem counting promises to be significant for combinatorial
+algorithms of all kinds. The standard graphs available in the
+Stanford GraphBase should make it possible to carry out a large
+number of machine-independent experiments concerning the practical
+efficiency of algorithms that have previously been studied
+only asymptotically.
+
+@ The graphs we will deal with are produced by the |miles| subroutine,
+found in the |gb_miles| module. As explained there,
+|miles(n,north_weight,west_weight,pop_weight,0,max_degree,seed)| produces a
+graph of |n<=128| vertices based on the driving distances between
+North American cities. By default we take |n=100|, |north_weight=west_weight
+=pop_weight=0|, and |max_degree=10|; this gives billions of different sparse
+graphs, when different |seed| values are specified, since a different
+random number seed generally results in the selection of another
+one of the $128\choose100$ possible subgraphs.
+
+The default parameters can be changed by specifying options on the
+command line, at least in a \UNIX\ implementation, thereby obtaining a
+variety of special effects. For example, the value of |n| can be
+raised or lowered and/or the graph can be made more or less sparse.
+The user can bias the selection by ranking cities according to their
+population and/or position, if nonzero values are given to any of the
+parameters |north_weight|, |west_weight|, or |pop_weight|.
+Command-line options \.{-n}\<number>, \.{-N}\<number>, \.{-W}\<number>,
+\.{-P}\<number>, \.{-d}\<number>, and \.{-s}\<number>
+are used to specify non-default values of the respective quantities |n|,
+|north_weight|, |west_weight|, |pop_weight|, |max_degree|, and |seed|.
+
+If the user specifies a \.{-r} option, e.g.~by saying `\.{miles\_span}
+\.{-r10}', this program will investigate the spanning trees of a
+series of e.g.~10 graphs having consecutive |seed| values. (This
+option makes sense only if |n<128| and |north_weight=west_weight=pop_weight=0|,
+because |miles| chooses the top |n| cities by weight; it rarely needs
+to use random numbers to break ties when the weights are nonzero,
+because cities rarely have exactly the same weight in that case.)
+@^UNIX dependencies@>
+
+Here is the overall layout of this \Cee\ program:
+
+@p
+#include "gb_graph.h" /* the GraphBase data structures */
+#include "gb_miles.h" /* the |miles| routine */
+@#
+@<Global variables@>@;
+@<Procedures to be declared early@>@;
+@<Priority queue subroutines@>@;
+@<Subroutines@>;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{@+unsigned n=100; /* the desired number of vertices */
+ unsigned n_weight=0; /* the |north_weight| parameter */
+ unsigned w_weight=0; /* the |west_weight| parameter */
+ unsigned p_weight=0; /* the |pop_weight| parameter */
+ unsigned d=10; /* the |max_degree| parameter */
+ long s=0; /* the random number seed */
+ unsigned r=1; /* the number of repetitions */
+ @<Scan the command line options@>;
+ if (n>1)
+ while (r--) {
+ g=miles(n,n_weight,w_weight,p_weight,0,d,s);
+ if (g==NULL) {
+ fprintf(stderr,"Sorry, can't create the graph! (error code %d)\n",
+ panic_code);
+ return -1;
+ }
+ @<Report the number of mems needed to compute a minimum spanning tree
+ of |g| by various algorithms@>;
+ gb_recycle(g);
+ s++; /* increase the |seed| value */
+ }
+}
+
+@ @<Global...@>=
+Graph *g; /* the graph we will work on */
+
+@ @<Scan the command line options@>=
+while (--argc) {
+@^UNIX dependencies@>
+ if (sscanf(argv[argc],"-n%u",&n)==1) ;
+ else if (sscanf(argv[argc],"-N%u",&n_weight)==1) ;
+ else if (sscanf(argv[argc],"-W%u",&w_weight)==1) ;
+ else if (sscanf(argv[argc],"-P%u",&p_weight)==1) ;
+ else if (sscanf(argv[argc],"-d%u",&d)==1) ;
+ else if (sscanf(argv[argc],"-r%u",&r)==1) ;
+ else if (sscanf(argv[argc],"-s%ld",&s)==1) ;
+ else if (strcmp(argv[argc],"-v")==0) verbose=1;
+ else {
+ fprintf(stderr,"Usage: %s [-nN][-dN][-rN][-sN][-NN][-WN][-PN][-v]\n",
+ argv[0]);
+ return -2;
+ }
+}
+
+@ We will try out four basic algorithms that have received prominent
+attention in the literature. Graham and Hell's Algorithm~1 is represented
+by the |krusk| procedure, which uses Kruskal's algorithm after the
+edges have been sorted by length with a radix sort. Their Algorithm~2
+is represented by the |jar_pr| procedure, which incorporates a
+priority queue structure that we implement in two ways, either as
+a simple binary heap or as a Fibonacci heap. And their Algorithm~3
+is represented by the |cher_tar_kar| procedure, which implements a
+method similar to Bor{\accent23u}vka's that was independently
+discovered by Cheriton and Tarjan and later simplified by Karp and Tarjan.
+
+@d INFINITY (unsigned long)-1
+ /* value returned when there's no spanning tree */
+
+@<Report the number...@>=
+printf("The graph %s has %d edges,\n",g->id,g->m/2);
+sp_length=krusk(g);
+if (sp_length==INFINITY) printf(" and it isn't connected.\n");
+else printf(" and its minimum spanning tree has length %d.\n",sp_length);
+printf(" The Kruskal/radix-sort algorithm takes %d mems;\n",mems);
+@<Execute |jar_pr(g)| with binary heaps as the priority queue algorithm@>;
+printf(" the Jarnik/Prim/binary-heap algorithm takes %d mems;\n",mems);
+@<Allocate additional space needed by the more complex algorithms;
+ or |goto done| if there isn't enough room@>;
+@<Execute |jar_pr(g)| with Fibonacci heaps as
+ the priority queue algorithm@>;
+printf(" the Jarnik/Prim/Fibonacci-heap algorithm takes %d mems;\n",mems);
+if (sp_length!=cher_tar_kar(g)) {
+ if (gb_alloc_trouble) printf(" ...oops, I've run out of memory!\n");
+ else printf(" ...oops, I've got a bug, please fix fix fix\n");
+ return -3;
+}
+printf(" the Cheriton/Tarjan/Karp algorithm takes %d mems.\n\n",mems);
+done:;
+
+@ @<Glob...@>=
+unsigned long sp_length; /* length of the minimum spanning tree */
+
+@ When the |verbose| switch is nonzero, edges found by the various
+algorithms will call the |report| subroutine.
+
+@<Sub...@>=
+report(u,v,l)
+ Vertex *u,*v; /* adjacent vertices in the minimum spanning tree */
+ int l; /* the length of the edge between them */
+{ printf(" %d miles between %s and %s [%d mems]\n",
+ l,u->name,v->name,mems);
+}
+
+@*Strategies and ground rules.
+Let us say that a {\it fragment\/} is any subtree of a minimum
+spanning tree. All three algorithms we implement make use of a basic
+principle first stated in full generality by R.~C. Prim in 1957:
+``If a fragment~$F$ does not include all the vertices, and if $e$~is
+a shortest edge joining $F$ to a vertex not in~$F$, then $F\cup e$
+is a fragment.'' To prove Prim's principle, let $T$ be a minimum
+spanning tree that contains $F$ but not~$e$. Adding $e$ to~$T$ creates
+a circuit containing some edge $e'\ne e$, where $e'$ runs from a vertex
+in~$F$ to a vertex not in~$F$. Deleting $e'$ from
+$T\cup e$ produces a spanning tree~$T'$ of total length no larger
+than the total length of~$T$. Hence $T'$ is a minimum spanning
+tree containing $F\cup e$, QED.
+
+@ The graphs produced by |miles| have special properties, and it is fair game
+to make use of those properties if we can.
+
+First, the length of each edge is a positive integer less than $2^{12}$.
+
+Second, the $k$th vertex $v_k$ of the graph is represented in \Cee\ by
+the pointer expression |g->vertices+k|. If weights have been assigned,
+these vertices will be in order by weight. For example, if |north_weight=1|
+but |west_weight=pop_weight=0|, vertex $v_0$ will be the most northerly city
+and vertex $v_{n-1}$ will be the most southerly.
+
+Third, the edges accessible from a vertex |v| appear in a linked list
+starting at |v->arcs|. An edge from |v| to $v_j$ will precede an
+edge from |v| to $v_k$ in this list if and only if $j>k$.
+
+Fourth, the vertices have coordinates |v->x_coord| and |v->y_coord|
+that are correlated with the length of edges between them: The
+Euclidean distance between the coordinates of two vertices tends to be small
+if and only if those vertices are connected by a relatively short edge.
+(This is only a tendency, not a certainty; for example, some cities
+around Chesapeake Bay are fairly close together as the crow flies, but not
+within easy driving range of each other.)
+
+Fifth, the edge lengths satisfy the triangle inequality: Whenever
+three edges form a cycle, the longest is no longer than the sum of
+the lengths of the two others. (It can be proved that
+the triangle inequality is of no use in finding minimum spanning
+trees; we mention it here only to exhibit yet another way in which
+the data produced by |miles| is known to be nonrandom.)
+
+Our implementation of Kruskal's algorithm will make use of the first
+property, and it also uses part of the third to avoid considering an
+edge more than once. We will not exploit the other properties, but a
+reader who wants to design algorithms that use fewer mems to find minimum
+spanning trees of these graphs is free to use any idea that helps.
+
+@f Vertex int /* |gb_graph| defines these data types */
+@f Arc int
+@f Graph int
+@f Area int
+
+@ Speaking of mems, here are the simple \Cee\ instrumentation macros that we use
+to count memory references. The macros are called |o|, |oo|, |ooo|,
+and |oooo|; hence Jon Bentley has called this a ``little oh analysis.''
+Implementors who want to count mems are supposed to say, e.g., `\\{oo},'
+just before an assignment statement or boolean expression that makes
+two references to memory. The \Cee\ preprocessor will convert this
+to a statement that increases |mems| by~2 as that statement or expression
+is evaluated.
+
+Notice that, for example, the semantics of \Cee\ tell us that
+the evaluation of an expression like `|a&&(o,a->len>10)|'
+will increment |mems| if and only if the pointer variable~|a|
+is non-null. Warning: The parentheses are very important in this example,
+because \Cee's operator |&&| (i.e., \.{\&\&}) has higher precedence than comma.
+
+Values of significant variables, like |a| in the previous example,
+can be assumed to be in ``registers,'' and no charge is made for
+arithmetic computations that involve only registers. But the total
+number of registers in an implementation must be finite and fixed,
+independent of the problem size.
+@^discussion of \\{mems}@>
+
+\Cee\ does not allow the |o| macros to appear in declarations, so we cannot
+take full advantage of \Cee's initialization mechanism when we are
+counting mems. But it's easy to initialize variables in separate
+statements after the declarations are done.
+
+@d o mems++
+@d oo mems+=2
+@d ooo mems+=3
+@d oooo mems+=4
+
+@<Glob...@>=
+long mems; /* the number of memory references counted */
+
+@ Examples of these mem-counting conventions appear throughout the
+program that follows. Some people will undoubtedly ask why the insertion of
+macros by hand is being recommended here, when it would be possible to
+develop a fancy system that counts mems automatically. The author
+believes that it is best to rely on programmers to introduce |o| and
+|oo|, etc., by themselves, for several reasons. (1)~The macros can be
+inserted easily and quickly using a text editor. (2)~An implementation
+need not pay for mems that could be avoided by a suitable optimizing
+compiler or by making the \Cee\ program text slightly more complex;
+thus, authors can use their good judgment to keep programs more
+readable than if the code were overly hand-optimized. (3)~The
+programmer should be able to see exactly where mems are being charged,
+as an aid to bottleneck elimination. Occurrences of |o| and |oo| make
+this plain without messing up the program text. (4)~An implementation
+need not be charged for mems that merely provide diagnostic output, or
+mems that do redundant computations just to doublecheck the validity
+of ``proven'' assertions as a program is being tested.
+@^discussion of \\{mems}@>
+
+Computer architecture is converging rapidly these days to the
+design of machines in which the exact running time of a program
+depends on complicated interactions between pipelined circuitry and
+the dynamic properties of cache mapping in a memory hierarchy,
+not to mention the effects of compilers and operating systems.
+But a good approximation to running time is usually obtained if we
+assume that the amount of computation is proportional to the activity
+of the memory bus between registers and main memory. This
+approximation is likely to get even better in the future, as
+RISC computers get faster and faster in comparison to memory devices.
+Although the mem measure is far from perfect, it appears to be
+significantly less distorted than any other measurement that can
+be obtained without considerably more work. An implementation that
+is designed to use few mems will almost certainly be efficient
+on today's sequential computers, as well as on the sequential computers
+we can expect to be built in the foreseeable future. And the converse
+statement is even more true: An algorithm that runs fast will not
+consume many mems.
+
+Of course authors are expected to be reasonable and fair when they
+are competing for minimum-mem prizes. They must be ready to
+submit their programs to inspection by impartial judges. A good
+algorithm will not need to abuse the spirit of realistic mem-counting.
+
+Mems can be analyzed theoretically as well as empirically.
+This means we can attach constants to estimates of running time, instead of
+always resorting to $O$~notation.
+
+@*Kruskal's algorithm.
+The first algorithm we shall implement and instrument is the simplest:
+It considers the edges one by one in order of nondecreasing length,
+selecting each edge that does not form a cycle with previously
+selected edges.
+
+We know that the edge lengths are less than $2^{12}$, so we can sort them
+into order with two passes of a $2^6$-bucket radix sort.
+We will arrange to have them appear in the buckets as linked lists
+of |Arc| records; the two utility fields of an |Arc| will be called
+|from| and |klink|, respectively.
+
+@d from a.v /* an edge goes from vertex |a->from| to vertex |a->tip| */
+@d klink b.a /* the next longer edge after |a| will be |a->klink| */
+
+@<Put all the edges into |bucket[0]| through |bucket[63]|@>=
+o,n=g->n;
+for (l=0;l<64;l++) oo,aucket[l]=bucket[l]=NULL;
+for (o,v=g->vertices;v<g->vertices+n;v++)
+ for (o,a=v->arcs;a&&(o,a->tip>v);o,a=a->next) {
+ o,a->from=v;
+ o,l=a->len&0x3f; /* length mod 64 */
+ oo,a->klink=aucket[l];
+ o,aucket[l]=a;
+ }
+for (l=63;l>=0;l--)
+ for (o,a=aucket[l];a;) {@+register int ll;
+ register Arc *aa=a;
+ o,a=a->klink;
+ o,ll=aa->len>>6; /* length divided by 64 */
+ oo,aa->klink=bucket[ll];
+ o,bucket[ll]=aa;
+ }
+
+@ @<Glob...@>=
+Arc *aucket[64], *bucket[64]; /* heads of linked lists of arcs */
+
+@ Kruskal's algorithm now takes the following form.
+
+@<Sub...@>=
+unsigned long krusk(g)
+ Graph *g;
+{@+@<Local variables for |krusk|@>;
+ mems=0;
+ @<Put all the edges...@>;
+ if (verbose) printf(" [%d mems to sort the edges into buckets]\n",mems);
+ @<Put all the vertices into components by themselves@>;
+ for (l=0;l<64;l++)
+ for (o,a=bucket[l];a;o,a=a->klink) {
+ o,u=a->from;
+ o,v=a->tip;
+ @<If |u| and |v| are already in the same component, |continue|@>;
+ if (verbose) report(a->from,a->tip,a->len);
+ o,tot_len+=a->len;
+ if (--components==1) return tot_len;
+ @<Merge the components containing |u| and |v|@>;
+ }
+ return INFINITY; /* the graph wasn't connected */
+}
+
+@ Lest we forget, we'd better declare all the local variables we've
+been using.
+
+@<Local variables for |krusk|@>=
+register Arc *a,*aa; /* current edges of interest */
+register int l; /* current bucket of interest */
+register Vertex *u,*v,*w; /* current vertices of interest */
+unsigned long tot_len=0; /* total length of edges already chosen */
+int n; /* the number of vertices */
+int components;
+
+@ The remaining things that |krusk| needs to do are easily recognizable
+as an application of ``equivalence algorithms'' or ``union/find''
+data structures. We will use a simple approach whose average running
+time on random graphs was shown to be linear by Knuth and Sch\"onhage
+in {\sl Theoretical Computer Science\/ \bf 6} (1978), 281--315.
+
+The vertices of each component (i.e., of each connected fragment defined by
+the edges selected so far) will be linked circularly by |clink| pointers.
+Each vertex also has a |class| field that points to a unique vertex
+representing its component. Each component representative also has
+a |csize| field that tells how many vertices are in the component.
+
+@d clink z.v /* pointer to another vertex in the same component */
+@d class y.v /* pointer to component representative */
+@d csize x.i /* size of the component (maintained only for representatives) */
+
+@<If |u| and |v| are already in the same component, |continue|@>=
+if (oo,u->class==v->class) continue;
+
+@ We don't need to charge any mems for fetching |g->vertices|, because
+|krusk| has already referred to it.
+@^discussion of \\{mems}@>
+
+@<Put all the vertices...@>=
+for (v=g->vertices;v<g->vertices+n;v++) {
+ oo,v->clink=v->class=v;
+ o,v->csize=1;
+}
+components=n;
+
+@ The operation of merging two components together requires us to
+change two |clink| pointers, one |csize| field, and the |class|
+fields in each vertex of the smaller component.
+
+Here we charge two mems for the first |if| test, since |u->csize| and
+|v->csize| are being fetched from memory. Then we charge only one mem
+when |u->csize| is being updated, since the values being added together
+have already been fetched. True, the compiler has to be smart to
+realize that it's safe to add the fetched values |u->csize+v->csize|
+even though |u| and |v| may have been swapped in the meantime;
+but we are assuming that the compiler is extremely clever. (Otherwise we
+would have to clutter up our program every time we don't trust the compiler.
+After all, programs that count mems are intended primarily to be read,
+they aren't intended for production jobs.) % Prim-arily?
+@^discussion of \\{mems}@>
+
+@<Merge the components containing |u| and |v|@>=
+u=u->class; /* |u->class| has already been fetched from memory */
+v=v->class; /* ditto for |v->class| */
+if (oo,u->csize<v->csize) {
+ w=u;@+u=v;@+v=w;
+} /* now |v|'s component is smaller than |u|'s (or equally small) */
+o,u->csize+=v->csize;
+o,w=v->clink;
+oo,v->clink=u->clink;
+o,u->clink=w;
+for (;;o,w=w->clink) {
+ o,w->class=u;
+ if (w==v) break;
+}
+
+@* Jarn{\'\i}k and Prim's algorithm.
+A second approach to minimum spanning trees is also pretty simple,
+except for one technicality: We want to write it in a sufficiently
+general manner that different priority queue algorithms can be plugged in.
+The basic idea is to choose an arbitrary vertex $v_0$ and connect it to its
+nearest neighbor~$v_1$, then to connect that fragment to its nearest
+neighbor~$v_2$, and so on. A priority queue holds all vertices that
+are adjacent to but not already in the current fragment; the key value
+stored with each vertex is its distance to the current fragment.
+
+We want the priority queue data structure to support the four
+operations |init_queue(d)|, |enqueue(v,d)|, |requeue(v,d)|, and
+|delete_min()|, described in the |gb_dijk| module. Dijkstra's
+algorithm for shortest paths, described there, is remarkably similar
+to Jarn{\'\i}k and Prim's algorithm for minimum spanning trees; in
+fact, Dijkstra discovered the latter algorithm independently, at the
+same time as he came up with his procedure for shortest paths.
+
+As in |gb_dijk|, we define pointers to priority queue subroutines
+so that the queueing mechanism can be varied.
+
+@d dist z.i /* this is the key field for vertices in the priority queue */
+@d backlink y.v /* this vertex is the stated |dist| away */
+
+@<Glob...@>=
+void (*init_queue)(); /* create an empty priority queue */
+void (*enqueue)(); /* insert a new element in the priority queue */
+void (*requeue)(); /* decrease the key of an element in the queue */
+Vertex *(*delete_min)(); /* remove an element with smallest key */
+
+@ The vertices in this algorithm are initially ``unseen''; they become
+``seen'' when they enter the priority queue, and finally ``known''
+when they leave it and enter the current fragment.
+We will put a special constant in the |backlink| field
+of known vertices. A vertex will be unseen iff its |backlink| is~|NULL|.
+
+@d KNOWN (Vertex*)1 /* special |backlink| to mark known vertices */
+
+@<Sub...@>=
+unsigned long jar_pr(g)
+ Graph *g;
+{@+register Vertex *t; /* vertex that is just becoming known */
+ int fragment_size; /* number of vertices in the tree so far */
+ unsigned long tot_len=0; /* sum of edge lengths in the tree so far */
+ mems=0;
+ @<Make |t=g->vertices| the only vertex seen; also make it known@>;
+ while (fragment_size<g->n) {
+ @<Put all unseen vertices adjacent to |t| into the queue,
+ and update the distances of the other vertices adjacent to~|t|@>;
+ t=(*delete_min)();
+ if (t==NULL) return INFINITY; /* the graph is disconnected */
+ if (verbose) report(t->backlink,t,t->dist);
+ o,tot_len+=t->dist;
+ o,t->backlink=KNOWN;
+ fragment_size++;
+ }
+ return tot_len;
+}
+
+@ Notice that we don't charge any mems for the subroutine call
+to |init_queue|, except for mems counted in the subroutine itself.
+What should we charge in general for subroutine linkage when we are
+counting mems? The parameters to subroutines generally go into
+registers, and registers are ``free''; also, a compiler can often
+choose to implement a procedure in line, thereby reducing the
+overhead to zero. Hence, the recommended method for charging mems
+with respect to subroutines is: Charge nothing if the subroutine
+is not recursive; otherwise charge twice the number of things that need
+to be saved on a runtime stack. (The return address is one of the
+things that needs to be saved.)
+@^discussion of \\{mems}@>
+
+@<Make |t=g->vertices| the only vertex seen; also make it known@>=
+for (oo,t=g->vertices+g->n-1;t>g->vertices;t--) o,t->backlink=NULL;
+o,t->backlink=KNOWN;
+fragment_size=1;
+(*init_queue)(0); /* make the priority queue empty */
+
+@ @<Put all unseen vertices adjacent to |t| into the queue,
+ and update the distances of the other vertices adjacent to~|t|@>=
+{@+register Arc *a; /* an arc leading from |t| */
+ for (o,a=t->arcs; a; o,a=a->next) {
+ register Vertex *v; /* a vertex adjacent to |t| */
+ o,v=a->tip;
+ if (o,v->backlink) { /* |v| has already been seen */
+ if (v->backlink>KNOWN) {
+ if (oo,a->len<v->dist) {
+ o,v->backlink=t;
+ (*requeue)(v,a->len); /* we found a better way to get there */
+ }
+ }
+ } else { /* |v| hasn't been seen before */
+ o,v->backlink=t;
+ o,(*enqueue)(v,a->len);
+ }
+ }
+}
+
+@*Binary heaps.
+To complete the |jar_pr| routine, we need to fill in the four
+priority queue functions. Jarn{\'\i}k wrote his original paper before
+computers were known; Prim and Dijkstra wrote theirs before efficient priority
+queue algorithms were known. Their original algorithms therefore
+took $\Theta(n^2)$ steps.
+Kerschenbaum and Van Slyke pointed out in 1972 that binary heaps could
+do better. A simplified version of binary heaps (invented by Williams
+in 1964) is presented here.
+
+A binary heap is an array of |n| elements, and we need space for it.
+Fortunately the space is already there; we can use utility field
+|u| in each of the vertex records of the graph. Moreover, if
+|heap_elt(i)| points to vertex~|v|, we will arrange things so that
+|v->heap_index=i|.
+
+@d heap_elt(i) (gv+i)->u.v /* the |i|th vertex of the heap; |gv=g->vertices| */
+@d heap_index v.i /* the |v| utility field says where a vertex is in the heap */
+
+@<Glob...@>=
+Vertex *gv; /* |g->vertices|, the base of the heap array */
+int hsize; /* the number of elements currently in the heap */
+
+@ To initialize the heap, we need only initialize two ``registers'' to
+known values, so we don't have to charge any mems at all. (In a production
+implementation, this code would appear in-line as part of the
+spanning tree algorithm.)
+@^discussion of \\{mems}@>
+
+Important Note: This routine refers to the global variable |g|, which is
+set in |main| (not in |jar_pr|). Suitable changes need to be made
+if these binary heap routines are used in other programs.
+
+@<Priority queue subroutines@>=
+void init_heap(d) /* makes the heap empty */
+ long d;
+{
+ gv=g->vertices;
+ hsize=0;
+}
+
+@ The key invariant property that makes heaps work is
+$$\hbox{|heap_elt(k/2)->dist<=heap_elt(k)->dist|, \qquad for |1<k<=hsize|.}$$
+(A reader who has not seen heap ordering before should stop at this
+point and study the beautiful consequences of this innocuously simple
+set of inequalities.) The enqueuing operation turns out to be quite simple:
+
+@<Priority queue subroutines@>=
+void heap_enqueue(v,d)
+ Vertex *v; /* vertex that is entering the queue */
+ long d; /* its key (aka |dist|) */
+{@+register unsigned k; /* position of a ``hole'' in the heap */
+ register unsigned j; /* the parent of that position */
+ register Vertex *u; /* |heap_elt(j)| */
+ o,v->dist=d;
+ k=++hsize;
+ j=k>>1; /* |k/2| */
+ while (j>0 && (oo,(u=heap_elt(j))->dist>d)) {
+ o,heap_elt(k)=u; /* the hole moves to parent position */
+ o,u->heap_index=k;
+ k=j;
+ j=k>>1;
+ }
+ o,heap_elt(k)=v;
+ o,v->heap_index=k;
+}
+
+@ And in fact, the general requeuing operation is almost identical to
+enqueueing. This operation is popularly called ``siftup,'' because
+the vertex whose key is being reduced may displace its ancestors
+higher in the heap. We could have implemented enqueuing by first
+placing the new element at the end of the heap, then requeuing it;
+that would have cost at most a couple mems more.
+
+@<Priority queue subroutines@>=
+void heap_requeue(v,d)
+ Vertex *v; /* vertex whose key is being reduced */
+ long d; /* its new |dist| */
+{@+register unsigned k; /* position of ``hole'' in the heap */
+ register unsigned j; /* the parent of that position */
+ register Vertex *u; /* |heap_elt(j)| */
+ o,v->dist=d;
+ o,k=v->heap_index; /* now |heap_elt(k)=v| */
+ j=k>>1; /* |k/2| */
+ if (j>0 && (oo,(u=heap_elt(j))->dist>d)) { /* change is needed */
+ do@+{
+ o,heap_elt(k)=u; /* the hole moves to parent position */
+ o,u->heap_index=k;
+ k=j;
+ j=k>>1; /* |k/2| */
+ }@+while (j>0 && (oo,(u=heap_elt(j))->dist>d));
+ o,heap_elt(k)=v;
+ o,v->heap_index=k;
+ }
+}
+
+@ Finally, the procedure for removing the vertex with smallest key is only
+a bit more difficult. The vertex to be removed is always |heap_elt(1)|. After we
+delete it, we ``sift down'' |heap_elt(hsize)|, until the basic heap
+inequalities hold once again.
+
+At a crucial point below, we have |j->dist<u->dist|; we cannot then have
+|j=hsize+1|, because the previous steps have made |(hsize+1)->dist=u->dist=d|.
+
+@<Prior...@>=
+Vertex *delete_from_heap()
+{@+Vertex *v; /* vertex to return */
+ register Vertex *u; /* vertex being sifted down */
+ register unsigned k; /* hole in the heap */
+ register unsigned j; /* child of that hole */
+ register long d; /* |u->dist|, the vertex of the vertex being sifted */
+ if (hsize==0) return NULL;
+ o,v=heap_elt(1);
+ o,u=heap_elt(hsize--);
+ o,d=u->dist;
+ k=1;
+ j=2;
+ while (j<=hsize) {
+ if (oooo,heap_elt(j)->dist>heap_elt(j+1)->dist) j++;
+ if (heap_elt(j)->dist>=d) break;
+ o,heap_elt(k)=heap_elt(j); /* NB: we cannot have |j>hsize|, see above */
+ o,heap_elt(k)->heap_index=k;
+ k=j; /* the hole moves to child position */
+ j=k<<1; /* |2k| */
+ }
+ o,heap_elt(k)=u;
+ o,u->heap_index=k;
+ return v;
+}
+
+@ OK, here's the way we plug binary heaps into Jarn{\'\i}k/Prim.
+
+@<Execute |jar_pr(g)| with binary heaps as the priority queue algorithm@>=
+init_queue=init_heap;
+enqueue=heap_enqueue;
+requeue=heap_requeue;
+delete_min=delete_from_heap;
+if (sp_length!=jar_pr(g)) {
+ printf(" ...oops, I've got a bug, please fix fix fix\n");
+ return -4;
+}
+
+@*Fibonacci heaps.
+The running time of Jarn{\'\i}k/Prim with binary heaps, when the algorithm is
+applied to a connected graph with |n| vertices and |m| edges, is $O(m\log n)$,
+because the total number of operations is $O(m+n)=O(m)$ and each
+heap operation takes at most $O(\log n)$ time.
+
+Fibonacci heaps were invented by Fredman and Tarjan in 1984, in order
+to do better than this. The Jarn{\'\i}k/Prim algorithm does $O(n)$
+enqueuing operations, $O(n)$ delete-min operations, and $O(m)$
+requeueing operations; so Fredman and Tarjan designed a data structure
+that would support requeueing in ``constant amortized time.'' In other
+words, Fibonacci heaps allow us to do $m$ requeueing operations with a
+total cost of~$O(m)$, even though some of the individual requeuings
+might take longer. The resulting asymptotic running time is then
+$O(m+n\log n)$. (This turns out to be optimum within a constant
+factor, when the same technique is applied to Dijkstra's algorithm for
+shortest paths. But for minimum spanning trees the Fibonacci method is
+not always optimum; for example, if $m\approx n\sqrt{\,\mathstrut\log n}$, the
+algorithm of Cheriton and Tarjan has slightly better asymptotic
+behavior, $O(m\log\log n)$.)
+
+Fibonacci heaps are more complex than binary heaps, so we can expect
+that overhead costs will make them non-competitive unless $m$ and $n$ are
+quite large. Furthermore, it is not clear that the running time with simple
+binary heaps will behave as $m\log n$ on realistic data, because
+$O(m\log n)$ is a worst-case estimate based on rather pessimistic
+assumptions. (For example, requeueuing might rarely require many
+iterations of the siftup loop.) But anyway, it will be instructive to
+implement Fibonacci heaps as best we can, just to see how good they
+look in actual practice.
+
+Let us say that the {\it rank\/} of a node in a forest is the number
+of children it has. A Fibonacci heap is an unordered forest of trees
+in which the key of each node is less than or equal to the key of each
+child of that node, and in which the following further condition,
+called property~F, also holds: The ranks $\{r_1,r_2,\ldots,r_k\}$ of the
+children of every node of rank~$k$, when put into nondecreasing
+order $r_1\le r_2\le\cdots\le r_k$, satisfy $r_j\ge j-2$ for all~$j$.
+
+As a consequence of property F, we can prove by induction that every
+node of rank~$k$ has at least $F_{k+2}$ descendants (including itself).
+Therefore, for example, we cannot have a node of rank $\ge30$ unless
+the total size of the forest is at least $F_{32}=2{,}178{,}309$. We cannot
+have a node of rank $\ge46$ unless the total size of the forest
+exceeds~$2^{32}$.
+
+@ We will represent a Fibonacci heap with a rather elaborate data structure,
+in order to guarantee the efficiency of all the necessary operations.
+Each node will have four pointers: |parent|, the node's parent (or
+|NULL| if the node is a root); |child|, one of the node's children
+(or undefined if the node has no children); |lsib| and |rsib|, the
+node's left and right siblings. The children of each node, and the
+roots of the forest, are doubly linked by |lsib| and |rsib| in
+circular lists; the nodes in these lists can appear in any convenient
+order, and the |child| pointer can point to any child.
+
+Besides the four pointers, there is a \\{rank} field, which tells how
+many children exist; and a \\{tag} field, which is either 0 or~1.
+
+Suppose a node has children of ranks $\{r_1,r_2,\ldots,r_k\}$, where
+$r_1\le r_2\le\cdots\le r_k$. We know that $r_j\ge j-2$ for all~$j$;
+we say that the node has $l$ {\it critical\/} children if there are
+$l$ cases of equality, where $r_j=j-2$. Our implementation will
+guarantee that any node with $l$ critical children will have at
+least $l$ tagged children of the corresponding ranks. For example,
+suppose a node has seven children, of respective ranks $\{1,1,1,2,4,4,6\}$.
+Then it has three critical children, because $r_3=1$, $r_4=2$, and
+$r_6=4$. In our implementation, at least one of the children of
+rank~1 will have $\\{tag}=1$, and so will the child of rank~2, and so will
+one of the children of rank~4.
+
+There is an external pointer called |F_heap|, which indicates a node
+whose key is smallest. (If the heap is empty, |F_heap| is~|NULL|.)
+
+@<Prior...@>=
+void init_F_heap(d)
+ long d;
+{@+F_heap=NULL;@+}
+
+@ @<Glob...@>=
+Vertex *F_heap; /* pointer to the ring of root nodes */
+
+@ We can save a bit of space and time by combining the \\{rank} and \\{tag}
+fields into a single |rank_tag| field, which contains $\\{rank}*2+\\{tag}$.
+
+Vertices in GraphBase graphs have six utility fields. That's just enough
+for |parent|, |child|, |lsib|, |rsib|, |rank_tag|, and the key field
+|dist|. But unfortunately we also need the |backlink| field, so
+we are over the limit. That's not really so bad, however; we
+can set up another array of $n$ records, and point to it. The
+extra running time needed for indirect pointing does not have to
+be charged to mems, because a production system involving Fibonacci
+heaps would simply redefine |Vertex| records to have seven utility
+fields instead of six. In this way we can simulate the behavior of larger
+records without changing the basic GraphBase conventions.
+@^discussion of \\{mems}@>
+
+We will want an |Arc| record for each vertex in our next algorithm,
+so we might as well allocate storage for it now even though Fibonacci
+heaps need only two of the five fields.
+
+@d newarc u.a /* |v->newarc| points to an |Arc| record associated with |v| */
+@d parent newarc->tip
+@d child newarc->a.v
+@d lsib v.v
+@d rsib w.v
+@d rank_tag x.i
+
+@<Allocate additional space needed by the more complex algorithms...@>=
+{@+register Arc *aa;
+ register Vertex *uu;
+ aa=gb_alloc_type(g->n,@[Arc@],g->aux_data);
+ if (aa==NULL) {
+ printf(" and there isn't enough space to try the other methods.\n\n");
+ goto done;
+ }
+ for (uu=g->vertices;uu<g->vertices+g->n;uu++,aa++)
+ uu->newarc=aa;
+}
+
+@ The {\it potential energy\/} of a Fibonacci heap, as we are
+representing it, is defined to be the number of trees in the forest
+plus twice the total number of tagged children. When we operate on a
+heap, we will store potential energy to be used up later; then it will
+be possible to do the later operations with only a small incremental
+cost to the running time. (Potential energy is just a way to prove
+that the amortized cost is small; it does not appear explicitly in our
+implementation. It simply explains why the number of mems we compute
+will always be $O(m+n\log n)$.)
+
+Enqueueing is easy: We simply insert the new element as a new tree in
+the forest. This costs a constant amount of time, including the cost of
+one new unit of potential energy for the new tree.
+
+We can assume that |F_heap->dist| appears in a register, so we need not
+charge a mem to fetch it.
+
+@<Prior...@>=
+void F_heap_enqueue(v,d)
+ Vertex *v; /* vertex that is entering the queue */
+ long d; /* its key (aka |dist|) */
+{
+ o,v->dist=d;
+ o,v->parent=NULL;
+ o,v->rank_tag=0; /* |v->child| need not be set */
+ if (F_heap==NULL) {
+ oo,F_heap=v->lsib=v->rsib=v;
+ } else {@+register Vertex *u;
+ o,u=F_heap->lsib;
+ o,v->lsib=u;
+ o,v->rsib=F_heap;
+ oo,F_heap->lsib=u->rsib=v;
+ if (F_heap->dist>d) F_heap=v;
+ }
+}
+
+@ Requeueing is of medium difficulty. If the key is being decreased in
+a root node, or if the decrease doesn't make the key less than the key
+of its parent, no links need to change (except possibly |F_heap|
+itself). Otherwise, we detach the node and its descendants from its
+present family and put this former subtree into the forest as a new
+tree. (One unit of potential energy must be stored with it.)
+
+The rank of the former parent, |p|, decreases by~1. If |p| is a root,
+we're done. Otherwise if |p| was not tagged, we tag it (and pay for
+two additional units of energy); property~F still holds, because an
+untagged node can always admit a decrease in rank. If |p| was tagged,
+however, we detach |p| and its remaining descendants, making it another
+new tree of the forest, with |p| no longer tagged. Removing the tag
+releases enough stored energy to pay for the extra work of moving~|p|.
+Then we must decrease the rank of |p|'s parent, and so on, until finally
+we get to a root or to an untagged node. The total net cost is at most
+three units of energy plus the cost of relinking the original node,
+so it is $O(1)$.
+
+We needn't clear the tag fields of root nodes, because we never
+look at them.
+
+@<Prior...@>=
+void F_heap_requeue(v,d)
+ Vertex *v; /* vertex whose key is being reduced */
+ long d; /* its new |dist| */
+{@+register Vertex *p,*pp; /* parent and grandparent of |v| */
+ register Vertex *u,*w; /* other vertices being modified */
+ register int r; /* twice the rank plus the tag */
+ o,v->dist=d;
+ o,p=v->parent;
+ if (p==NULL) {
+ if (F_heap->dist>d) F_heap=v;
+ } else if (o,p->dist>d)
+ while(1) {
+ o,r=p->rank_tag;
+ if (r>=4) /* |v| is not an only child */
+ @<Remove |v| from its family@>;
+ @<Insert |v| into the forest@>;
+ o,pp=p->parent;
+ if (pp==NULL) { /* the parent of |v| is a root */
+ o,p->rank_tag=r-2;@+break;
+ }
+ if ((r&1)==0) { /* the parent of |v| is untagged */
+ o,p->rank_tag=r-1;@+break; /* now it's tagged */
+ } else o,p->rank_tag=r-2; /* tagged parent will become a root */
+ v=p;@+p=pp;
+ }
+}
+
+@ @<Remove |v| from its family@>=
+{
+ o,u=v->lsib;
+ o,w=v->rsib;
+ o,u->rsib=w;
+ o,w->lsib=u;
+ if (o,p->child==v) o,p->child=w;
+}
+
+@ @<Insert |v| into the forest@>=
+o,v->parent=NULL;
+o,u=F_heap->lsib;
+o,v->lsib=u;
+o,v->rsib=F_heap;
+oo,F_heap->lsib=u->rsib=v;
+if (F_heap->dist>d) F_heap=v; /* this can happen only with the original |v| */
+
+@ The |delete_min| operation is even more interesting; this, in fact,
+is where most of the action lies. We know that |F_heap| points to the
+vertex~|v| we will be deleting. That's nice, but we need to figure out
+the new value of |F_heap|. So we have to look at all the children of~|v|
+and at all the root nodes in the forest. We have stored up enough
+potential energy to do that, but we can reclaim the potential only if
+we rebuild the Fibonacci heap so that the rebuilt version contains
+relatively few trees.
+
+The solution is to make sure that the new heap has at most one root
+of each rank. Whenever we have two tree roots of equal rank, we can
+make one the child of the other, thus reducing the number of
+trees by~1. (The new child does not violate Property~F, nor is it
+critical, so we can mark it untagged.) The largest rank is always
+$O(\log n)$, if there are |n| nodes altogether, and we can afford to
+pay $\log n$ units of time for the work that isn't reclaimed from
+potential energy.
+
+An array of pointers to roots of known rank is used to help control
+this part of the process.
+
+@<Glob...@>=
+Vertex *new_roots[46]; /* big enough for queues of size $2^{32}$ */
+
+@ @<Prio...@>=
+Vertex *delete_from_F_heap()
+{@+Vertex *final_v=F_heap; /* the node to return */
+ register Vertex *t,*u,*v,*w; /* registers for manipulation of links */
+ register int h=-1; /* the highest rank present in |new_roots| */
+ register int r; /* rank of current tree */
+ if (F_heap) {
+ if (o,F_heap->rank_tag<2) o,v=F_heap->rsib;
+ else {
+ o,w=F_heap->child;
+ o,v=w->rsib;
+ oo,w->rsib=F_heap->rsib; /* link children of deleted node into the list */
+ for (w=v;w!=F_heap->rsib;o,w=w->rsib)
+ o,w->parent=NULL;
+ }
+ while (v!=F_heap) {
+ o,w=v->rsib;
+ @<Put the tree rooted at |v| into the |new_roots| forest@>;
+ v=w;
+ }
+ @<Rebuild |F_heap| from |new_roots|@>;
+ }
+ return final_v;
+}
+
+@ The work we do in this step is paid for by the unit of potential
+energy being freed as |v| leaves the old forest, except for the
+work of increasing~|h|; we charge the latter to the $O(\log n)$ cost of
+building |new_roots|.
+
+@<Put the tree rooted at |v| into the |new_roots| forest@>=
+o,r=v->rank_tag>>1;
+while (1) {
+ if (h<r) {
+ do@+{
+ h++;
+ o,new_roots[h]=(h==r?v:NULL);
+ }@+while (h<r);
+ break;
+ }
+ if (o,new_roots[r]==NULL) {
+ o,new_roots[r]=v;
+ break;
+ }
+ u=new_roots[r];
+ o,new_roots[r]=NULL;
+ if (oo,u->dist<v->dist) {
+ o,v->rank_tag=r<<1; /* |v| is not critical and needn't be tagged */
+ t=u;@+u=v;@+v=t;
+ }
+ @<Make |u| a child of |v|@>;
+ r++;
+}
+o,v->rank_tag=r<<1; /* every root in |new_roots| is untagged */
+
+@ When we get to this step, |u| and |v| both have rank |r|, and
+|u->dist>=v->dist|; |u| is untagged.
+
+@<Make |u| a child of |v|@>=
+if (r==0) {
+ o,v->child=u;
+ oo,u->lsib=u->rsib=u;
+} else {
+ o,t=v->child;
+ oo,u->rsib=t->rsib;
+ o,u->lsib=t;
+ oo,u->rsib->lsib=t->rsib=u;
+}
+u->parent=v;
+
+@ And now we can breathe easy, because the last step is trivial.
+
+@<Rebuild |F_heap| from |new_roots|@>=
+if (h<0) F_heap=NULL;
+else {@+int d; /* smallest key value seen so far */
+ o,u=v=new_roots[h];
+ /* |u| and |v| will point to beginning and end of list, respectively */
+ o,d=u->dist;
+ F_heap=u;
+ for (h--;h>=0;h--)
+ if (o,new_roots[h]) {
+ w=new_roots[h];
+ o,w->lsib=v;
+ o,v->rsib=w;
+ if (o,w->dist<d) {
+ F_heap=w;
+ d=w->dist;
+ }
+ v=w;
+ }
+ o,v->rsib=u;
+ o,u->lsib=v;
+}
+
+@ @<Execute |jar_pr(g)| with Fibonacci heaps...@>=
+init_queue=init_F_heap;
+enqueue=F_heap_enqueue;
+requeue=F_heap_requeue;
+delete_min=delete_from_F_heap;
+if (sp_length!=jar_pr(g)) {
+ printf(" ...oops, I've got a bug, please fix fix fix\n");
+ return -5;
+}
+
+@*Binomial queues.
+Jean Vuillemin's ``binomial queue'' structures [{\sl CACM\/ \bf21} (1978),
+309--314] provide yet another appealing way to maintain priority queues.
+A binomial queue is a forest of trees with heap ordering between keys,
+satisfying two conditions that are considerably stronger than
+the Fibonacci heap property: Each node of rank~$k$ has children of
+respective ranks $\{0,1,\ldots,k-1\}$; and each root of the forest
+has a different rank. It follows that each node of rank~$k$ has exactly
+$2^k$ descendants (including itself), and that a binomial queue of
+$n$ elements has exactly as many trees as the number $n$ has 1's in
+binary notation.
+
+We could plug binomial queues into the Jarn{\'\i}k/Prim algorithm, but
+they don't offer advantages over the heap methods already considered
+because they don't support the requeueing operation as nicely.
+Binomial queues do, however, permit efficient merging---the operation
+of combining two priority queues into one---and they achieve this
+without as much space overhead as Fibonacci heaps. In fact, we can
+implement binomial queues with only two pointers per node, namely a
+pointer to the largest child and to the next sibling. This means we
+have just enough space in the utility fields of GraphBase |Arc| records
+to link the arcs that extend out of a spanning tree fragment. The
+algorithm of Cheriton, Tarjan, and Karp, to be considered in the next
+section, maintains priority queues of arcs, not vertices; and it
+requires the operation of merging, not requeueing. Therefore binomial
+queues are well suited to it, and we will prepare ourselves for that
+algorithm by implementing basic binomial queue procedures.
+
+Incidentally, if you wonder why Vuillemin called his structure a binomial
+queue, it's because the trees of $2^k$ elements have many pleasant combinatorial
+properties, among which is the fact that the number of elements on
+level~$l$ is the binomial coefficient~$k\choose l$. The backtrack tree
+for subsets of a $k$-set has the same structure. A picture of a
+binomial-queue tree with $k=5$, drawn by Jill~C. Knuth, appears
+as the frontispiece of {\sl The Art of Computer Programming},
+facing page~1 of Volume~1.
+
+@d qchild a.a /* pointer to the arc for largest child of an arc */
+@d qsib b.a /* pointer to next larger sibling, or from largest to smallest */
+
+@ A special header node is used at the head of a binomial queue, to represent
+the queue itself. The |qsib| field of this node points to the smallest
+root node in the forest. (``Smallest'' means smallest in rank, not in
+key value.) The header also contains a |qcount| field, which
+takes the place of |qchild|; the |qcount| is the total number of node,
+so its binary representation characterizes the sizes of the trees
+accessible from |qsib|.
+
+For example, suppose a queue with header node |h| contains five elements
+$\{a,b,c,d,e\}$ whose keys happen to be ordered alphabetically. The first
+tree might be the single node~$c$; the other tree might be rooted at~$a$,
+with children $e$ and~$b$. Then we have
+$$\vbox{\halign{#\hfil&\qquad#\hfil\cr
+|h->qcount=5|,&|h->qsib=c|;\cr
+|c->qsib=a|;\cr
+|a->qchild=b|;\cr
+|b->qchild=d|,&|b->qsib=e|;\cr
+|e->qsib=b|.\cr}}$$
+The other fields |c->qchild|, |a->qsib|, |e->qchild|, |d->qsib|, and
+|d->qchild| are undefined. We can save time by not loading or storing the
+undefined fields, which make up about 3/8 of the structure.
+
+An empty binomial queue would have |h->qcount=0| and |h->qsib| undefined.
+
+Like Fibonacci heaps, binomial queues store potential energy: The
+number of energy units present is simply the number of trees in the forest.
+
+@d qcount a.i /* this field takes the place of |qchild| in header nodes */
+
+@ Most of the operations we wish to do with binomial queues rely on
+the following basic subroutine, which merges a forest of |m| nodes
+starting at |q| with a forest of |mm| nodes starting at |qq|, putting
+a pointer to the resulting forest of |m+mm| nodes into |h->qsib|.
+The amortized running time is $O(\log m)$, independent of |mm|.
+
+The |len| field, not |dist|, is the key field for this queue, because our
+nodes in this case are arcs instead of vertices.
+
+@<Prio...@>=
+qunite(m,q,mm,qq,h)
+ register long m,mm; /* number of nodes in the forests */
+ register Arc *q,*qq; /* binomial trees in the forests, linked by |qsib| */
+ Arc *h; /* |h->qsib| will get the result */
+{@+register Arc *p; /* tail of the list built so far */
+ register long k=1; /* size of trees currently being processed */
+ p=h;
+ while (m) {
+ if ((m&k)==0) {
+ if (mm&k) { /* |qq| goes into the merged list */
+ o,p->qsib=qq;@+p=qq;@+mm-=k;
+ if (mm) o,qq=qq->qsib;
+ }
+ } else if ((mm&k)==0) { /* |q| goes into the merged list */
+ o,p->qsib=q;@+p=q;@+m-=k;
+ if (m) o,q=q->qsib;
+ } else @<Combine |q| and |qq| into a ``carry'' tree, and continue
+ merging until the carry no longer propagates@>;
+ k<<=1;
+ }
+ if (mm) o,p->qsib=qq;
+}
+
+@ As we have seen in Fibonacci heaps, two heap-ordered trees can be combined
+by simply attaching one as a new child of the other. This operation preserves
+binomial trees. (In fact, if we use Fibonacci heaps without ever doing
+a requeue operation, the forests that appear after every |delete_min|
+are binomial queues.) The number of trees decreases by~1, so we have a
+unit of potential energy to pay for this computation.
+
+@<Combine |q| and |qq| into a ``carry'' tree, and continue
+ merging until the carry no longer propagates@>=
+{@+register Arc *c; /* the ``carry,'' a tree of size |2k| */
+ register long key; /* |c->len| */
+ register Arc *r,*rr; /* remainders of the input lists */
+ m-=k;@+if (m) o,r=q->qsib;
+ mm-=k;@+if (mm) o,rr=qq->qsib;
+ @<Set |c| to the combination of |q| and |qq|@>;
+ k<<=1;@+q=r;@+qq=rr;
+ while ((m|mm)&k) {
+ if ((m&k)==0) @<Merge |qq| into |c| and advance |qq|@>@;
+ else {
+ @<Merge |q| into |c| and advance |q|@>;
+ if (mm&k) {
+ o,p->qsib=qq;@+p=qq;@+mm-=k;
+ if (mm) o,qq=qq->qsib;
+ }
+ }
+ k<<=1;
+ }
+ o,p->qsib=c;@+p=c;
+}
+
+@ @<Set |c| to the combination of |q| and |qq|@>=
+if (oo,q->len<qq->len) {
+ c=q,key=q->len;
+ q=qq;
+} else c=qq,key=qq->len;
+if (k==1) o,c->qchild=q;
+else {
+ o,qq=c->qchild;
+ o,c->qchild=q;
+ if (k==2) o,q->qsib=qq;
+ else oo,q->qsib=qq->qsib;
+ o,qq->qsib=q;
+}
+
+@ At this point, |k>1|.
+
+@<Merge |q| into |c| and advance |q|@>=
+{
+ m-=k;@+if (m) o,r=q->qsib;
+ if (o,q->len<key) {
+ rr=c;@+c=q;@+key=q->len;@+q=rr;
+ }
+ o,rr=c->qchild;
+ o,c->qchild=q;
+ if (k==2) o,q->qsib=rr;
+ else oo,q->qsib=rr->qsib;
+ o,rr->qsib=q;
+ q=r;
+}
+
+@ @<Merge |qq| into |c| and advance |qq|@>=
+{@+register Arc *t;
+ mm-=k;@+if (mm) o,rr=qq->qsib;
+ if (o,qq->len<key) {
+ r=c;@+c=qq;@+key=qq->len;@+qq=r;
+ }
+ o,r=c->qchild;
+ o,c->qchild=qq;
+ if (k==2) o,qq->qsib=r;
+ else oo,qq->qsib=r->qsib;
+ o,r->qsib=qq;
+ qq=rr;
+}
+
+@ OK, now the hard work is done and we can reap the fruits of the
+basic |qunite| routine. One easy application enqueues a new arc
+in $O(1)$ amortized time.
+
+@<Prio...@>=
+qenque(h,a)
+ Arc *h; /* header of a binomial queue */
+ Arc *a; /* new element for that queue */
+{@+long m;
+ o,m=h->qcount;
+ o,h->qcount=m+1;
+ if (m==0) o,h->qsib=a;
+ else o,qunite(1,a,m,h->qsib,h);
+}
+
+@ Here, similarly, is a routine that merges one binomial queue into
+another. The amortized running time is proportional to the logarithm
+of the number of nodes in the smaller queue.
+
+@<Prio...@>=
+qmerge(h,hh)
+ Arc *h; /* header of binomial queue that will receive the result */
+ Arc *hh; /* header of binomial queue that will be absorbed */
+{@+long m,mm;
+ o,mm=hh->qcount;
+ if (mm) {
+ o,m=h->qcount;
+ o,h->qcount=m+mm;
+ if (m>=mm) oo,qunite(mm,hh->qsib,m,h->qsib,h);
+ else if (m==0) oo,h->qsib=hh->qsib;
+ else oo,qunite(m,h->qsib,mm,hh->qsib,h);
+ }
+}
+
+@ The other important operation is, of course, deletion of a node
+with the smallest key. The amortized running time is proportional to
+the logarithm of the queue size.
+
+@<Prio...@>=
+Arc *qdelete_min(h)
+ Arc *h; /* header of binomial queue */
+{@+register Arc *p,*pp; /* current node and its predecessor */
+ register Arc *q,*qq; /* current minimum node and its predecessor */
+ register long key; /* |q->len|, the smallest key known so far */
+ long m; /* number of nodes in the queue */
+ long k; /* number of nodes in tree |q| */
+ register long mm; /* number of nodes not yet considered */
+ o,m=h->qcount;
+ if (m==0) return NULL;
+ o,h->qcount=m-1;
+ @<Find and remove a tree whose root |q| has the smallest key@>;
+ if (k>2) {
+ if (k+k<=m) oo,qunite(k-1,q->qchild->qsib,m-k,h->qsib,h);
+ else oo,qunite(m-k,h->qsib,k-1,q->qchild->qsib,h);
+ } else if (k==2) o,qunite(1,q->qchild,m-k,h->qsib,h);
+ return q;
+}
+
+@ If the tree with smallest key is the largest in the forest,
+we don't have to change any links to remove it,
+because our binomial queue algorithms never look at the last |qsib| pointer.
+
+We use a well known binary number trick: |m&(m-1)| is the same as
+|m| except that the least significant 1~bit is deleted.
+
+@<Find and remove...@>=
+mm=m&(m-1);
+o,q=h->qsib;
+k=m-mm;
+if (mm) { /* there's more than one tree */
+ p=q;@+qq=h;
+ o,key=q->len;
+ do@+{@+long t=mm&(mm-1);
+ pp=p;@+o,p=p->qsib;
+ if (o,p->len<=key) {
+ q=p;@+qq=pp;@+k=mm-t;@+key=p->len;
+ }
+ mm=t;
+ }@+while (mm);
+ if (k+k<=m) oo,qq->qsib=q->qsib; /* remove the tree rooted at |q| */
+}
+
+@ To complete our implementation, here is an algorithm that traverses
+a binomial queue, ``visiting'' each node exactly once, destroying the
+queue as it goes. The total number of mems required is about |1.75m|.
+
+@<Prio...@>=
+qtraverse(h,visit)
+ Arc *h; /* head of binomial queue to be unraveled */
+ void (*visit)(); /* procedure to be invoked on each node */
+{@+register long m; /* the number of nodes remaining */
+ register Arc *p,*q,*r; /* current position and neighboring positions */
+ o,m=h->qcount;
+ p=h;
+ while (m) {
+ o,p=p->qsib;
+ (*visit)(p);
+ if (m&1) m--;
+ else {
+ o,q=p->qchild;
+ if (m&2) (*visit)(q);
+ else {
+ o,r=q->qsib;
+ if (m&(m-1)) oo,q->qsib=p->qsib;
+ (*visit)(r);
+ p=r;
+ }
+ m-=2;
+ }
+ }
+}
+
+@* Cheriton, Tarjan, and Karp's algorithm.
+\def\lsqrtn{\hbox{$\lfloor\sqrt n\,\rfloor$}}%
+\def\usqrtn{\hbox{$\lfloor\sqrt{n+1}+{1\over2}\rfloor$}}%
+The final algorithm we shall consider takes yet another approach to
+spanning tree minimization. It operates in two distinct stages: Stage~1
+creates small fragments of the minimum tree, working locally with the
+edges that lead out of each fragment instead of dealing with the
+full set of edges at once as in Kruskal's method. As soon as the
+number of component fragments has been reduced from $n$ to \lsqrtn,
+stage~2 begins. Stage~2 runs through the remaining edges and builds a
+$\lsqrtn\times\lsqrtn$ matrix, which represents the problem of
+finding a minimum spanning tree on the remaining \lsqrtn\ components.
+A simple $O(\sqrt n\,)^2=O(n)$ algorithm then completes the job.
+
+The philosophy underlying stage~1 is that an edge leading out of a
+vertex in a small component is likely to lead to a vertex in another
+component, rather than in the same one. Thus each delete-min operation
+tends to be productive. Karp and Tarjan proved [{\sl Journal of Algorithms\/
+\bf1} (1980), 374--393] that the running time on a random graph with
+$n$ vertices and $m$ edges will be $O(m)$.
+
+The philosophy underlying stage~2 is that the problem
+on an initially sparse graph eventually reduces to a problem on a smaller
+but dense graph that is best solved by a different method.
+
+@<Sub...@>=
+unsigned long cher_tar_kar(g)
+ Graph *g;
+{@+@<Local variables for |cher_tar_kar|@>;
+ mems=0;
+ @<Do stage 1 of |cher_tar_kar|@>;
+ if (verbose) printf(" [Stage 1 has used %d mems]\n",mems);
+ @<Do stage 2 of |cher_tar_kar|@>;
+ return tot_len;
+}
+
+@ We say that a fragment is {\it large} if it contains \usqrtn\ or more
+vertices. As soon as a fragment becomes large, stage~1 stops trying
+to extend it. There cannot be more than \lsqrtn\ large fragments,
+because $(\lsqrtn+1)\usqrtn>n$. The other fragments are called {\it small}.
+
+Stage~1 keeps a list of all the small fragments; initially this list
+contains |n| fragments consisting of one vertex each. It
+repeatedly looks at the first fragment on its list, and finds the
+smallest edge leading to another fragment. These two fragments are
+removed from the list and combined; the resulting fragment is put at
+the end of the list if it is still small, or put onto another list if
+it is large.
+
+@<Local variables for |ch...@>=
+register Vertex *s,*t; /* beginning and end of the small list */
+Vertex *large_list; /* beginning of the list of large fragments */
+int frags; /* current number of fragments, large and small */
+unsigned long tot_len=0; /* total length of all edges in fragments */
+register Vertex *u,*v; /* registers for list manipulation */
+register Arc *a; /* and another */
+register int j,k; /* index registers for stage 2 */
+
+@ (We need to make |lo_sqrt| global so that the |note_edge| procedure
+below can access it.)
+
+@<Glob...@>=
+int lo_sqrt,hi_sqrt; /* \lsqrtn\ and \usqrtn\ */
+
+@ There is a nonobvious way to compute \usqrtn\ and \lsqrtn. Since
+$\sqrt n$ is small and arithmetic is mem-free, the author
+couldn't resist writing the |for| loop shown here.
+Of course, different ground rules for counting mems would be
+appropriate if this sort of computing were a critical factor in
+the running time.
+@^discussion of \\{mems}@>
+
+@<Do stage 1 of |cher_tar_kar|@>=
+o,frags=g->n;
+for (hi_sqrt=1;hi_sqrt*(hi_sqrt+1)<=frags;hi_sqrt++) ;
+if (hi_sqrt*hi_sqrt<=frags) lo_sqrt=hi_sqrt;
+else lo_sqrt=hi_sqrt-1;
+large_list=NULL;
+@<Create the small list@>;
+while (frags>lo_sqrt) {
+ @<Combine the first fragment on the small list with its nearest neighbor@>;
+ frags--;
+}
+
+@ To represent fragments, we will use several utility fields already
+defined above. The |lsib| and |rsib| pointers are used between fragments
+in the small list, which is doubly linked; |s|~points to the first small
+fragment, |s->rsib| to the next, \dots, |t->lsib| to the second-from-last,
+and |t| to the last. The pointer fields |s->lsib| and |t->rsib| are
+undefined. The |large_list| is singly linked via |rsib| pointers,
+terminating with |NULL|.
+
+The |csize| field of each fragment tells how many vertices it contains.
+
+The |class| field of each vertex is |NULL| if this vertex represents a
+fragment (i.e., if this vertex is in the small list or |large_list|);
+otherwise it points to another vertex that is closer to the fragment
+representative.
+
+Finally, the |pq| pointer of each fragment points to the header node of
+its priority queue, which is a binomial queue containing all
+unlooked-at arcs that originate from vertices in the fragment.
+This pointer is identical to the |newarc| pointer already set up;
+in a production implementation, we wouldn't need |pq| as a
+separate field, it would be part of a vertex record, so we do not
+pay any mems for referring to it.
+
+@d pq newarc
+
+@<Create the small...@>=
+o,s=g->vertices;
+for (v=s;v<s+frags;v++) {
+ if (v>s) {
+ o,v->lsib=v-1;@+o,(v-1)->rsib=v;
+ }
+ o,v->class=NULL;
+ o,v->csize=1;
+ o,v->pq->qcount=0; /* the binomial queue is initially empty */
+ for (o,a=v->arcs;a;o,a=a->next) qenque(v->pq,a);
+}
+t=v-1;
+
+@ @<Combine the first fragment...@>=
+v=s;
+o,s=s->rsib; /* remove |v| from small list */
+do@+{a=qdelete_min(v->pq);
+ if (a==NULL) return INFINITY; /* the graph isn't connected */
+ o,u=a->tip;
+ while (o,u->class) u=u->class; /* find the fragment pointed to */
+}@+while (u==v); /* repeat until a new fragment is found */
+if (verbose) @<Report the new edge verbosely@>;
+o,tot_len+=a->len;
+o,v->class=u;
+qmerge(u->pq,v->pq);
+o,old_size=u->csize;
+o,new_size=old_size+v->csize;
+o,u->csize=new_size;
+@<Move |u| to the proper list position@>;
+
+@ @<Local variables for |cher...@>=
+int old_size,new_size; /* size of fragment |u|, before and after */
+
+@ Here is a fussy part of the program. We have just merged the small
+fragment |v| into another fragment~|u|. If |u| was already large,
+there's nothing to do (except to check if the small list has just
+become empty). Otherwise we need to move |u| to the end of the small
+list, or put it onto the large list. All these cases are special, if we
+want to avoid unnecessary memory references; so let's hope we get them right.
+
+@<Move |u|...@>=
+if (old_size>=hi_sqrt) { /* |u| was large */
+ if (t==v) s=NULL; /* small list just became empty */
+} else if (new_size<hi_sqrt) { /* |u| was and still is small */
+ if (u==t) goto fin; /* |u| is already where we want it */
+ if (u==s) o,s=u->rsib; /* remove |u| from front */
+ else {
+ ooo,u->rsib->lsib=u->lsib; /* detach |u| from middle */
+ o,u->lsib->rsib=u->rsib; /* do you follow the mem-counting here? */
+@^discussion of \\{mems}@>
+ }
+ o,t->rsib=u; /* insert |u| at the end */
+ o,u->lsib=t;
+ t=u;
+} else { /* |u| has just become large */
+ if (u==t) {
+ if (u==s) goto fin; /* well, keep it small, we're done anyway */
+ o,t=u->lsib; /* remove |u| from end */
+ } else if (u==s)
+ o,s=u->rsib; /* remove |u| from front */
+ else {
+ ooo,u->rsib->lsib=u->lsib; /* detach |u| from middle */
+ o,u->lsib->rsib=u->rsib;
+ }
+ o,u->rsib=large_list;@+large_list=u; /* make |u| large */
+}
+fin:;
+
+@ We don't have room in our binomial queues to keep track of both
+endpoints of the arcs. But the arcs occur in pairs, and by looking
+at the address of |a| we can tell whether the matching arc is
+|a+1| or |a-1|. (See the explanation in |gb_graph|.)
+
+@<Report the new edge verbosely@>=
+report((edge_trick&(unsigned long)a? a-1: a+1)->tip,a->tip,a->len);
+
+@*Cheriton, Tarjan, and Karp's algorithm (continued).
+And now for the second part of the algorithm. Here we need to
+find room for a $\lsqrtn\times\lsqrtn$ matrix of edge lengths;
+we will use random access into the |z| utility fields of vertex records,
+since these haven't been used for anything yet by |cher_tar_kar|.
+We can also use the |v| utility fields to record the arcs that
+are the source of the best lengths, since this was the |lsib|
+field (no longer needed). This program doesn't count mems for
+updating that field, since it considers its goal to be simply
+the calculation of minimum spanning tree length; the actual
+edges of the minimum spanning tree are computed only for
+|verbose| mode. (We want to see how competitive |cher_tar_kar| is
+when we streamline it as much as possible.)
+
+In stage 2, the vertices will be assigned integer index numbers
+between 0 and $\lsqrtn-1$. We'll put this into the |csize| field,
+which is no longer needed, and call it |findex|.
+
+@d findex csize
+@d matx(j,k) (gv+((j)*lo_sqrt+(k)))->z.i
+ /* distance between fragments |j| and |k| */
+@d matx_arc(j,k) (gv+((j)*lo_sqrt+(k)))->v.a
+ /* arc corresponding to |matx(j,k)| */
+@d INF 30000 /* upper bound on all edge lengths */
+
+@<Do stage 2 of |cher_tar_kar|@>=
+gv=g->vertices; /* the global variable |gv| helps access auxiliary memory */
+@<Map all vertices to their index numbers@>;
+@<Create the reduced matrix by running through all remaining edges@>;
+@<Execute Prim's algorithm on the reduced matrix@>;
+
+@ The vertex-mapping algorithm is $O(n)$ because each nonnull |class| link
+is examined at most three times. We set the |class| field to null
+as an indication that |findex| has been set.
+
+@<Map all...@>=
+if (s==NULL) s=large_list;
+else t->rsib=large_list;
+for (k=0,v=s;v;o,v=v->rsib,k++) o,v->findex=k;
+for (v=g->vertices;v<g->vertices+g->n;v++)
+ if (o,v->class) {
+ for (t=v->class;o,t->class;t=t->class) ;
+ o,k=t->findex;
+ for (t=v;o,u=t->class;t=u) {
+ o,t->class=NULL;
+ o,t->findex=k;
+ }
+ }
+
+@ @<Create the reduced matrix by running through all remaining edges@>=
+for (j=0;j<lo_sqrt;j++) for (k=0;k<lo_sqrt;k++) o,matx(j,k)=INF;
+for (kk=0;s;o,s=s->rsib,kk++) qtraverse(s->pq,note_edge);
+
+@ The |note_edge| procedure ``visits'' every edge in the
+binomial queues traversed by |qtraverse| in the preceding code.
+Global variable |kk|, which would be a global register in a
+production version, is the index of the fragment from which
+this arc emanates.
+
+@<Procedures to be declared early@>=
+void note_edge(a)
+ Arc *a;
+{@+register int k;
+ o,k=a->tip->findex;
+ if (k==kk) return;
+ if (oo,a->len<matx(kk,k)) {
+ o,matx(kk,k)=a->len;
+ o,matx(k,kk)=a->len;
+ matx_arc(kk,k)=matx_arc(k,kk)=a;
+ }
+}
+
+@ As we work on the final subproblem of size $\lsqrtn\times\lsqrtn$,
+we'll have a short vector that tells us the distance to each fragment that
+hasn't yet been joined up with fragment~0. The vector has |-1| in positions
+that already have been joined up. In a production version, we could
+keep this in row~0 of |matx|.
+
+@<Glob...@>=
+int kk; /* current fragment */
+int distance[100]; /* distances to at most \lsqrtn\ unhit fragments */
+Arc *distance_arc[100]; /* the corresponding arcs, for |verbose| mode */
+
+@ The last step, as suggested by Prim, repeatedly updates
+the distance table against each row of the matrix as it is encountered.
+This is the algorithm of choice to find the minimum spanning tree of
+a complete graph.
+
+@<Execute Prim's algorithm on the reduced matrix@>=
+{@+int d; /* shortest entry seen so far in |distance| vector */
+ o,distance[0]=-1;
+ d=INF;
+ for (k=1;k<lo_sqrt;k++) {
+ o,distance[k]=matx(0,k);
+ distance_arc[k]=matx_arc(0,k);
+ if (distance[k]<d) d=distance[k],j=k;
+ }
+ while (frags>1)
+ @<Connect fragment 0 with fragment |j|, since |j| is the column
+ achieving the smallest distance, |d|; also compute |j| and |d|
+ for the next round@>;
+}
+
+@ @<Connect fragment 0...@>=
+{
+ if (d==INF) return INFINITY; /* the graph isn't connected */
+ o,distance[j]=-1; /* fragment |j| now will join up with fragment 0 */
+ tot_len+=d;
+ if (verbose) {
+ a=distance_arc[j];
+ @<Report the new edge verbosely@>;
+ }
+ frags--;
+ d=INF;
+ for (k=1;k<lo_sqrt;k++)
+ if (o,distance[k]>=0) {
+ if (o,matx(j,k)<distance[k]) {
+ o,distance[k]=matx(j,k);
+ distance_arc[k]=matx_arc(j,k);
+ }
+ if (distance[k]<d) d=distance[k],kk=k;
+ }
+ j=kk;
+}
+
+@* Conclusions. The winning algorithm, of the four methods considered
+here, on problems of the size considered here, is
+clearly Jarn{\'\i}k/Prim with binary heaps. Second is Kruskal with
+radix sorting, on sparse graphs, but the Fibonacci heap method beats
+it on dense graphs. Procedure |cher_tar_kar| never comes close,
+although every step it takes seems to be reasonably sensible and
+efficient, and although the implementation above gives it the benefit
+of every doubt when counting its mems. The reason it loses may be
+that it more or less gives up a factor of~2 by treating each edge
+twice; the other methods put very little effort into discarding an arc
+whose mate has already been processed.
+
+Perhaps the |krusk| procedure would go a bit faster if it were
+given a streamlined union/find algorithm?
+
+@* Index. We close with a list that shows where the identifiers of this
+program are defined and used. A special index term, `discussion of \\{mems}',
+indicates sections where there are nontrivial comments about instrumenting
+a \Cee\ program in the manner being recommended here.
+
diff --git a/support/graphbase/mona.dat b/support/graphbase/mona.dat
new file mode 100644
index 0000000000..9132c3ba88
--- /dev/null
+++ b/support/graphbase/mona.dat
@@ -0,0 +1,3605 @@
+* File "mona.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* La Gioconda by Leonardo, digitized in 360 rows and 250 columns
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 3600,849143729)
+545A5A55504E4F525450505255565657585A5A5E6062636464
+6362626365676A6C6C6A6765656A6B696663605D5A5B5D5E61
+65676868686B6E6B69686B6D6D6A666364686D6E6D6C6E7377
+7576797A7977737171717374777C8083838282817E7F828789
+8885827F7C787475797B7977787C7A75717071747677777777
+767575767777767775757371707072716F6F71716F6F6F6D6A
+69686869676464686C6C6968686B6E6E6D6E6E6B6764626363
+6162636261615F5C5654555657575553514F4E4F5051525355
+5657565554555454535251504E4C4E5051504E4F504E4A4A48
+464648494845424344474A4C4C4B4946454749484848494A4B.
+575B5A555152565A595656585B595758595B5E636464686D6E
+6964656B6F6D6D7073736F6C6968696C6D6C67615C5E636566
+696B6A696B6E706E6967686B6D6D6E6C6A6E73777674747678
+7C7E7E7F7F7D7A77757576777B7E7F808182807F8084898A8A
+8A8A87807975757B81817E7C7D7E7E7C77737477797A7A797B
+7C797877797B7B7B7B7B797978777776767676767675726E6B
+6B6D6C6C6C6867686A6B6A696A6E71706F7073736F6C6A6969
+696868686766645E595856575859585656565453525356595A
+59595A5A59585553525151515151515152525352524F4E4D4A
+4746484C4C474545474B4D4D4D4C4A46424344464747484A4A.
+61645C5555595B5B5A5B5B5D5D5C5B5B5C5E616365686E7374
+716E6F7478777778797874716C68696B6D6D6A666363666A6E
+71737271706F6F6E6A67686C7174747171757A7B7A7A7C7E7F
+8081828281807F80807E7C7B7D808284858585848688898B8E
+90908B827C797B8185858483838383817E7D7D7E7D7D7F8284
+81807F7F7F7F7F8082827F7E7B79797A7A7A7B7D7B76747372
+7171706E6C6C6C6B6B6B6B6C7072737274767676757473716F
+6C6B6B6C6D6D68615B595A5B5D5F5F5D5A595A5B5957585A5C
+5C5C5B5D5D5B57545354555656575657575756565452514F4E
+4D4E4F504F4D4C4B4D51535352514F4C484747484A4B4D4F4E.
+6267635C5A5B5D5E5F5F61636361606163646465676B707474
+7374797E7F7E7C7C7D7C7A756D69696D70706D6B6B6C6E6F72
+777A7A7A787571706E6D6E707072747676797C7E7E7F808182
+80848888858384878988837F808385878A8B89868687888B90
+93938F8882808084888988878787888988888987838081868B
+8B8886858485868787878583807E7D7D7E7F7F80807C7A7978
+787775726F70727373737273767977787A7B7A787878787775
+7270717476747067615F606263666663626262605D5B5C5E5F
+5E5D5D5E605E5A5858595B5D5C5C5B5C5C5C5A575554565756
+555554555454545455565656575654504E4D4D4E4F50535555.
+606867615E5F6267696767686969686767666667696C717577
+77787D848685838281807C77716D6F7174757572727475777A
+7E80807E7D7A7470717274757473767B7D7B7E818281828384
+84888B898685878A8D8C89868586898C8E8E8C8986878B9094
+9696938D8684878A8B8C8D8E8F908F8E8F91908C8682838A8F
+8E8B8C8D8D8E8F90908F8D88868382838584838282817F7D7C
+7B7B7B787373797D7D7B797A7C7E7F7E7F7F7D7C7D7E7D7A79
+7676787B7D7A736C696A6C6D6D6C6B6A6A6967626060616263
+626160606262605F5E5E5E5F5F5F5E5F5F5E5A5756575B5C5C
+5A5A59595757575B5D5E5B5A5A585654545353545556585959.
+6168666363686D6F6D686B6E706F6C6B6B6A696A6E74787B7C
+7C7D82888A8A8A87858483807B7778797A7A7877787A7A7C7F
+82828283827E787374777979787A7C7B7A7B7E828586868685
+868A8B8888898B8E91918E8B8C8C8D8F908F8D8D8E90939595
+9696938E8A898B8D8D8E9093949394949494928D8783878D91
+8F8D8F919294989B9C97938C8A8A8A8A89888684848382807D
+7E7F807B76798084838280808285858483827F7E8182807D7C
+7C7D80817E7774727475757371706F6E6E6E6A656363656767
+656364666766636261605F5F61616161615F5C5B5B5C5F605E
+5C5C5D5C5B5B5D60626262615F5C5A595656595958585A5C59.
+63696865676D71716F6C6F716E6B6B6E6F717372757A7F8080
+7F8184898F908C88888A8A8785807E7C7D7C7B7A797B7D7F81
+8382838484827F7A797A7D7F8182828282818183878889888A
+8B8D8C8C8D8D8E8F90908E90918F8F91939494959595959799
+999895918F8E918F8C8D91969897969695949493908E8D9092
+93919395989C9E9E9D9A96929393908D8C8D8B878482817F7F
+818484807E81848586878584858787868687878584827F7E80
+828483807C78797B7E7E7B787574747373716F6A6A6B6B6A69
+68696B6E6D6A68656464646566686866636160606265615F5D
+5C5D5E5F5D5D6165676B6C686461615F5F605F5C5A5A5B5C5B.
+60696C6C6C6D6E6F6E6C6D6E6D6B6A6C6F7275767A7F828383
+8384868A9092918F8E8E90908F898684817E7D7E8081818083
+85848283858684817F8084888A8A89888787878585878B8D8D
+8D8E8E8D8D8E8F8F8E8F9193908E8C8F94999A99999A9C9D9D
+9B989491929392908E8E9093969899979596989B9A98969596
+989897989B9DA0A19F9A999998979592908F8F8D8984807F82
+86898A878584868888858485898F8F8D8A8988888887868484
+868786827E7E80848482817E7C7B7A78777878706B6B6C6E6E
+6F6F717372716F6E6E6E6F6E6C6E6F6D6A666465656665625E
+5D5F6364616163676D71726F6A6867686968635F5C5C5D5F5F.
+626B706F6C6A69696B6E6D6C6A68696E7273757A7F83868888
+888A8E91939594929192949494918C8985827F7F8285868687
+86848383858889868384878B8D8E8C8A888A8C8B8B8D8F9191
+8F8F908F8D8F9292908F9092918F8C8E949CA1A09DA0A3A3A0
+9C9A9795969795929090909295989B9B97989B9E9F9E9C9A98
+9A9EA0A2A4A5A3A09F9D9D9C9A989697989897958E87838386
+898A8C8B89868687868484868B9093918D8C8D8E8C8A898989
+8C8D8B868283878A8B898885807D7C7B7C7D7A746F6E707374
+757575777877757575757372717272706D6A69696867676664
+646668696766696E7072747573716E6D6E6D6963605F5F6161.
+6771736F6B6B6B6A6B6E6D6C6B6B6D707273757C84888A8B8C
+8C8F9294939595949394959594908E8D89827D7C7F82858788
+878684858789888585888C8E8D8D8D8C8B8C8D8E9194959594
+939392908D8E91949494949392908F90969EA4A4A1A0A3A5A3
+9F9C9998969798969191929395999D9D9D9E9FA0A09E9C9B9C
+A1A5A8AAABABA8A5A3A0A0A09E9C9C9D9F9F9D9A938C8A8C8E
+8F8E8D8A8885868687888A8D9293928F8E9091908C898C8F93
+9494928E8A8A8D8C8C8B8A87827F7E7F828480787473767877
+7677797B7A78767677787878787672706E6D6E6E6F6D6A6869
+6C70716F6C6C6F7476767675757573716E6B6A676564636161.
+6B7474706C6A6C6F71706D6E727271717272747B84888C8E91
+93939698999797979798999B99969493908B8783807F82878B
+8D8D8B8988888786888C8E91939493918F8D90949697999B9C
+99969493919090919396969595939292969DA4A6A4A3A3A5A5
+A3A19F9B9796969693929294969A9EA0A4A5A6A4A2A2A3A2A1
+A4A9ACAEB0B0AFACA9A7A7A8A8A7A6A5A5A4A09E9A96929295
+9695928F8E8B89898A8B8E9195959695949392918F9092969D
+9F9D9A979491908F8D8B8B8A86838283878C8A837D7A797979
+7B7B7E80807D7C7B7B7B7C7D7C787472717274767774716F6C
+6E747878777474787B7D7D7A77757373716F6D6B6A69666463.
+7078786F6663676F75747273767777757372737A83898C9094
+97999B9C9B99999A9B9C9C9C9B99969493928F8B888686898D
+8F90918F8E8F918F8D8E8F91949697938D9094949698999A9A
+9994919291908F8F919292959797969699A0A7A9A8A3A3A3A4
+A4A4A29E9995949696969696989C9FA1A6A8AAAAA9A7A6A5A7
+A9ACACADAEB0B2B2AEADADADAEAEADABA9A5A0A09E9D9A9796
+9698999592908F8E8F8F909091959798969290929393959A9F
+A1A1A09C98959293908B8887888A8B8C8E908E8782807E7C7D
+8080808284858583817E7D80837C767476797A787677787671
+7174787B7B7877777B7F7E7A7674747574716F6E6D6A666464.
+747A766C64646A707273777B7A787677797A767D858A8F9499
+9DA0A09E9C9C9D9E9C99979A9E9C999695969795918C8B8E91
+919090939595959595949090959A9A9692918F93999D9F9F9D
+99928F8F919394939394989D9D9B9A9A9DA4AAADABA8A5A4A4
+A4A3A09C97949496999A99989B9EA0A3A7A8A9ABACAAA6A7AB
+AEADADADACACAFB2B4B1B0B1B2B3B5B3ADA8A5A1A1A19F9D9C
+9C9C9C99979697969492918F909498989695979A9A96959BA4
+A7A7A6A29C9693938E8C8D8F91908F8F91928F8A8683828283
+85888786888A898786848384827C78787D7F7F7D7C7C7A7976
+777B7F7F7A7575787C7C7A7775767978737273716E6A68696A.
+767B776E68686B707274797E7F7C7A7B7C7C7A7E848B90959A
+9EA2A2A09FA0A09E9B979695989A999A9B9C9B979291939395
+969696989A9D9D9E9C98959597999A98979695969BA1A4A39F
+9B99969696969799999A9C9EA0A0A1A3A7ABAFB0AEA8A6A8A8
+A4A19E9C9A9795999C9E9E9FA1A3A3A5A8AAA9A8A8A8A9ACAF
+B2B2B0ACABADAFB0B1B0B1B3B5B6B7B5B1ACA8A7A7A7A6A4A3
+A29F9D9C9B9C9E9E9D9B979392959999989B9C9C9C9E9DA1A9
+ADACA9A5A19D989592929393939292918F8F908D8A88888889
+8C8F8E8D8D8C8C8B8A898886838180818486858582807D7D7D
+7F8282807E7D7B797777787776777A7B76727271706E6F7272.
+747977716C6B6D6F7172747B8182808081807E8085898E9296
+9BA1A3A3A2A19F9D9B9997979A9A999A9D9F9E9B9795979999
+9A9B9D9E9FA1A3A4A29D9A9A9B9A9897979C9F9F9FA1A3A3A1
+9F9E9E9F9E9B999A9C9FA1A1A3A4A5A7A9ADB1B2AFABA8A8A8
+A8A5A3A2A09C9B9D9FA2A4A4A6A7A8AAAAA9A6A4A4A6A8ACAF
+B1B1AFACAAACADADADADADB2B8BABAB8B6B2AEABAAAAAAAAA9
+A5A1A0A1A1A2A3A5A6A4A19D9B9C9E9D9EA0A1A2A2A4A5A6AA
+ACACAAA9A7A39D9A9898989796989998959292918F8E8D8D8F
+9092949495928F8E8E8D8C8A8988868586898B8A8684838180
+8386888684817F7D7C7B7A7A7B7B7C7C797674747373737676.
+737876716E6E6F727471747B8184858586848285888B8E9299
+9EA0A1A4A5A4A29F9C9B9D9D9C9B9C9C9B9B9C9C9C9A9A9C9D
+9F9E9E9FA1A4A6A8A59F9C9B9B9A9A9A9BA0A4A6A6A7A6A4A4
+A4A5A4A5A29E9C9B9DA1A5A5A8AAA9A9AAACAFB0AFACAAA8A8
+A9A7A6A6A7A3A1A1A1A4A8ABADADACABA9A7A7A7A8A9ABADAE
+AFAEAAA8A9ACAEAEADACACB0B5B7B6B6B7B6B2B0AEAEB0AFAA
+A5A4A5A8A8A7A7A8A9A9A7A5A4A5A7A6A5A4A4A7A9ABACAEAE
+AEAEAEADA9A49F9DA0A1A09C9B9D9E9C989698979390919599
+9B9B999896938F8E909393908D8C8C8C8D8D8D8C8D8C878487
+8A8B898786868784817E7D7D7D7D7E7E7D7C79777777797D7C.
+72777571707072757777797D82858787898884888E9092979D
+A09F9FA3A5A3A1A09F9FA09F9D9C9F9E9A999C9E9D9D9EA0A2
+A1A1A0A1A6ABAEADA8A4A19F9D9B9A9A9CA2A4A5A9ACABA7A5
+A5A7A8A9A5A19F9E9EA0A6ACAFAEABA9A8A8A9ABACABAAABAB
+A8A5A5A8A9A5A2A3A5A8ACAEAFB0AFA9A5A7AAABACADAEADAB
+A8A7A7A9ABAEB0B2AFAEAEB1B2B1B0B2B5B3B2B2B3B2B1ACA8
+A8AAAFAFABAAABADAEAEABA9A9ABABA9A7A6A8AAADAFB1B4B4
+B3B0ACAAA8A5A1A0A3A7A7A29C999A9B9B9B9E9C979495989B
+9C9E9E9C9A96918F939897949290909192918F8E8E8D8A8A8B
+8C8C8B8A8A8A8A898684827F7B7B7D818382807D7D7E808280.
+7277797673717274797C7D80868786878A8B8A8C8F9296999B
+9C9EA0A1A2A3A3A3A3A2A09F9C9C9C9B9B9C9E9E9B999A9FA2
+A4A2A2A4A8ACAFB0B1ACA8A5A19D9A9998A0A5A5A7ABADACAB
+A8A8A9A9A6A3A3A2A0A1A5ACB1B0ACA9AAABA9A6A7AAADAEAE
+ABA8A6A9ADABA7A4A7AAADB0B3B3AEA9A6A8ABADACACADAEAE
+ADAAA8A9ADB1B3B5B3B2B2B0B1B1B2B3B2B0AEB0B3B1AEABAA
+ABADAEAEADADAEAFAFAEADACADAEACAAA8A8ACAFB1B3B2B2B4
+B4B2ADAAA7A5A19EA1A7A9A49E9A989A9FA2A09B9897979A9E
+A0A09D9C9B98969698999A9D9B98969594939292918F8E8E8F
+908D8A8A8C8E8F8F8E8D8A85807C7F83888784828386898985.
+787F807C7673737A818384878B8E8E8C8D8D8E8F8F93979A9C
+9FA09F9EA2A6A8A8A6A3A09D9C9D9F9F9E9C9C9D9FA1A09C9C
+A0A3A5A8ABACAAABACABA8A5A3A19F9D9EA3A8AAABADB0B1AE
+ABACADADA9A6A3A1A1A4A9ADAFB1AEADAEAFADA8A9AFB1B0AE
+ADACADB0B3B0ACA9A9ABAFB3B5B3B1AEACADAFB1AFADAEB2B5
+B2AFABACAFB1B3B2B3B3B2B1B0B1B4B6B5B1AFAEB2B2ADA9A9
+ACADACACADAFAFAEAEADAEAFB1B3B2ADACADB0B2B3B0AFB1B4
+B3B0ACABAAA8A39FA1A6A9A8A29D9A999DA09C98999B9A9A9D
+A2A4A09B97989A9C9C9C9E9E999696999A9793918E8C8E9092
+939190909091918F8F91918B848186898D8C8987898E928E87.
+7F8786807A787C83888A8F9292908D8D9091908D91969B9D9E
+A0A1A2A1A3A5A6A7A5A3A3A2A1A2A2A19E9C9C9E9E9E9C9797
+999DA1A4A8ABABAAA9A6A4A5A7A8A8A5A5A7AAADAEB0B3B3B1
+AFADAEAEAAA6A5A7ABAEAEACADADADAEAFB0B1B1B2B3B2B0AF
+AFAEADAFB2B4B3B2B0B0B2B4B5B4B3B1AEAEB1B2B1AFB1B4B6
+B3B0ADAEAFB0B2B2B4B2AFADAEB2B6B7B3AFB0B2B2AFABA8A9
+ACADABACADADADAEAFAEAEB1B5B7B6B2B0B1B4B4B2AFAEAEB0
+B2B0ADACABA6A3A3A5A7A9A5A19F9F9FA0A09B9C9D9EA0A2A3
+A19F9D9C9B9998999A9C9C9C9C9998989796959391908F9195
+949291919394929292908D8A8685878C90908E8F9294938D8A.
+89908E87818085898C8F939593908D8D9092919194999EA09E
+9EA1A3A4A6A5A3A3A3A4A4A5A4A5A4A2A1A09F9F9F9D989492
+94989DA2A7A9AAA9A5A3A5A8AAABACACAAAAABABACAEB0B0B1
+B3B1B0B0ADACAEB1B2B1AFAAACADAFB0B0B0B2B7B9B8B5B4B5
+B4B2B0B1B3B6B7B8B6B3B2B1B3B5B4B0AEADAFB0B0B1B4B6B6
+B5B2B0AEACACADB0B1ADABACAFB2B3B2B0B0B1B2AEA8A6A7AB
+ACADADAFAFACAAABAEB0B0B0B2B7B8B7B5B5B5B2AEABABADB1
+B4B1AEACABA9A7A6A6A6A5A3A1A09F9F9F9F9E9D9A9A9EA3A4
+A09B9A9B9B98999A9B9A9A9A99999897969492939494919294
+969594939596979694928F8B8686898E90909093959694908F.
+8C92948F8B898B8F929294959492908F91939594979B9D9E9F
+9FA1A2A5A7A7A5A1A0A1A4A6A6A7A5A1A0A0A09F9C9A989593
+9394969A9FA3A6A7A7A7A9ABABACAEB0B0AEACABA8A7A9ACB1
+B6B8B6B3B2B2B5B6B5B4B3AFACAAADAFB0B0B2B7BDBEBBB9BA
+BAB9B7B6B6B8BCBDBBB6B1ADACAFB1B0AEACADADAEAFB2B2AF
+AEAEADACA8A5A3A3A6A8A8A5A5A8ACAEAEAFB0B0ABA6A5A8AC
+AFB0AFAEACACACADAFB0ADACB0B2B4B2B3B4B4B2B0ADACAFB2
+B4B2AEACACADABA9A5A3A3A3A2A1A09E9E9C999796969AA0A3
+A29B999C9E9E9B99999A9B9998979796949395979997929294
+94949595989B9C9995918F8D8B8A8B8C8E8F90949799979492.
+90969998959393979999989897959392939495979B9FA2A3A5
+A7A7A5A6A9A9A6A2A2A4A8AAA9A7A4A3A19F9D9B9B9B9A9795
+969898999B9FA3A7AAACADADADACAEB2B6B4B0ABA5A2A3A8AF
+B7BCBBB9B9B8B8B7B6B6B5B0AAA9ABAEB1B3B5BABEBFBFBDBC
+BCBCBBB8B7BBC3C5C2BAB2ACACAFB2B3AFADADAEADADADADA9
+A5A29F9D9995928F92969693949B9FA2A4A8ABA9A5A4A7ACB0
+B3B5B3AFADACAEB0B3B2AEAEB2B2B0AFB1B2B2B1B1B1B0B0AF
+AEAEAFB1B2B0ADABA7A4A4A5A6A5A3A09E9E9B9999999B9EA1
+A19C9CA0A4A29D9A999B9B989495989A979393969A9C999896
+96989897989B9C9A979392919090908F9093959A9E9F9C9A9B.
+969A9C9A9796979A9B9897979694919090929696999FA3A5A7
+A8A7A4A7A8A8A5A3A5A8AAABA8A6A4A3A09B9795969A9B9695
+999EA09FA0A2A5A3A5A9ABAAA8AAAEB3B7B5B2ACA5A2A4A9B0
+B6B9BAB9B8B7B8B7B4B1B1ADA9A9ACB2B7B8B6B6BABDBCBDBD
+BBB9B6B5BBC3C8C7C2BAB2AEB0B5B8B5AFACABA9A6A29D958F
+878079757371706F706F6E70767C808389949FA09D9FA6ADB2
+B5B6B6B4B0ADAEB2B6B6B3B2B2B1B2B2B1B0B0B1B2B3B2B1AF
+ADACADAFB0AEAAAAA8A5A4A4A3A09E9FA2A19C9A9B9A9A9B9E
+A0A1A3A6A8A7A39E9A999A9895939393939393969BA0999391
+9497989897999C9B99979593908F9094999B9CA0A2A09C9C9B.
+939B9E9C9A999A9DA09C97959694918E8E929595979C9EA0A2
+A4A6AAABA7A6A7A7A8AAABAEACA9A7A5A29D99969697999B9C
+9D9E9FA3A7ABACA8A4A2A4A8ACAEAEB1B4B4B3ADA6A3A4A7A9
+ACAFB3B6B6B6B5B2AFB0B4B5B1AEAEB2B7B9B9BABBBDBFC2C2
+BFBAB6B6BBC6CCCCC8C2BBB7B7B8B8B0A8A29B93897F76706A
+64605C595857565656565556575A5C5F656E7781858C959FA9
+AEB1B1B3B3B2B2B5B8BAB9B6B5B6B6B7B6B2B1B2B3B4B5B7B7
+B6B4B1B0B0B0AFACADABA8A4A2A1A0A0A1A2A0A0A09C999B9F
+A3A5A7ABACA7A19D9D9D9B9A9A98999A9997989CA1A39F9997
+979795959CA09F9F9E9C9A96919093989C9FA0A3A4A3A19F9A.
+92979D9E9E9D9EA0A19D97959594928F8E8F919395999D9E9E
+A0A6ADAEAEACAAA8A9ACAFAEACAAA8A5A09D9B9A989798989A
+9C9D9FA4A9ACAEACA8A5A7ABAFB0B0AFB2B7B6B0ABA7A6A7A8
+ABAEAFB2B4B5B5B5B4B5B7BABAB6B5B8BBBDBEBEBEBFC3C6C5
+C3C0BCB8B9C3CDD0CEC7C0BAB8B4ACA19282766D67625D5A57
+534F4D4C4D4F4E4C4B4C4D4E4D4C4D5C706F584E5969747D87
+939DA4ADB4B6B8BBBDBCBABABBBCBAB8B6B6B6B8B8B6B6BBBA
+BABBBCBAB8B6B5B2AEADAAA9A8A6A5A5A5A6A4A3A09D9C9FA2
+A5A8ADAFADA9A6A4A19D9C9D9E9B9A9D9F9F9D9EA2A49F9897
+989998979AA2A6A6A39E9996959495969CA3A5A5A4A4A2A09D.
+959B9F9F9D9DA0A19E999695949391908F909093989DA1A2A1
+A3AAAFAFADADADACACADAEAEACABA8A5A2A09F9E9C9A999799
+9EA0A2A5A8ADB1AEAAABADAFB0B2B3B3B3B5B4B1AEABABAAAA
+AAACB0B4B7B8B9B9B9B8B8B9BAB9BABCBFC0C0C0C0C4C7C8C7
+C5C2C0BEC0C8D0D1CBC2B9B0A4958575685E58575654515151
+4C484646484A4A484748494947464B6689814D333F525E6266
+6F7B8896A8B4BDC0BFBDBCBEBFBFBEBCBBBBBCBEBDBBBABBBD
+C1C3C3C0BDBCBAB8B2AEABABABA9A7A6A6A6A4A09D9C9FA2A5
+A9ACAEAEADAAA7A4A2A2A3A0A0A09FA1A2A3A4A4A3A099979D
+A1A09C9BA0A7A9A6A2A19F9C99989A9DA5A9A9A7A4A2A1A0A0.
+969C9F9E9C9DA0A09E999894908E8F91918F90949AA0A5A6A6
+A7ABAFB0B0AEACABABACAEB0B1ADAAA7A6A6A5A29E9D9C9B9E
+A09FA1A5ABAFB3B2AFAFB0B2B2B2B2B0B2B6B7B6B4B1AFADAA
+AAAEB4B9BABBBDBFBEBBB7B4B4B7BBBFC0C0C0C1C2C5C8C9C6
+C2C1C1C2C6CCD0CBBFB1A3937F6B5C5755525151514F4E4E4E
+49464445464848474545474645454647484643434445484B4F
+545C6572879AAEBCC1C1C0C0C2C1C1C1C1C2C3C2C1BFBEC0C2
+C6C7C5C2BEBAB8B6B1ADACADADAAA8A5A3A3A2A2A2A3A5A6A5
+A6A8ACAEAEAEAAA5A3A6A9A7A2A0A3A5A5A5A7A8A69F9B9EA5
+A7A3A0A2A7ABAAA8A4A1A1A1A0A1A2A3A6A8A9A9A6A5A5A7A8.
+90979D9B9897999E9D98938E8B8A8D909291909499A0A5A9AA
+AAABAEB1B3B0ADABACAEB1B2B0AEABA9A9AAA9A5A19F9D9D9F
+A2A0A0A6ADB2B5B6B5B4B4B5B5B3B1B0B0B4B8BBB9B7B5B4B2
+ADAEB4B8B9BABEC3C3BFBBB4B1B4BBC2C5C3C0BFC0C5CACBC9
+C6C3C2C4C7CAC9BEAD978170625652514F4D4F5354524E4C4B
+4947454545454646464647474644434445444342403F3F4042
+444649515D697A8FA5B7C0C2C3C1C4C8C9C9C8C6C3BEBEC0C4
+C7C9C8C4C0BCB7B5B3B2B1B0AEAAA7A6A6A6A3A3A5A7A8A8A6
+A5A7ACAFAEAEADA9A7A7A8A6A4A3A6A9A8A5A5A9ACA7A5A5A9
+ABA8A5A5A9ACADAEABA4A0A1A4A6A4A4A6AAACAEAEADA9A6A8.
+919A9D9A9593969B9D97928F8B8B8C8F929393979DA4AAACAC
+ACAEB0B1B1B1AEACAEB2B5B4B2AFACABACACAAA7A5A4A2A0A2
+A4A4A5A8AFB6B8B7B5B7B9B8B6B6B6B4B2B5B8BBBABBBCBBB7
+B0AEB4BCC1C3C5C7C8C4BCB6B4B9C2CACCC8C3C2C5CACCCAC8
+C8C7C6C6C5C1B8A58B6E584F4F4F4D4C4B4E545959544D4A49
+494A48464343444646474747454241414243434342403E3D3E
+3F404041474D58677B96B2C5CAC8C6C8CECFCAC5C1BEBFC5CA
+CFD0CDC8C3BDB7B4B3B4B4B1ADA7A3A4AAAFADADACACABAAAA
+AAACAFB2B4B2AEAAA7A8AAA9A2A4A8ABABABACAEAEACABABAC
+ADADABA9A9ABADB0AFAAA6A4A5A7A8ACAEB1B2B1AFAEACABAB.
+909897939194999FA09A94908F9093949496999EA3AAAFB1B1
+B0B1B3B3B2B1AFB0B2B5B5B6B2ACA9ABAEB0ACA6A4A8AAA8A7
+A7A8ABAFB4B9BAB7B6B8BABABAB9B7B6B8BBB7B6B8BCC0BEB9
+B3AFB2BAC2C7CACAC7C2BEBBBCC1C9D0D2CEC8C5C9CFD0CBC8
+C8CAC9C2B7A99880634D45464949494B51585D5D59534C4948
+4949474645454444444444444342424242424242403E3E3E3E
+3F3F3F3E3F42484F5C7290AFC6CBC8CCD1D1CAC2BEC1C6CDD1
+D4D0CAC5C2BEB8B1AFB2B5B3AFACAAAAAEB3B3B0ADADADAEAE
+B0B2B3B4B6B9B7B0ABADAFAFABABACADAEAFAFAFB0B0ADACAC
+ACACABA9AAAEB4B6B2AEAAA7A6A8ADB1B4B4B4B4B2AEA9A9AE.
+8E96989594989DA2A29C999798999A9998999FA4A8ADB1B3B5
+B5B5B4B3B3B2B1B1B1B3B6B7B5AFAFAFAFAFADA9A6A6A8A7A6
+A8ABAEB1B6BBBBB6B4B4B4B6B8BAB9B7B7BAB8B5B5B8BDBFBB
+B4B1B5BCC4C9CBC9C6C5C5C1C0C2C8CFD3D1CDC9C8CBCECECD
+CCC9C1B19E8A735D4C4645474746494E545B5E5D574F4A494A
+4B484645454544444343414242434343424141403F3E3D3D3D
+3F4142414240404248556883A1BCCAD1D4D0CBC7C5C8CCD1D5
+D3CEC8C3C1BEBAB4B1B2B6B6B4B1B0B0B2B4B1B2B1AEACADB0
+B3B5B7B9B8B8B6B4B2B2B2B2B2B2B3B4B5B4B2B0AFB0AEACAA
+ACB0B2B1B0B1B5B5B2AEAAA6A7AAB0B1B2B3B6B8B7B2ACABAE.
+8E94979797999C9E9F9D9C9D9D9C9EA0A1A0A1A6ADB3B7B8B8
+B9B9B6B4B5B3B2AFAFB2B6B6B6B5B5B5B4B3B0ABA9AAAAA9A8
+ABADB0B2B5B8B7B4B2B2B2B2B3B4B5B4B4B5B7B8B9BABDBDB8
+B3B5BBC2C7CACBC9C6C5C5C2BEBFC5CFD5D4D0CBC8C9CBCCCD
+CAC2B2987C64534B4746484949484B51575D605E554B464649
+4A46444445454444444442424243434342413F3E3D3D3D3B3B
+3E41444343403E3E4046505F7593B8D0D8D5CFCCCCCFD2D4D8
+D9D5CECBCAC6C0BBB7B7BABAB7B5B5B6B6B3B0B2B2B2B1B2B5
+B7BABCBDBCBCBBB9B7B6B4B3B3B4B7B9BBBAB9B8B7B6B4B1AE
+B0B5B9B9B7B4B2B4B4B2AFABAAADB4B6B3B4B9BDBBB5AEABAD.
+909697979798999A9D9F9E9D9E9FA1A3A4A3A2A7AFB9BCBBB9
+B9BABABAB8B5B2B0B0B2B5B7B9B8B9B9B8B4B0ADAEB1B1ADAB
+ACAEB2B5B7B6B1B0AFAEADADADADADADAFB2B6B9BCBDBDBBB8
+B6BBC2C7C7C8CACAC8C8C7C6C4C4C8CFD3D2CFCDCDCAC5C3C0
+B8A78F72594A474848474647494B4D535D6361594F46434547
+4846424242434444444342434343434342403E3B3C3C3C3C3C
+3E414342413F3F3F4142444C5B7298BFD7DCD8D2D0D2D6D8DD
+DEDAD5D1CFCBC4C0BFBEBDBBBBBDBFBFBBB4B1B3B4B5B4B5B8
+BDC1C3C2C1C0BFBDBBB9B5B3B6BABEC0C1C1C2C0BDB9B6B4B4
+B7BABBBAB8B6B5B8B8B6B2AEAEB1B6B7B6B8BDBEBCB7B1ADAF.
+979E9D99969696999EA1A1A0A1A4A6A7A7A5A5ABB3BBBEBFBF
+BEBEC1C4C2BDBAB7B5B5B6B7BABBBCBCBDBBB6B1AFB3B6B3B2
+B2B3B6B9BBB8B5B2AEAAAAACAEAEADACAEB4BABDBEBEBFBFBF
+BEC3C8CAC9CACBCDCECFCECCCCCED0D0D1D2D4D5D3CDC5BFB4
+9F856B54474447494848494A494B515A656C675A4C44434648
+484645444343434446454444434342424242413E3D3D3D3D3E
+3E3F41413E3D3D3E3F403F4149587094B9D4DEDCD6D4D7DDE0
+DFDBD8D6D4CFC9C5C7C9C7C4C3C4C6C6C1B7B2B5B7B8B9BABD
+C1C5C6C8C8C6C2C1C0BDB8B6BBC2C7C8C7C6C5C4C0BBBBBCBD
+BEBFBFBFBBB8B8B8B8B6B4B2B3B6B9BAB9BCC0C1BFBCB8B5B4.
+9B9F9D97939294969AA3A3A0A0A3A6A8AAA8A5ABB3B9BBBABA
+BCBDBFC1BEB9B6B7BABDBBB8B5B6BCBFBDBAB7B4B2B3B3B3B3
+B2B1B2B5B8BBB8B0AAA7A9ADAFAFB0AEAAADB2B8BABBBCBFC1
+C1C1C5C5C4C5C8CCCFCECECED1D3D0CDCFD2D6D7D5CDC3B9A7
+8D705647424244464747484848484E59646D6C615349484949
+45454545454443434346454546464441403F3F40403E3D3D3D
+3D3C3C3D3D3B3A383A3C3D3E3F414959739DC6DDDFD8D3D5DC
+E0DED8D4D3D2CFCFCFCECDCAC6C4C4C5C2BCB5B4B8BCBBB9B9
+BBBEC1C5C8CAC7C3C0BEBBB8B8C0C9CCCAC8C6C3C1BEBEBEC0
+C2C3C4C4C0BAB5B7B8B5B1AEB0B5B9B6B1B4B9BDBEBCBBBAB9.
+A5A4A09B97969AA1A4A6A2A2A5A7A9ABACAEAEB0B4B8BBBBBA
+BCBEBFC0BEBCBBBABABBBEBFBCBABABAB9B8B7B6B5B4B3B4B6
+B7B6B6B8BBBDBAB5AEACAEB2B5B5B3B1B1B2B5B8BABABBBCBF
+C2C4C3C1C0C2C7CCD1D0CDCED4D7D5D1D0D2D5D5CFC6BBA88C
+6D544643454747464647494B4B4B525C666D6B60534A494B4B
+4947454648474543454848464646464442403F3F403F3D3C3C
+3D3E3E3D3B3838393B3D3E3E3D3C3D4454749FC8E1E4DDD8D8
+D9DAD9D8D7D6D6D4D2D1CFCDCCCBC9C6C1BCB8B7BABCBCB9B6
+B7BCC3C7CACAC7C4C0BFBDBDBFC4C9CBCCCBCAC8C6C3C4C5C5
+C6C7C8C6BFBAB9BDBCB7B2B0B3B7B9B9B6B7BABFC1C0BEBCBB.
+AEACA7A19E9FA1A6A9A9A8A9AAAAAAACAFB1B2B0B1B6B8B7B7
+BBBEC0C0BFBFBFBFBFC0C0BFBDBBB9B9B9B9B7B6B6B7B9BBBB
+B9B6B5B8BDBFBDB7B1AFB1B5B9BBBAB7B6B8B9B7B7BABCBDC0
+C4C5C3C0C0C3C8CED2D2D1D1D4D4D3D4D4D4D4D1C9BCA98866
+4D43424547484846474A4C4D4E5056626B6C64594F49494B4B
+4B49494949484644464748494645454442403E3D3E3E3D3C3C
+3C3D3D3D3A3736393C3C3B3B3B3A393D475C83B3D9E8E2DAD9
+DADCDEE0E0DCD9D8D5D3D0CDCCCAC6C1BDBBB9BABBBCBAB8B8
+B9BABCC2C7C9C6C2C1C0BFC0C2C6CACECECBC8C7C8CACCCBCB
+C9C8C9C7BFBBBCC0BEBAB5B4B7BABCBAB7B6BABEC0C1C1C0BF.
+B3AFABA8A7A8A8AAACACACABAAA9A8ACB1B4B6B4B2B2B2B1B3
+B8BBBDBDC0C2C0BEBEC1C3C1BDB9B8BABCBBB9B6B5B7BABEBD
+BBB7B5B6BCC0C1BEB9B4B2B4B9BDBCB8B7B8B8B7B6B9BEC1C2
+C3C3C3C2C2C4C7CACED1D3D4D3D3D3D6D9D9D6D1C8B1906B4F
+4443454647474747484A4C4E51565D69726F6559514D4D4D4D
+4E4D4D4D4B49454345484A4B4947464342403D3C3C3B3B3C3D
+3D3D3E3D3C3939393939393A3A3A39393C465E85B2D9E8E3DD
+DCDFE2E3E1DEDCDADAD7D2CECBC8C2BCBAB8B6BABDBDBBBABA
+BABBBCC0C2C4C3C3C3C4C3C3C6C9CCCBCACAC9C8C7C8CDCFD0
+CDC9C8C8C5C4C4C4C2BEBAB8B9BBBCB9B7B6B9BBBEC1C3C3C0.
+B3B3AFABAAABACAEAFAFACACACABABADB1B4B5B6B4B1AEACAF
+B5BABAB9BCBFC0C1C3C4C4C0BBB7B7BABCBAB8B7B6B7B9BCBB
+B9B8B7BABFC2C4C2BDB7B4B7BBBDBCBABABBB8B5B5B9C0C4C5
+C5C5C4C5C6C8C9CACCCED3D6D4D4D5D8DADAD6D0C1A2775241
+404446464646484A4B4C4E5257606F7D837C6E605855555451
+515050504D4A474646494B4B4A484542413E3B3A39393A3B3C
+3D3D3D3C3B3B3A39393A3B3B3B3B3937373B475E83B4DCEBE4
+DFE0E3E4E2E0DDD9DAD9D5D2CFC9C2BCB9B7B5B9BBBCBCBCBC
+BDBFC0BEBDBFC2C5C8CBC7C4C7C9C8C6C7C8C9C9C6C5CAD0D3
+D2CECDCDCCCBC9C7C4C1BEBDBEC0BEBAB6B5B7BABCBFC3C5C1.
+AFB1B1ADABABAFB3B3AEABACADADAEB1B3B3B4B5B4B2AEACAD
+B2B8BABBBCBCBEC0C3C4C1BDB8B6B7BABAB8B6B5B4B5B8BDBB
+B9B7B9BDC1C3C4C4BFBAB9BBBDBEBDBBBABBB8B6B8BDC2C4C5
+C4C4C5C8CBCBCBCCCED2D6D9D7D4D6DADCD9D1C1A279553F3C
+4145474647494B4F535458616F7E8C949A978A7A6E67635F5D
+5A5753514E4A4848484748484644413E3C3B3C3C3C3C3B3B3C
+3C3C3B3B3B3A3A393A3A3B3C3C3A373434373F4F6B97CDE9E9
+E2E1E4E5E3DED8D3D5D6D6D4CEC6BEBBBCBCBEBFBFBEC0C1C1
+BEBEBEBEBEC1C1C1C3C5C5C5C6C6C4C4C6C9CCCBC6C7CDD4D8
+D5D2D2D4D2CEC9C7C3C3C5C6C6C3BEB9B4B3B6BABDBFC1C2C2.
+ADB0B4B3B2B1B0B1B0AEACAEAEAFB1B4B6B4B5B5B4B3B0AFB0
+B3B6B7BABEBBBBBCBFC2C2C0BEBBB9B7B8BAB8B5B5B8BCC1BD
+B8B6BAC1C7C7C4C0BFBEBEBEBCBBBBBCBEC0B9B6BAC1C6C6C3
+C0C1C5C8C9C8CBD0D5D6D7DAD9D5D5D9DBD6C8AF865A3F383D
+444847474B5359616A74818F9EAAB0B3B8BBB7AEA293857D7B
+7870675E57514D4A474546454443413D3B3B3B3C3C3C3D3D3D
+3D3C3A3A39393A3A393837383A383634343538425575A8D5EB
+EAE5E2E1DFDAD5D2D4D5D6D4CFC7BFBCC1C7C8C5C3C4C7C6C5
+C3C0BEC1C3C3C0C0C2C5C6C7C6C6C6C7CACCCDCDCED0D3D4D5
+D5D6D8D8D6CFCBC9C7C8CDD0CDC4BEBDB7B3B3B8BEC0C0C1C3.
+B3B7B7B7B5B5B4B1AEAAAAADB1B2B2B2B6BABBB6B3B2B1B0B1
+B3B6B8B9B9BBBBBBBDBEBEBFBFBDBCBDBDBBB9B8B8BABCBFC1
+C0C0C2C6C9CAC7C4C3C1C2C2BFBDBDBEBFC0BDB9B9BDC4C7C6
+C2C1C3C7C8C9CCD2D8DBDCDBDAD8D7DADBD5C4A5784F3B393D
+43484D556273828F99A3AFBDC9CFD2D3D3D7D8D5CBBDB1A9A7
+A29A8E80766E675E544B46434242403E3D3B3A3A3B3D3D3E3E
+3C3B3A393A3A3A393836363738383434353536383E4B6996CF
+EDEFE5DCD7D6D5D5D9DBD8D6D4D0CBC7C5C6CACDCCC9C8C8C9
+C8C3BEBDBFC3C5C7C9C9C6C6C8CBCAC8CACDCFCFCDCFD3D8D9
+D8D6D7D9D7D2CBC7C7CACED0CEC7C1BCB7B3B0B3BBC0BFBDBF.
+B7BBBBB8B4B3B3B2B0ABA9ABB0B4B5B6B8BBBBBAB8B6B3B0AF
+AFB2B6B8BBBAB7B7BABEC0C0C0BEBDBDBCBCBBBBBBBDBFC0C0
+C0C1C4C9CDCCC7C2C0BFC0C1C0BEBEBFC2C2BDB9B9BDC3C6C6
+C5C5C6C7CACED1D5D9DCDDDDDBD9D8D9D9D0B78B5D3F393C44
+4C596A7D91A4B4C0C9CED4DBE1E6E7E6E5E6E6E5DED4CCC8C5
+C0B7AB9F958C8378685A50484342413F3E3D3A3A3A3B3C3D3C
+3B39373638393837353535363737353535343434373D4E6FA8
+D9EEE9DCD4D5D8DBDEDEDCDADADBD9D4CFCFD2D4D3CFCBCACA
+CAC7C2C1C3C7CACBC9C6C6C8CBCDCCCACBCED2D2CFD2D8DBDA
+D9D9D8D8D4CCC6C5C6C9CED2CFC8C1BDB7B2B4B8BCC0C1BFBE.
+B7BCB9B4B2B2B4B2ADA9A8A9ADB0B4BABDBEBDBBB7B4B2B0AE
+AEB1B5B9BCB9B6B7BABEC1C1BFBFC0C1C1BFBDBBBCBFC2C3C1
+C1C2C6CACCC9C5C1C0BFC0C0BFBEBEC0C2C4C0BDBBBDC2C5C7
+CACCCDCED0D2D5D9DDDEDDDBD9D9D9D8D0BC966541363B4453
+68829CB0C1CDDAE0E4E6E8EBEDEFEFEDECECEBEAE7E2DCD8D4
+D1C9BFB4ACA49B8E7E6B5D514A464443413D3A39393A3B3A39
+37363535363737363535353536373635353333333437415B88
+C5EBF0E2D6D4D9DFE1E0DFDFE1E1DFDAD7D7D8D8D6D3D0CDCB
+CAC8C7C9CFD3D2CFCCCCCCCCCFD1D0CECDD0D5D7D6D7D9DADA
+DADBDAD6D0C8C2C1C4CAD1D4D0C8C2BFB9B5BABDBEBFC1C1C2.
+AEB4B4B1AFB0B3B1ABA8A8AAADAFB3B8BCBCBDBCB9B5B2B1B1
+B0B1B4B7BBBCBCBCBEC1C3C3C2C2C2C2C3C1BFBDBCBFC4C7C7
+C5C4C7CCCCC9C4C1C2C1C2C1C1C0BFC1C6C9C9C5C2C4C6C7C8
+CBD0D2D4D6D7D8DBDFE1DFDAD6D5D5D2C2A3784C353743556F
+8CA6BDCFDADFE4E7EBEEEFF0F0F2F4F1F0EEEDEEEDEAE4E1DE
+DBD2C8BFB7AFA5998A7969594F494846423D39363537393836
+3435363636363636363636363636363534333333333439496A
+A6DAEFEBDED7DADFE3E4E2E2E3E3E1DEDADADCDCDBD9D6D1CC
+CBCBCED4D8D9D7D4D2D2D3D4D5D4D2D1D0D2D8DCDCDAD9D9DA
+DAD9D5D0CECCC9C4C3C9D0D4D1CAC4C0BEBDBCBCBDBDBEC0C3.
+A9ADAFB1B2B2B2B1ADAAABAEB1AFAFB4BABBBCBDBBB9B7B6B8
+BAB9B5B3B9C1C4C4C4C5C5C5C3C3C2C2C3C3C3C2C1C2C6C8C9
+C7C6C7CACBC9C7C5C7C7C5C5C4C4C4C6C9CDCCCBCBCBCDCDCD
+CCD1D8DBDBDCDDE0E1E0DCD9D5D2D1CAB38C6140333E506D8C
+A4B3BDC8D6E4EBEEF1F2F3F5F7F8F7F5F5F6F6F5F4F1EEEBE9
+E7E0D8CCC2B8AEA192857461534E4A46413C39363436373735
+34363637373736353536373838383836343232333436373E4F
+78AFDDF0EADDD9E0E5E6E5E3E3E4E4E2DEDCDEDFE0DDDAD7D4
+D3D3D4D7D9DAD9D9D8D8D9DADAD6D4D5D6D8DBDDDCD9D8D9DB
+DBD6D0CCCFD2D1CDCACCD0D3D2CCC5C2C1BFBFC0BFBCBCBEC4.
+A4A8ACAEB1B3B2ADABADB0B3B4B2B2B4B5B5B6B9BCBCBCBBBB
+BCBDBCBCC0C4C6C7C9C9C6C3C0BEBFC2C4C3C3C2C2C5C9CBC8
+C5C4C4C3C4C6C8C9C5C1C3C5C6C7C7C8CBCBC9C8CACED2D2CF
+D0D6DCDEDDDDDFE1E1DCD9D6D0CCC8BB9A6A4233394F6C8AA1
+B0BBC7D8E7F2F5F4F6F7F9F9F8F9F8F8F8F9F8F8F7F6F4F2EE
+EBE9E2DAD4CDC1B2A18B776559514A45413F3B383637383835
+34353535353533343436373839393936333132333536363946
+639BD4F0EEDFDAE0E8E9E5E2E3E5E6E4DFDDDFE0E1E0DDDBDA
+D8D8D9D9D8D8D9DADCDCDCD9D9DADBDBDADBDEE0DDD7D5D8DA
+D5CDC8CAD1D6D5CEC9C9CACCCDCBC7C4C4C6C5C1BDBCBFC3C4.
+ABA9A9ABADAFB0ADACAFB5B9B8B4B1B3B5B5B8BCBEC0BFBDC0
+C4C4C1C2C4C5C5C7C9C9C6C4C3C3C6C8C7C3C1C0C1C5C9C9C6
+C5C5C5C6C7C8C8C9C6C2C3C4C6C7C8C8CBCECBC9C9CCD1D2D0
+D1D6DDE1E0DFE0E2E2DEDBD9D1C8BBA480573B3540567598B3
+C6D7E5EFF4F6F8F9FAFAFBFBFCFBF9F9F8FAFBFBF9F8F6F4F4
+F3EFEAE7E4DED5C8B79F8977695B514B4846423E3B38373738
+3634343435343332333536383837353433323335373635363C
+507CB0D9EDEBE2E2E7E9E6E2E2E4E5E3E0DFE1E3E3E1DFDCDD
+DFE0DFDEDCDADBDEE1E1DFDEDFDEDEDFDFE0E1DFDBD6D5D7D9
+D4CCC9CED5D8D3CBC8CBCFD0CFCCCAC6C7CAC9C0BABAC2CAC9.
+AEACA9A8A8A9ACACACAFB4B6B8B8B7B7B6B6B9BEC1C1C0BFC1
+C5C7C5C4C5C6C8C9CCCDCBC7C4C6CACCC9C4C0BEBFC5CBCBC8
+C6C6C6C8CAC9C6C6C7C3C0C0C2C5C6C8CBCECDCAC9CACDD1D2
+D1D3DCE1E1DFDFE0E1DDDBD9D1C2B1946E4E3C3A465D7EA7C8
+DBE5EDF3F6F9FBFCFBFBFBFCFCFCFBFBFAFBFBFBFBFAF8F7F5
+F4F2EFEBE9E6E1D9C9B29A877A6C5E534E4B4744403C393839
+38363434353434333333343536363534333334373938353437
+415A83B6E1F1ECE4E5E8E7E3E2E3E5E5E3E2E0DFDFDEDEDEE0
+E2E3E3E2DFDBDBDEE1E3E2E2E2E1E1E1E1E0DFDFDDD7D5D7D7
+D5D0CCCED5D9D8D3CFCFD1D3D2D1CEC9C8C8C7C3C0BDBFC4C7.
+B1ADABA9A6A5A6A5A5ABB0B5B8B9B9B7B5B5BAC2C5C4C3C4C5
+C6C7C8CBCBCCCECFCFCECECCCACACCCECBC6C0BDBFC6CECFCB
+C9C8C8CACBC9C7C6C6C4C3C4C7C8C7C7CACCCAC9C9CACDD0D3
+D5D5DAE0E1DFDDDEDEDBD8D6C9B49A78563F394154739AC2DC
+E8EDF1F5F9FBFBFBFCFDFDFDFDFCFBFBFAFBFBFBFBFAF9F8F6
+F5F4F2EFEBE8E4DBCCB9A59485756559524E4A46423E3A3839
+38373637373634333232323233333334343535373838353639
+3E4D6CA0D5F1F1E7E1E2E4E4E3E4E5E5E5E4E1DCD9DBDFE2E4
+E3E4E4E3E1DEDCDDE0E3E4E4E4E4E3E2DFDDDDDDDCD9D7D7D7
+D6D5D5D8DBDCD9D5D2D3D6D7D4D2D1CBC9C8C5C3C1BFBEC1C2.
+B1AEABAAA6A2A09D9CA2A9B2BABDBAB5B4B7BDC4C6C6C7C9C9
+C9CBCDD1D3D3D3D2D0CECDCDCECECBCAC8C6C3C2C3C8CFD2CF
+CAC8C9CACBCAC9C8C8C7C9CDCFCECAC8C8C9C6C6C9CDCFD0D4
+D8D9DADFE0DFDDDCDDDCDCD7C4A6835F42363A496284A9CBE3
+EFF3F5F8FAFCFBFCFCFCFDFDFDFDFCFBFBFAFBFBFBFBFAF9F8
+F7F5F3F1EDEAE5DFD4C4B5A5917E6D5F55504A45423E3B3A3A
+393838383939363432302F3033343435353535363737363637
+3A425885C0EAF4EAE1DFE2E4E3E1E2E4E5E4E1DCD8DADEE2E3
+E3E5E6E6E4E1DEDDE0E5E6E5E4E4E3E1DFDDDCDCDBD9D7D7DA
+DBDCDDDFE0DED8D7D5D6D9D9D6D3D2D0CDCCCAC5C0BEBFC2C5.
+B4B0AAA6A2A2A3A19E9EA8B6BEC0BDB9B9BABFC5CBCDCDCDCC
+CBCBCDD0D3D3D3D1CFD0D1D1D1D0CECBC9C7C5C5C8CBCECECD
+CBCACCCDCFCECAC8C8C9CDD2D4D2CFCBCACBC4C1C4CAD1D6D7
+D7DADEE0E1DFDDDEDFDEDBD3B991664534343E506E94BAD5E7
+F1F5F7F8FAFBFCFDFDFDFDFDFDFDFDFBFBFBFBFCFCFCFBFBF9
+F7F5F4F2EEEAE6E2DCCFC1AE9B887767594F4742403D3B3B3B
+3A3938383939363332302F3033353436373534353535343333
+363C4D6FA3D6F2F1E5E0E2E4E1DDDFE4E5E2DFDDDAD9DBDEE1
+E4E4E7E9E7E3E1E2E3E5E7E7E6E5E3E2E0DEDDDCDAD9D7D8DC
+DCDDDEDFE1E2DFDCDAD9D9D9D9D7D3D2D3D1CCC6C4C4C7C9C9.
+B8B1A79F9EA4AAABA9A6ABB5BDC1C1BFBEBEC0C8CCCFD1D0CD
+CBCCCED2D4D3D2D1D0D0D2D3D3D1CECBCBCBCBCCCDCFD0CFCC
+CCCCCDCECFCFCDCBCAC9CCD0D3D4D1D0CECEC8C3C3C7CCD2D6
+D8DBE0E2E2E1E0E0E0DED6C7A3754C343139475A79A2C7DFED
+F3F5F7FAFCFCFCFDFDFDFDFDFDFDFDFCFCFBFCFBFBFBFBFAFA
+F7F7F6F4F0EBE7E5DED3C4B29D897666594F48423F3C3B3B3C
+3C3A3735393935323130303030323333343435353432323133
+353A455E8ECCF6F8E5DBDDE2E3E2E0E0E1E1E0DFDEDEDEDEDE
+E0E3E6E4E4E3E2E3E5E8E6E3E4E3E3E2E1DFDCDADAD8D9DBDC
+DDDEDFE1E3E2E3E1DFDEDDDCDCDBD8D5D0D0CCC7C4C4C7CBCE.
+BDB3A59C9EA7B1B6B3ADADB5BEC5C6C5C2C1C3C9CFD2D2D0CD
+CBCCD0D4D7D6D6D7D7D7D5D5D5D5D1CECECECDCCCDD1D5D4D1
+CCC8C8CCD0CFCBC5C5CBD1D6D8D5D0CED1D4CDC6C3C5CBD3D7
+D9DCDFE4E6E4E2E2E1DDCFB17E5136313741506789B2D2E4ED
+F3F7F9FBFBFCFDFDFDFDFDFDFDFDFDFCFCFBFCFCFBFBFBFBF9
+F9F8F6F3F0ECE9E6DFD5C8B59F897564574D4744403C393A3A
+39373535363533312F2F2F2F2F2F2F30323232323232323233
+34373E527EBEECF2E2DADDE1E2E0DEDDDEDFDFDEDFE0DFDDDF
+E2E5E5E3E1E0E1E3E6E6E6E4E4E3E2E0DFDEDDDBD8D7D8DBDC
+DBDBDCDFE3E7E6E4E2E0E0E1E1DED8D3D1CFCBC9C7C8CBCFD2.
+C5C1B4A7A2A8B3BABAB4B0B2B7BFC5C7C6C6C7CACFD1D2D2D1
+D0CFD1D4D9DBDCDCDCDBDAD9D8D8D7D7D6D5D3CFCDD1D7D7D4
+CFC9C7C8CDD1CEC8C8CCD0D5D8D6D0CCCFD4D3CBC3C2C8D0D7
+DCDDDFE3E5E5E4E4E4DFCEA6714B353136404F678CB1CCDFEC
+F4F7F9FAFAFCFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBF9
+F9F8F7F4F2EFEBE8E4DBCFBDA8917D6C5D524C4845403C3937
+36363636353331303030302F2F302E2E303232313133333433
+333436405B8EC7EAE9DEDDDFE0DDDAD9D9D9D9DCE0E2E2E1E1
+E2E4E3E1DEDEE0E3E6E5E4E3E3E4E5E3E1DEDCDAD6D6D7D8DA
+DBDCDFE2E4E6E7E6E4E2E2E2E2E0DCD4CFCECECDCBCACCCED1.
+C8C5B9ABA4A6B0B8B8B2AEAEB2BBC4C8C9C9CBCFD1D3D3D3D4
+D5D6D6D7DBDEDFDFDDDDDDDDDDDDDDDDDDDAD5D1CFD3D8D7D3
+CECAC9CBCFD4D3CFCCCDD1D6D7D3CECCCED3D2CCC7C5C9D1D9
+DDDFE3E6E7E8E8E7E3D5B88960453733354053719BBFD5E4EE
+F4F7F9FAFAFDFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFCFBFBF9
+F8F7F6F4F1EEEAE7E2D8CAB9A5907F7162564F4C48423D3A37
+353436353331303030303030312E2D2E303231303134343533
+3233353B507BB2E3EDE4E1DFDDDAD7D5D3D3D6D9DEE2E3E1DF
+E0E2E2E0DEDDDEE1E4E4E0DFE1E5E4E2DEDCDAD9D7D6D8DADB
+DCDFE1E2E3E6E9E9E7E4E4E3E2E0DDD8D3D1D2D2D0CFD0D2D3.
+C3BEB4AAA4A6ABB0AEA9A5A9B1BDC7CBCBCCCFD1D2CFCFD2D5
+D7D8D9DCDCDEDFDFDFDFDFDEDEDEE0E3E2DDD8D4D3D6D8D5D1
+CECBCCCFD2D4D0CDCDCFD4D6D5D2CECACCD0CEC9C6C6CAD1D9
+E0E5E7E8E7E8E8E5D9BD98796148373135435A7BA6CADEEAF0
+F3F6F9FCFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFCFCFCFBFBF9
+F8F6F5F3F1ECE7E4DDD3C4B3A08F81736458504C4946403B37
+3433343332323131302F3031302E2E3031302F303234323231
+30313338486BA2DDEFE7DED9D4D0CFCFD0D1D3D4DBE1E3DED9
+DBE1DDDBDAD6D7DBE0E2DFDBDCE0DFDDDAD8D9D9DADADADBDD
+E0E2E2E1E2E6E9EBE9E6E4E4E4E4E3DED9D8D7D7D8D7D6D7D8.
+BCBAB4ABA4A2A6A9AAA39FA2ABB7C4CED0CECED2D2CECED1D4
+D5D5D6D8D9D9DDE2E4E2DDDBDBDDE1E5E4E1DDD7D3D5D8D6D0
+CCCAC9CBCED1D1CFD0D3D5D8D9D5CDCACED1CDC5C3C5C9CED4
+DCE2E7E9EAEAE7E0D0B28E7C6C523A2E313F547097BFDDECF0
+F1F3F7FBFEFCFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFCFBFAF8
+F7F6F6F3EFEBE7E2D9CFC2B6A796887D7264564E4D4A453E38
+35343433312F2F3031313030302F2F30302E2D2F3233313131
+313132343B517DC4ECE6D4C4BCBDC3CCD2D2D2D3D7DFE2DCD1
+CACECFCED0CFCED2DAE0E2DDD3D0D4D9D9D7D6D8DBDBD9DBDE
+E0E1E0DEE0E3E8E8E7E7E7E7E7E6E4E0DAD7D5D6D8D9D9D9DC.
+B4B6B5B0ABA9AAA9A69D9799A3B4C4CDCCC8CCD1D3D0CECFD0
+D2D6DADAD9DADDE2E5E4E1DFDFE2E5E5E3E0DCD8D6D5D7D5D2
+CEC9C8CBD0D3D6D5D5D6D8DADAD6D0CED0D6D2CAC6C6CAD1D9
+E0E5E8E9E9E8E3CFB194857E6748332E36465B769EC8E5EFF0
+F0F4FAFCFDFDFEFEFEFDFDFDFDFDFDFDFDFDFDFDFCFCFBFAF9
+F7F5F5F1ECE7E0D9D4CEC6BCAD9B8D82756A5F5B564C453F3C
+3A373332323131313131313231302F2F2F30302F2F3033312F
+2F303232384B75B7DFD9C2AEAAB4C4D1D3CDCBCDD4DDDED3C1
+B8BBC1C7CCD1D4D5D8DEE0D6C6C7D3DBDCDBDCDEE1E1E0E0E1
+E0DFE2E5E5E7E8E7E5E6E6E5E5E5E6E4E0DBD9D8D8DBDEE0E1.
+ACB0B1AEA9A4A19F9D948D909FB4C5CCC7C1C4CDD1D0CDCCCF
+D4D9D9D8DADDE0E5E7E5E3E2E1E3E5E5E1DCD8D5D5D7D8D5D1
+CCC9C8CBCFD2D4D3D4D7DADEDDD8D2D0D2D5D0CAC7C7CCD6DE
+E3E6E8EBE8DFCCAE9183796B4F38313540516787B2D7EBF1F0
+F1F5FBFCFDFDFEFEFDFDFDFDFDFEFDFCFCFCFCFCFCFBFAF8F6
+F5F5F1ECE6E1DBD5D0CBC3BCB0A29385786D6662584E484441
+3F3A36313130303131302F2F2F30302F2E2F2F302F2F302F2D
+2D2F3132374B76ADC9BEA79695A4BBCDD1C8BEBEC9D5D4C4B2
+A9AEBEC8CBCCCED3D6D8D5C5BCCADADEDBD9DDE1E2E1E3E3E1
+E0E1E3E5E6E6E6E4E2E1E2E3E6E7E7E7E2DDDAD9DBE0E2E1DE.
+A8A9AAA7A198929293908B8B95A9BECAC8C2C1C8CECDCBCCD0
+D4D9DBDCDEDFE3E6E6E4E1E0E2E5E6E6E3DED8D5D7DCDDD7D1
+CBC9CBCED1D3D4D6D9DCDEE0DFDAD2CECED1CDCACBCED4DBE1
+E4E7EAEAE4D0B297857867503D35343843556E8EB7DAEBF1F2
+F3F6FAFDFDFEFEFEFEFDFDFDFDFDFDFDFDFDFCFCFBFAF9F7F6
+F6F4F0EAE5DFD9D5D1CCC5BFB6AA9C8D8077716B6058534E4A
+443F3A34302F303131302E2E2E2F30302E2D2E2F2F2F2C2B2C
+2D2D2F323642638CA19E91858596B2CBD2C8BBB9BFC7C5BAAD
+A8ACB8C0C4C6C9CDD1D3CDBDB6CADEE2DAD6DBE3E5E1E1E0DF
+E0E3E5E6E7E7E5E3E1E0E1E4E7E8E8E6E2DFDEDEDFE2E4E3E0.
+A4A3A3A19B928984858887878EA2B9C8CBC5C0C5CDD3D3D2D3
+D6D9DDDEE0E1E2DFDBD7D6D9DFE4E5E5E4E0DBD8DCE0E0DAD4
+CECBCBCED0D1D3D6DADFE1E0DED9D2CDCCD0CDCACCD1D6DCE1
+E6EAEDEBE1C8A5897C6D5641363335394459728FB1D1E8F2F4
+F4F6F9FCFDFCFDFDFDFDFDFCFCFCFCFCFDFDFDFDFCFAF9F7F6
+F7F4F0EBE6E1DAD6D4D2CCC7BFB4A89B918981786E67615C55
+4E47413A332F2E3032312E2C2E2F2F302F2C2C2D2D2D2C2B2B
+2B2D2F31343A496380908E807B89A6C3CFC8BBB2B0B4B8B5AE
+A7A6ACB5BCC1C4C7CBCCC4B4B0C5DBDFD3CAD1E0E8E3DEDDDE
+DFE0E2E5E7E8E7E7E4E1E2E5E8E9E9E6E4E2DFDDDFE1E3E2E0.
+999D9D99938B847F7E8182828BA2BCCBCAC4BFC3CBD4D9DBD9
+DADEE2E3DEDDDBD4CAC2C1C5D2E1E7E8E5E1DEDCDDE0E1DDD8
+D5D3D2D3D5D6D4D3D9DFE3E2DFDBD4D0D1D4D1CED1D4D8DEE4
+E8EBEDEBD8B6947E6F5C463A3532343A4A6584A1BBD3E9F4F6
+F5F5F8FBFCFBFDFDFCFBFBFAFAFBFBFBFBFCFCFCFBFAF8F7F7
+F8F5F0ECEAE6DFD9D8D6D2CEC7BDB2A9A49F958B7E756E6862
+5A4F453D36302D2E30302E2D2F2F2E2E2E2D2B2A2A2A2A2A2B
+2C2F303031343F5170858578727E9CBDC7BAACA7A9ADB1B2AB
+A29EA8B4BBC1C5C7CAC8B8ABAFC6D9D8C7BDC6DBEAE8DEDDDF
+E0E0E3E6E8E8E7E9E7E4E4E5E7E9EAE7E6E5E2DEDCDDE0E2E0.
+8792928B847F7B7675797C7E889DB6C6C9C6C0C3CAD3DADDDD
+DEE1E2DDD6D4D1C7BBB2B0B6C8D9E6E9E6E1DCDBDFE1E3E1DE
+D9D5D3D4D6D5D0D1D7E0E3E2DFDCD9D6D2D4D4D6D9DBDDE0E6
+EBEDECE8CBA48673624B39343335373D4F7098BACEDBE8F1F4
+F5F6F8FAFBFAFCFCFBFBFAFAFBFBFBFAFAFBFCFDFCFAF8F7F7
+F8F6F1EFEDE9E5DFDCD9D9D7D2CCC3BCB7B0A79D928A82786E
+6255463C3532302F2F3031302E2D2E2E2E2D2B2A2928292B2C
+2E2F303131323949687C7B7470768CABB5A99D9EA5A9A7A098
+9497A4B1BBC5CCCFCABEA89FAFC9D4CEBAAEBBD9EEECE3DFDF
+E1E5E9EAE9EAEAEBE9E6E5E6E9E9E8E7E7E7E4DFDBDCE1E2DD.
+6D798589857D736C6A6E72787F8EA3B7C5CBC9C6C6CED5D8D7
+D7DBDBD3C7C0BDB7AFACADB2BECDDBE4E6E1DBD8DCE2E3E1DF
+DAD5D2D3D6D7D5D4D8DFE2E1E1DFDCD9DADADCDFE1E3E3E3E6
+EBEDEAE3C39B7E6B584235333637393F5376A1C7D9E1EAEFF2
+F5F6F8F9F9FAFCFBFBFBFBFBFBFBFBFAFAFAFBFBFBFAFAF8F8
+F6F5F4F1EEEAE7E5E1E0DEDFDDD8D2CCC5BCB3ABA39D95897C
+6C5C4A3E3733302F3032302D2C2F2E2C2C2B2B2A29292A2C2C
+2D2F30303032384460767B746D6D7C98A5A097979B9B97918D
+8F99A3ACB7C3CBCBC5B7A29CB3C9CEC2ADA3B4D3EDF0E6DFE0
+E4E7EAECECECEBEBEAE9E8E6E6E7E8E8E5E4E5E2DFDDDDDEDE.
+616F7F888882787069696C717A8795A3B3C2C9C4C0C7CDD0D0
+D1D1CABEB1B1B1ADABADAEB0B7C2CBD7DFDFDBD9DDE3E4E1DF
+DBD8D7D8DBDAD7D8DDE1E2E2E3E3E2E0E0E3E4E5E6E7E6E6E8
+EBECE6D7B38D735F4A393436363639445F89B7DAE6E6E8EEF2
+F5F7F8F9F9FAFBFCFCFCFBFBFAFBFBFAFBFAFBFBFBFAF9F8F6
+F6F5F4F1EEEBEBEAE6E4E5E5E2DDD9D4CEC7C2BDB4A99D9283
+6F5A453A36322F2D2E2F2E2C2C2C2B2A2A2B2B2A2A29292B2E
+2F3030302F323A455E74796D626579929B948B878786838285
+8E98A2ACB6C0C4BFB5ABA5ABBAC3BEB0A2A2B7D6ECECE4E3E5
+E8EAECECEDEDEDEDECEAE8E7E7E7E5E4E6E7E5E1DDDCDEE1E4.
+5868798486827A76726F6E6E717A8694A3B2BCB9B5B9C1C6C7
+C6C3B8AA9FA0A3A4A8ADAFACAFB4BCC7D4DBDCDCDDE0E3E0DC
+DBDCDCDCDEDFDEDCDEE2E4E6E7E6E4E4E5E7E7E8E9EAE8E7E9
+EBEBE0C9A5846B543E333236353538446290C0E1EAE9ECF1F5
+F6F7F8F8F8F9FBFCFCFCFBFBFAFBFAFAFAFBFBFBFBFAF8F6F6
+F6F5F3F1EFEEEDEDEBE8E9E8E3DEDBD9D6D1CCC7BCB1A29484
+6F58443834302E2D2D2D2D2C2C2B2929292A2B2B2B2B2B2C2D
+2E2F302F2E3039465E7072655A5D6C7F88857D757273767A81
+8A96A5B1BABDB9AFA5A2AAB4B7B7B0A2979BB3D6EEEFE7E4E7
+EAECECEDEDEEEEECEAE9E8E8E9E7E3E1E4E5E4E1DEDEE2E7E7.
+5262727D827F77717277756E696C778796A3ABABA7A6ABB2B8
+B9B3AAA59E9895989EA5A7A4A7A7A9B0C0D2DEE0DDDCDFDEDC
+DCDDDFE1E1DFDEE0E4E7E9E9E9E7E6E6E8EAE7E6E9ECEBEAEA
+EBE9DBBD9C80674E392F3136363537415E8CBBDBECEFEFF2F5
+F7F9F9F8F8F8FAFBFCFCFCFBFAFAF9FBFBFBFBFAFAF9F8F7F6
+F6F4F2F0F0F0F0EEECEBEBEAE6E1DEDBD8D6D1CABDB0A39483
+6D5643383531302E2C2C2C2C2D2B2929292A2B2B2C2C2B2B2A
+2C2E2F2F2D2D3540576769615959606B767B776D66676F767C
+838FA2AFB6B4ACA09697A5AFADACA4978D91AACEEBF2EAE7E8
+ECEDECECEDEFEFEDECEAE8E7E7E6E4E2E3E3E4E3E3E4E8EAE5.
+525F6A73797A75707173736E67646A7988949FA4A5A19FA0A6
+AAA7A3A7A19891949A9D99949496969AAEC8DCE0D6CDD1D9E0
+E3E2E3E4E5E5E4E3E4E9ECEBEAE9E7E7E9EAE8E9ECEEEEEEEC
+E8E3D1AF917B664B332B313838353642608DBADBEFF2F2F3F5
+F7F9F9F7F7F9FBFAFBFBFBFBFAFAF9FAFAFAFAFAF8F7F7F6F4
+F2EFEEEDEEEFEEEBE8E8E8EAE6E1DDD7D1CCC9C4B6A89A8B7A
+685543373431302F2E2E2D2C2B2A28292A2B2B2B2B2B2A2A2A
+2B2C2D2D2C2D313A506064615A55565E6C75746C66676E767B
+828B9AA2A3A0988F8A91A3ABA5A39889838BA3C8EAF5EDE8E8
+EAEAE9EBEEF0EFEBEBE9E7E7E7E6E5E4E4E4E6E7E7E9EBEAE3.
+4F5A636C73757373757A78726B64646D7B8A9A9D9995929499
+9FA0A0A2A19B94909092918B888A8D95A9C1CECABDB7C3D6E3
+E6E5E4E5E7E8E8E5E7EAECEBE9E7E6E7EAEBE9EAEDEFF0EEE9
+E5E0CAA18372614B352C3038393435406090BEDFECF0F2F3F5
+F7F7F7F6F6F6F9FBFAF9F9F9F9F9FAFAF9F9F9F8F7F5F3EFEC
+E8E6E4E3E4E5E6E6E4E3E4E6E5E0D8D0C9C4BFB6A5978C8072
+625141373232302E2E2E2C2B2B2928292A2A29282A2C2D2D2A
+2928292A2B2C2E364A5A605E574E4D556977776D686A71797E
+82898F908D8884838893A4A69A97867573819DC2E4F3EEE7E5
+E7E9EAEAECEEECEAE9E8E8E8E8E7E5E7E7E6E6E6E8EAEAE6DD.
+4E565F676D71727173767674727170727982888A8B8D8E8E90
+949697999E9E9792908E8B878685878C95A0A6A39EA1AEC2D5
+E0E6E7E7E9EBEAE7E6E9ECECECEAE8E7EAEEEDEEEFF0F1EFEB
+E7E1CB9E7A695F4F3A2C2E393A35333D5883B3DAEFF3F0F0F2
+F5F5F4F3F3F3F6F8F9F8F8F8F8F9FAFAF9F9F8F7F4EFEAE4DD
+D4CECBCBD2D9DDDDDCDEDFDEDEDDD8D1C8BEB3A5978D847A6D
+5F524539312E2F302F2D2C2D2D2C2A2A2A2A2A2A2B2D2F2F2D
+2B2B2C2D2D2C2D3040525E5D544B494F5D6D727173777E8284
+85888C8C877E797B8697A39F93928972677391B7D9E9E8E6E7
+E9EBEBEBEBECECEBEBE9E8E9EBEBE9E9E8E8E8E8E9EAEBE8E1.
+4F585B5D626A7071706F6F6F707477797C7E7E818689898785
+8586898B9298968E86838384868889878685848387919CA8B8
+C7D3DEE6EAEBE8E6E4E7EAEBEBE9E6E7EBEEEEEEEEEEEEEEEB
+E5D7BA8D6B5B564C392C2B333634343B5581B3DDF1F1ECEBED
+EEEDEBE9E8EAEFF4F6F7F7F7F6F6F9FAF8F7F6F2EBE1D3C4B3
+ABA9ACB0B7BDC4C9CAC9C8C9CAC9C5BEB3A79A8D8178716961
+584F4438302E2E2F2E2D2C2B2B2B2A2A2A2A2A2B2C2E2F2F2E
+2D2E2E2E2E2C2D30405159554A43444B58656D747D848A8E90
+8E8983818077737A89999D958B8C7F69627392B1C6CDD3DEE8
+EBEAE8E8E8EAECEAE8E8E8EAEBEBE8E8EAEBEBEBEBEBE9E3DB.
+525B5B5B626B71716E6D6E717578797A7C7F82828483807D7C
+7B7B7E838C94948B807C7D81888E8F887F79787C838B9399A3
+ADB8C6D6E5EEEBE6E3E6E8E9E9E7E5E7EBEEEEEEEDEBE9E8E5
+DDC3987059514C44362C2A313535363F5B89BBE0EEECE8E5E2
+DEDAD5CFCCCDD6E5F3F9F9F5F4F5F7F8F7F6F2E7D6BEA59287
+85878C92989FA5A8A6A4A6A9ABA9A49C92887E756C65605C58
+52493D34302F2E2E2E2D2C2B2B2B2B2B2C2B2B2C2D2E2D2D2D
+2D2E2E2E2E2C2D334553554C413D434F5B636A77848C929696
+8E8281838076747D8A92908C8C897562637995AAB0AEBCD5E8
+EFECE9E7E7EAEBE8E8E9EBEDECEAE8E8EBEFF0EEECE9E4DDD4.
+515C5C5E656C6F6E6D6B6F75797A7A7B7E8386827E7A777575
+7474777D858B8A837B77787C848C8B80746F747E878C909090
+949CA7B8D2E9EEE7E1E2E5E7E6E6E5E6E8ECEDECEAE7E4E0DC
+D0B0856350494540382F2A2E3437373D547EADD1E1DFD9D1C9
+C0B6ADA5A2A0AAC0DCF3FCF8F3F1F3F5F5F2EAD7B8957B6E6B
+6D6E6F71767D8283807D7F828584817C756F69615C58555452
+4E473E3430302E2E2F2E2C2B2B2B2C2D2F2E2B2B2D2D2D2C2C
+2C2C2D2D2C2C2D32424C4C453F3F47525A5E6470787D82898D
+8A827D7E7E7A7A7F8587868B928A7260657C95A2A29EB3D2E9
+EFEBE6E5E7EBECE9E9EAEBECEDECEBEBEEF0F1EFECEAE6DED7.
+4F595C60696F6F6C696B6E727576787D8386837F78716D6D6D
+6C6D6F737B7D7B7874706F7179807D736967707C858E938F88
+85888E9DB8D5EAEBE3E1E2E2E3E2E2E3E6ECEEEDE9E5E0DAD0
+BE9D785A4B46423D372F2C303739393E517191AAB7B9B4AA9D
+9087817C7A7D8596B5DBF6FDF7F0EDF0F0EDDABA93715D595C
+5E5F6161656D74736A615D5F605F5F5C595554514D4D4E4E4E
+4C473F3733302E2F2E2D2C2B2B2B2C2E2E2E2D2D2C2B2B2A2B
+2B2B2B2B2B2B2C303A44464543464E56595A5C6063656B7887
+8B807272777B7F858986828C978A6D5C637C959F9B98ABCBE7
+F0EBE5E5E9EEEDEBEBEBEBECEDEEEFEFEFEFEFEFEEECE9E3DD.
+4D55595F6972746E66626464676D757E8688817A78726D6C6D
+6D6D6E6E71726E6A666464666668696664676E757F8B938D83
+7E7D7E8496B4DEEFE8DFDEE0E1E1E1E4E8EFEFEEE9E4DDD5C9
+B69874564845423E3933313236383A3D495D707C7F7F7D7D80
+858D918D8379717487ADDAF8FCF4ECEBEBE4CAA2795B4E4E53
+555C6B7E92A1A8A1907B67574D47464746444342404144494D
+4D4A443C36312F2D2E2E2D2C2B2B2A2C2C2D2D2D2C2A2A2A2C
+2C2B2B2B2B2C2C2E343D434546484E555757585A58565A687C
+8B89766C7073788086848087937F63555D748A979B99A1B9DB
+F0F1E9E6E9F0F1EEECECEBEAEAECF0F2EFEEEFF0EFEEECE9E3.
+505659616A716F665F5E5E60646C768085837A75736F6A6764
+62656A70706D69625B585A5D5B5C5E6063686D747F8C958E84
+7E7C787682A3DAF5EFE0DCE0E4E4E1E2E7EDEFECE5DED8D1C5
+B28F694C4242403B373635353839383B46545D5D5B5B6782A0
+B4BBB5A99F988B7B768CBDECFEF9EBE4E1D5B185604B454B54
+5E789AB6C0BAB1AA9D8975614F453F3D3D3D3D3C3B3C404951
+5450463D38332F2D2D2E2D2C2B2B2A2B2C2D2C2B2B2A2A2B2C
+2C2B2C2C2D2D2D2D313C464845464B51545657565252576370
+7D8378707072777C7D7A76777562504D5D75869096989FB4D8
+EFF2EBE8ECF0F1EEEDEDEBE9E9EBEFF1EFECEDEFEEECE9E5DF.
+54595E6368696662616261646971777A7B78706E706D66605D
+60676F73706A645E5857595C5B5B5C5E64696D727E8F9B9888
+7C76716E7899D8F9EFE0DDE3EAE8E1DEE4ECEEEAE2D9D1CBC0
+AE8F6B493B3A3C3B3A3938383B3B393A414C53504B51657F91
+968F8177737781828084A2D4FAFDF5E8DECAA1755648474F5D
+7491A7A99A84736B676059544F4944413F3C3B3A3A3F495762
+62584B40393533302E2D2D2D2D2C2C2C2C2C2B2A2A2A2B2C2C
+2B2B2B2C2D2D2E2F343D484C4A484B51535352505051565F68
+727A7977777474777A766B6159504B4D5B70818B90939BB1D5
+EDF2EDE9EBEEF1F0EEEDECEBEAEBEDF0EEECEDECEBE8E6E3E0.
+565A5E61635F5A5B60656465696E706F6C6963656B6A645D5A
+5E6872746B625C5756585A5A5856595D63696C717F909C9B8A
+796F69666F93D7FBF2E1DFE6EBE7DFDCE1EBEDE7DFD3C8C0B8
+AB926F483534393B3837383A3B383638404C524E474B58636B
+6C64564A49505D6E7D899EC5ECFFFDEEDCBC8F68524C505A6A
+7F8B8C887D6A56453F42444442424342403E3D3F4451637379
+746450433C38332F2E2D2D2D2C2C2C2C2C2B2A2B2B2C2E2E2C
+2A2A2A2B2C2D2F30343D49504F4C4B4E4F4F4C494B50565C63
+6D74716E6F7074797B7567574C48484D5765717D868E98AED1
+EBF3EFEAEAEEEEEEEDEDECE9E8E9ECEFEEECEBE9E6E2E1E1DE.
+5B5F61615F5C595A6064636264676663605D5B606767605A58
+5B656E6E665D565355595B595452575E6466687081939D9C88
+73666162729AD9F8EEE0DEE4E7E1D6D1DAE9ECE4D8CBBFB7B3
+A995754E363136393837383937343439495D645949434D637D
+85714E3533404F5D7088A4C5E8FFFEEFD7AF7E5B4F54606A74
+8190A0ACA58456332D3B43423F3E3F4142454C5764778C9995
+826952443F3B35302D2D2D2D2C2B2B2B2B2B2B2C2D2C2C2C2A
+29292A2A2A2B2E30343C474D4C4A494A4B4B4847494F545A62
+6A6E666263666C74797465534743454A515A65717D8A98AFD3
+EDF5F1EDECEEEEEDEEEDEBE8E7E8EDEEECE9E8E5E2DFDBD6D0.
+5E64646464625F5D5D5E5E626667635D5A58565A61615D5A59
+5C616768656058514E50545652565B606261626D82939A937D
+685F616E87AFDEECE1D9D9DEDCCBB6B0C2DCE5D7C7BCB9B8B2
+A899785339313234363638373332353E5D84938060566B91B1
+B08A5636384A57637797B6D4F1FFFDECCD9B6D545261758696
+AECADDDEC8985D363649524E4D5053575E6D8193A0ABB4B4A4
+86674E423B36322F2D2C2C2C2C2B2A29292A2B2B2B2B292929
+29292928292B2D30343C46494543464A4B484646484D52585F
+64645C5B5C5F666D716E61504644484C5057606975899AB3D3
+ECF5F2EDECEDEDEFEFECEAE8E8EAEDEBEAE8E6E4E1DCD6D1CB.
+5760666A6C68605956585E656C6D675F5957585C5E60615F60
+636464676660574D46454C54585C5E5D5C5C5F6A7F90958C73
+5C55688EB4CCDAD9D4D2D4D3C8AC8A7D8EB2C5BFB0AEB8C0BC
+AC9C80593B2F2F3436363634323134406497BABA998796BCD9
+D9BD916E6775808DA2B7C6D8EFFFFEF0D3A2715654657F9CBB
+D6E8F0ECE0C69B7060657278797572788BA7BDC6C9CACAC3AE
+8D6C51423B35302F2F2F2D2B2928292A2A292929292929292A
+2A292828282A2D2D31394144444445494B49484848494B4E53
+5758555253565A6064645D534C484A4F5255595E69839DB2C9
+E3F2F5F1EDEAEDF0F1EDE9E8E9EAEBE9E7E5E4E3E1DFDBD6D1.
+5C656C6E6A635B5656575C646E726E665F5C59595B61656768
+69686766645C51463F40454E575D5F5E5D5E5F65768990866F
+584E6698C4D6D3CBCACCCCC4B09173656A798E9C9FA8B8C5C5
+B7A68E5F3B2D2F353736333230303441669ECDD9BEA7B3D2EA
+EFE5D3BEAB9F9DA6B7C5CFDDEFFEFEF3DDAF7D5F5C6C839FBF
+DAEBF1EEE9E2D6C3AEA29D988F87838A9EBBD4DEDDDAD5C7B1
+947458443B352F2D2D2E2D2B2A29292929282828292929292A
+2A292828292A2B2C303A454B4A4745484C4D4A4B4C4E4F5051
+545655535352525355565654504F4F5256585A5C627A96ADC2
+DCF0F7F3EDECEEF1F2EEEBEAEBECECE9E7E7E8E8E5E1DDDAD5.
+626D706C635B555455565A626C706C645C5856575A5E5E5F63
+696B6A69665B4C3F3A3D444E595D5C595A5D6269768288826B
+534A6799BCC2BEBEC1C1B9A68D75635D5C5965798A9FB5C2C0
+B39F7F53373032353534322F2D30364871ABDAE7D1BFC4D6E3
+E4DBCAB29C8C8FA5BDCFDBE7F4FCFBF1DAAC7D6464748AA3BD
+D1DFE6E7E3DCD2C8BBAFA49589848796ADC7DBE4E3DFD4C3AB
+8F71554238322D2B2B2B2B2A2A292827272728292927262829
+292827292929292B303C4A4F4B45454A4D4D4B4C4E50535454
+595E5B54504E4F50504F5051504E50555A5D5C5A5D6E8BA6BC
+D6ECF6F3EDEBEEF0F0EDEAEAEBEBEBE9E8E8E8E7E2DDD8D3CF.
+5F6C6F696057525357585B5F676D6C655A515151535454555A
+60676B6D695C4A3D3A3F47525C5F5C56555A626B737C83826E
+5448608CA4A5AAB8BDB4A18872635E5F5C50525E6E88A7BBBC
+AC8C6A4F3E3634333231302F2E2F354A78B6E8F6E6D6D3D6D5
+CFC1AD97898596B2CDDEE6EBF1F8FAF3DEB3876D6D7C90A5BE
+D4DEDDD7CFC7BEB5ACA19488858E9FB4C7D5DFE5E5E2D7C3AA
+9175564035312E2C2B2A292929282726262727282727272929
+2828292A2B2B2B2C2F38434948454547494B4B4B4D5054585B
+60635D56514F4F4F515252534F4B4F565C5F5E5A586380A1B8
+CFE7F3F2EDECEEEEEDECEBEAE9E8E8E7EAEAE7E2DEDAD5CECB.
+5C686A635C565253545555596066676259504C4A4A4B4E5153
+55575E656456463C3C434D565C5B575454585E63676D747B69
+52485D7A848190ACB5A2877060595C625D4F4C50597497ADAB
+9271594C433A3330302F2E2E2E2E365087CCFAFDF0E4E3E6E3
+D9C9B7AAA7AEBFD4E6EBEBEBF0F7FAF2DAAF88767A8DA2B6CD
+E2E6E0D5CAC0B8B1A8A3A2A7B1C0CFDADFE1E4E6E5DECFB9A0
+886F523C332F2C2B2B2A29282727272725252627282827282A
+2928292B2C2C2D2E2F353E434443424245494C4D5054585C60
+61605B554E4B4B4F545757524B4A4F565D6162605D637D9BB1
+C8E1F1F4EFEBEAEBEAEAEAE9E7E3E0E2E7E6E2DDDAD8D5D0CB.
+56605E585453535252504F515659585553514E49484B50514D
+47464C53554D423C3F48515759544E4E53565655575C63695E
+4E4856686A6675949F8E776357545A6261524A484C61809794
+755A514D463D342F2D2F312F2B2E395690D5FFFEF5ECEEF3F4
+EFE8E0D9D7DCE3ECEFEDEBEDF2F7F7EFD9B28E80889BB1C8E0
+F0EEE7E5E3E0DEDCD8D9DEE4E6E6E8E9E9E9E7E2DDD4C5B098
+80664D3B312E2C2C2B29272525282825242526272828282A2B
+29292A2A2B2B2C2E31373C4040403F40454B4E4E5156595C5F
+63635E57504E4F52525252514E4C5054575A5E616164778D9E
+B7D6EEF4EEE9E7E5E7E7E7E6E2DDD9DCDBDAD7D6D6D7D7D5CF.
+5359554E4A4C4F51514D4B4D4E4D4D4D4D4E4E4B4B4C4C4B49
+444040444947424044494E51514E4D4E4D4A48494C535A5D53
+484249535556637C857B695A53545B64635648424657728781
+644E4C4F493A2F2C2C2F2F2D2C2E3E60A1E2FFFDF2EFF3F9FA
+F6F2EFEEF1F1EFEFEFEDEDF0F4F7F5EBD4B399929BABBDD6EF
+F7F4F0EFF0F2F3F2F2F1F3F3F3F1EFEDEBE7E1DAD3C8B8A58D
+71574338312B292929282727272827262727272728292B2B2A
+2A292A2A2B2C2C2E30373E42434241444A4E4F4E4F5254595F
+62605C5B5B58534E4B4B4D4F504E4D4E505254585F68737F91
+ABCCE8F3EEE4E0E2E2E3E4E4DFD7D1CECBCDD0D1D3D5D7D7D4.
+5055534F4B4A4B4E52524E4C4B4B4A494848494A4B49474546
+4745413F404243454647494D5153514E4A454242474E565B53
+473F4045484A525E6668625751525A666857433B3E4D627270
+5D4C494A453C322B2A2C2D2D2D2F3B5A97DAFEFDF4EEF2F9FB
+F9F7F6F5F5F5F4F2EFEDEEF1F5F6F3EBD7BDAAA4A9B5C7DDEF
+F8F9F6F5F5F6F7F8F8F7F7F7F6F4F2EEE9E2DCD5CABDAC9A84
+6B513E36312C28282A2928282929292929292827282A2B2B2B
+2B2B2A2A2B2B2B2B2C343D43444344474C4F4C4A4B4F54595D
+61615D5B5957524E4B4A49494A4C4E4E4B494B4E54606D7A88
+A0C1DEEDEBE2E0E1E1E1E2E0DCD6D2D2CCCBCDCDCED2D5D6D6.
+4E555452504E4D4F545654514D4A4948474643424444444548
+4B4A453D3A3C41454646494E51524F4E4A453F3E434A505653
+49403C3D3F42484B4E5657524D4E58626355443B3A44556263
+574C4A4B4841362E2A2B2D2E2D2E354E83C9FAFEF6EEF1F8FB
+FAF9F9F8F7F6F6F4F1EEEEF2F7F7F3EBDCC7B5AEB3BDCADAEB
+F7FAF8F7F7F8F9F9FAFBFAF8F7F6F4F0E9E1D8CDBFB2A59580
+69513E36302D2A2A29282829292828292A2929292A2A2B2C2C
+2D2D2C2B2A2A2A2B2C323C44484B4D4F4F504E4A4B4F535556
+575654524F4D4A494A4A4948454547494744444446505E6E81
+98B3D0E7EDE7E2E0DDDAD9D9D9D8D5D6D2CDC9CACED3D8D7D5.
+52534E4B4D505252535457544F4A494947413E3F404142464B
+4D4A433A363940434343474C4F4F4F4C47423F3F43484C504D
+463F3A3A3C3F414143474847484D565B584A403C3C46525956
+4F4A4A4C4B42362E2C2D2E2D2B2D354D81C6F7FDF4EDF1F8FB
+FAFAFAF9F8F8F6F2F1EFF0F5F9F8F3E8D8C6B8B4B9C3D2E1ED
+F5F9F9F7F6F8FAFBF9F8F7F8F7F5F2EEE6DBCEC1B2A4968571
+5C493A332F2D2B29282828292828282A2A292A2B2C2C2C2C2C
+2C2B2B2B2A2A2B2C2D34404B515352504F4E4E4B494A4D5051
+514E4B4946444444464746433E3D3E40403F3E3F4148516073
+8AA5C3DBE8E8E3DDDAD8D6D7D9D8D3D5D3CDC7C4C7CCD2D5D2.
+504F474142464A4C4E4E50514D484648453E39393C3F444A50
+4F49423B36373C3F4042454A4E4F4E4B46413F404346484C4A
+443D3A3A3B3D3C3D3E4042434449525551463C393A424C514F
+4C4B4D514E4438312E2E302E2B2C32426CABE5FDF9EEEDF4FB
+FCFBFAF9F8F8F5F1EFEEF1F7FAF9F3E9D9CABEBABEC7D3DFEB
+F4F7F8F8F8F8F9FBFAF9F8F7F6F5F3EEE4D6C6B8AB9D8C7967
+544437312E2A29282828282727292A2929292A2C2E2D2C2B2A
+292A2B2B2B2B2B2C2E343F4A5254524F4E504E4A49494A4D4F
+50504D4845454546454443413D3C3D3E3F3E3D3E41464D5764
+7388A1BBCFD9DAD5D0CDCDD0D2D2CFCFCDC9C5C6C7C8CACDCC.
+4D4D443D3A3B3D3E4143454647484846403A38393B3F464E52
+5149413C3A39393B3E43494E4E4B484442403F3E4042444646
+433E3A393A3A393C41464443434850534D4038373B434A4843
+4243464B473E3632302F2E2F2D2D314067A3DDFCFAF0EFF5FA
+FCFBF9FAF9F7F4F2EFEFF2F6FAF9F4E8DAC7BBBAC1CCD5DFEA
+F4F7F7F8F8F8F8FAFCF9F6F5F4F3F1EADDCEBCADA092826E59
+483D352E2B2B29272727272626292B2A29292A2C2D2D2C2A28
+282A2C2C2B2B2C2C2D3543535D5F5B565657524F4C4E505151
+5354524E49484949474544454442404040414142454950575C
+63708295A8B5B9BABCBEC1C5C9C8C5C5C4C5C8CAC9C6C3C2BD.
+4A4A423C393A3B3A393838393C4042423E3A393A3D434B5050
+4A4444443F3A383940484A4943403F403F3E3D3D3E3F404240
+3E3D3C3B3B3B393E4549484444484C4D483F3736393F43413E
+3D3D3F43403B35323131312E2D2F323E609BD6FAFDF2F0F2F7
+FBFCFAF8F6F4F3F1F1F2F5F7F9F8F2E8DAC7BBB8BBC3D2E4EF
+F4F5F5F6F7F8F9F8F9F8F5F3F1EEEAE3D6C4B29F8C7D706153
+463A322C2B2B2A2928282828282A2A2B2B2B2A2B2C2D2D2A29
+292A2A2A2A2A2B2D2F3D536B7A7D776F6D717677787975706C
+6A696765636362605C5A595A5954514E4C4B494A4C4F505255
+58606E7D8C959AA1A8ADAFB2B4B4B2B1B2B4B5B4B3B2B3B2AF.
+4949423D3B39373635353437393C3E3F3C39383B41474E5250
+4945494C453E3B3B3F4445423D39393C3E3E3D3B3B3D3F403F
+3C3B3C3D3D3B383B4042424241424444423D3635383B3B3838
+3A3B3B3B3937353434333231302F323C5C94D1FAFEF5F2F4F8
+FBFBF8F6F5F4F2F0F0F2F6F9FAF7F1E7DACDBFB8BAC4D5E7F1
+F4F3F4F5F6F8F8F8F8F6F4F2F0EDE8DFD0BBA5918073685B4E
+42372E28292A2A2A2B2A2928282A2A2B2B2B2B2B2B2B2B2B29
+2A2A29292A292A2B2F3D526A7B7E776F6B6B70777D82817E7B
+7A7B7D7B79777A7D7A716C6E74746E6865646668696A6B6B69
+686C75818C929496999E9F9C9997979AA0A4A0999392969795.
+4448433E3B39363535353434363A3D3F3E3C3B3D42484E5354
+4E48494E4A45403D3E41423E3938393D3E3D3A38383B3F3F3D
+3C3A3A3A3B3A37383A3C3D3D3B3B3C3D3C3A37363738373433
+363737353434343434333332323131365081BCEDFFF9F4F2F6
+F9F9F7F5F4F4F2F0EEF0F5F8F8F6F0E8DCCFC0B5B3BBCCE0EF
+F4F3F1F0F2F5F6F6F6F5F2EFECEBE6DBC9B5A28E7D6E5F544A
+40362D27292B29292A2A29292A2A2A2A2A2A2A2A2929292929
+2A2A2928282828282B34404F5D6667625C565663737C7E7A76
+767879767271757A7A7371767F7E7A78787A7C7D7E7C7D7F7E
+7F83888E9295999C9D9E9B96939495949495938E8885848381.
+4448433D3938383836353535363A3D3E3E3D3B3D42484F5557
+514A4A4C4C4944403F42423F3B3B3C3F403E3A36363A3E3D3D
+3B39393A3B3B37353638393A38373738373635363635343230
+323535343232323333333433323030354972A8DDFCFCF5F1F3
+F6F8F8F6F4F2F0EDECEFF4F8F9F7F1E8DCCCBBAEA9AEBDD4EB
+F6F4EFEEF1F3F4F3F4F2EFECEAE7E0D3C1AD9B8A78685A5048
+3E332C282A2C2B2A2A2928292A2B2A2928282A2A2827262829
+29282828272829282A30363E464C4E4D4B48474F5B666D7070
+7070706F6C6B6D71747575787C7B77787F878B8A8581808383
+85888D9193979DA3A5A29D9A9A9EA09E99948C847E78726D6C.
+4548413B38373739373433363A3D3E3E3D3B3A3C41484F5557
+544F4C4A4E4B4540404445423E3C3E41423F3B38383A3C3E3C
+3B39393B3C3B3735373838363535353433323233333231302F
+313535353332313030313333312E3035476C9FD6FAFFF5F0F1
+F5F8F7F5F4F2EEE9EAEFF5F8F8F6F0E6D6C3B0A5A3A6B0CAEA
+FAF6EFEEF0F3F3F1F1EFECE9E5DFD5C7B39F8B7B6B5F574E43
+39302B292B2B2B2A29282728292A2928282929292726252728
+282727282829292A2C2F33393E404142413E3D40444C525759
+5B5C5D5B5A5A5C5E6062646564636368727D8485807C7A7B7D
+8185898D939BA3A5A39E9996979A9A94887E78726D69635B59.
+4349433B3635373938312F333A3D3C393838393B3D3F444950
+5657534D4D4C484341434443403E3F40413F3D3C3B3C3C3E3F
+3D3C3A3A3B3A37353638383634333432313030323332312F2D
+2E32353332323231302F2F31312E2D31405E8BC1E9F8F5F1F1
+F3F5F6F6F3EFE9E7E8EEF5F9FAF7F0E3D4C3B5ADACABAFBFE1
+F9FBF2EEEFF2F3F3F2EFEAE7E1DACEBCA6917F70635B544D44
+3A312C292A2B2A2A2929292928282828292929292827262728
+282727282B2B2A2A2C2F33383A3938393A3735383A3A3D4246
+4A4B4A49494949494A4C4D4C4B4A4B4F555C636C7677747272
+767B80848A9095959291908D89867F74655F6163625F5C544D.
+3F46423C37363739372E2B323A3D3C3937373738383B3E4148
+4F53524D47464848474746444342423F3D3D3E3F414140403F
+3F3E3C3A3938373535353535343434322F2F313331302F2E2F
+2F30313131323230303031302D2D2E313D5881B2D9EDF2F3F2
+F2F4F4F3F1ECE3E1E7F0F7FAF9F4EDDFCCB8AEADB0ACA7B5DC
+FBFDF4EEECEFF3F4F0ECE7E0D8CDC2B29B8472645C564E463F
+38312C2B2C2A2A292929282727282826262829282627282927
+282927282A2B2A2A2B2E32353637373736363433343536393B
+3D3F3F3E3D3C3D404344413F3E3F40414244474D565D616263
+676C7074787B7874767B7D7A736C645D565152595F5F594E46.
+3D43413C39383839352E2D32373A3A3837363536383B3B3B3D
+41464A4946484C4C4A4947454544403C3A3B3F424444454242
+42413E3A3837363433333435353535333230313333312F2E2F
+31312F2F3030313335322F2D2D2F31333C5680AFD1E8F2F3F2
+F1F1F0EFECE7DCD8E3F1FAFBF5EDE0C7AC989498999493A8D6
+FDFFF4EDEBEFF3F2EDE6E0D2C6BCB2A18B76675B524D48433E
+38312B2B2D2B2A292827272627272625272828272627282729
+292827292A292A2B2C2D2F3233343536373635343436363738
+3B3C3C3C3B3D3D3E40403E3B3B3C3C3D3D3D3E4045494F545A
+616565656565636264666563615D584F4647505D61594C423F.
+3B403D3A3A3B3C3C3732303336393A3837363637393A393A3A
+3B3D414241464B4C4A47464644423F3B3A3C3F434544424241
+41403D3936353533323233353636353534343332312F2D2D2E
+30302E2E2F2F303436332E2C2F313131394F749EC1DBEBF1F0
+EFEFEFEDEBE6D7C8CCE4F8FBF1DFC39B7B6D6E737472758EC3
+F9FFF7EEEBEFF2F1E9E2DBCFBFB0A191817060544D4945423D
+362F2B2B2C2B2A292828272727262525262828262425272829
+2827282928292B2D2D2D2F30333535383B3935353739383736
+393D3D3C3C3D3E3F41413D3D3E3D3C3B3A38393C4041424850
+595F5F5C5B5A585654535456575450494446515C5C51453F3E.
+353E3D3A3A3C3E3F3D36323234353638393936373839393938
+38383A3C3C3F45484847474642403F3D3B3C3F424543414040
+403F3C39353333313133353534343433323231302F2D2C2B2B
+2C2D2F31302D2D3033332F2C3032313034405A7EA2BFD8E8EE
+EDECECEBECECE4CAADB6D8F1EECE9D70554A4C515555586DA0
+EEFDFDF2EBECEFEFEAE2D9CDBEAD9C8C7C6D60564C46413F3B
+352F2C2B2D2B2A2A2A2A292826252627272828262526272728
+2827282929292B2D2E2F2E2E303336373A3B3838393A393736
+373A3B3A3A393B3C3E3D3C3B3C3B3A39383837383A3B3C4045
+4D535552515354504D4C4D4E50504E494447515A5B53494341.
+393E3C3B3C3E3F3E3A35323435343435383B393637383A3A38
+36353738393A3D404346474642403E3C3B3B3E4142403E3E3D
+3D3C3A36343332302F323434333332303030302F2E2D2B2A29
+2A2D30322F2C2C2F31302C2C30323130333F577593B0C9DEE9
+EAE9EAECF0F3EED9BBA7ACBDBB9A69463A3A3D3F41454F71AE
+F7FEFBF0EAEBEDEAE4DAD1C4B4A3908072665B5248413F3C38
+33302E2D2E2B2A29292A2A2928262728292725252627272828
+28282A2A292A2B2C2C2D2E2E2F333637393937373838373636
+3737393A3937373A3C3C3C3939393837363738393837383D43
+484A484545494B4B4745474A4B4B494646505E645E51474445.
+3A3E3B3B3C3D3D3B393636373835323538393636383A393938
+363436383836393D4245464644413E3936383D3F3E3C3D3D3C
+3B3A393A3B3A353031323231313231302F30302D2C2D2C2B2B
+2C2F302F2B2A2B2D2F2E2E2D2E303230303A4F6B89A1B6CBDA
+E1E3E6ECF2F5F3EFDFBC967A6D625140373436393C415079B7
+F8FFF8EDE8E8E7E3DCD3C8B9A998897B7064584F46433F3A35
+32302E2E302E2A2829292A2A2A2A2826262626262627292A27
+27292B2B292A2B2A2B2C2D2F31323234363838363639393734
+33343538383535373A3B393939383634343537393936393F41
+413E3C3B3D3F4344434346484948444047525B5A514A484849.
+363A3635393E3E3B38353739393534373A3C3735383838393A
+39363436363636383D42454646423D3734383C3D3B3B3B3C3C
+3C3E3E3C3937353433343433312F2F2F2E2B2C2D2E2F2D2A28
+282D302F2B292A2B2B2B2C2C2E2F302F3037445A758EA3B8C8
+D3D8DEE9F4F8F6F4F1E6C79764453D403E3A383B414B5E7EAE
+E3FAF6EBE2DFDFDBD1C7BFB1A293877C706559514C49443F38
+33303030302D2B2A292A2B2C2B2B2926252526262626272829
+28282A292828282A2B2C2D2E30323434363838383637383736
+35363838353434353535373837333333343638393937373B3F
+3F3B3838393B3C3D3E3E3F4244444442444B5456524B484849.
+393B3433383D3C393734373938353537393836373839393939
+38353538383636383D44474745413A333134383A3A3B3D3C3A
+393A3B3D3C3935302F31333331302F2E2E2D2D2D2E2E2D2A28
+282B2F2E2D2D2C2B29292A2C2D2E2F303237455C758A9EAEBB
+C5CED9E8F3F7F6F5F4F0E1BF895134343F45484C54657F9FC0
+DEE9E5DBD3CFCECBC1B7AFA69B8E8072685F5A57514C453F38
+322F2D2D2D2C2C2A29282828292A2927262726252526272827
+272728282726282A2B2C2D2E3034383A3B3D3D3C3A38363536
+3736373738373533343535363634343537393837383838393A
+3836353638383839393A3C4044464342444B51524F4A494C4C.
+3A3A3433373B3A363435383938363739393734333537383938
+36343639383435383D4142413F3A35313135393B3B3C3B3A38
+373A3C3C3B38322E2E3133302E2F31312D2D2F2F2D2C2C2A29
+292A2C2E2F2F2D2B2A2A2C2D2E2F2F2F3035445B79929FA6AE
+B8C3D0E0F0F6F5F3F4F2EAD09D6646414C555C646F8097AFBF
+C8C9C5BDB7B6B9BAB7B0AAA196897D71655D5B5B534B443E38
+322D2B2B2B2B2A292928272829282626262626252628292825
+252727272727282B2B2C2E3032373B3E3F42413D3B3A393838
+373736373A3B38363537373736363839393736363838373635
+343333343637393B393A3B3F43464748494B4E51514E4C4C4C.
+37393433363939363638373535363737363431303235383A39
+363334363534343537393A3936353533333437393B3B3A3A39
+3A3B3C3C3B38332E2E3132302F2F302F2D2C2D2E2D2C2C2B2A
+28292B2D2E2D2C2B2A2B2B2D2E2E2E2F30343E527596A6A8A9
+AFB8C5D5E5EEF3F3F3F3EFDDB98C6B5F63696E757D8896A4AC
+ABA5A09C9A9CA6B2BABAB2A5978A7E71675F5C5A534C46413B
+342D29292B2B2A292726262828272526262625252628292825
+262727262527292B2C2D2E2F32393E4041403E3A37383A3936
+343536383A3838383939373738393838393836363737353432
+3232323234373A3D3D3C3C3D41464A4C4B4B4C4F4F4D4B4C4C.
+343B3835373A3A38383937353435353534312F2F3133353738
+3735353534343333343739393532333233343638393A383839
+3B3C3C3B3B3A35302E2D2D2E2E2E2E2D2C2B2B2C2D2D2D2C29
+27292B2A292A2B2B2C2C2D2F2F2E2D2D2E303645658DA8B4B7
+B6B7B9BFC6CEE3F3F8F6F0E7D8BEA28E817977797E84898D90
+8B837E7E838E9FB1BDBEB8AEA19485786C635B56504D48413B
+352F2A292C2C2B292726262828252526262524242526282927
+272827252426282C2E2E2E2E31363C3F3F3F3C383637393937
+373533353637383A3A39373738383737383938363635333333
+323231313335383D3D3D3E4042454A4E4C4A49494949494C4D.
+383E3A383A3D3B3A3937353434343435353331303134383B3A
+36353535353636353638393734323231313234373A3C3B3B3B
+3C3B3B3C3B39353031302F2D2C2D2D2D2B29292B2E2F2E2B28
+282A2C2A2A2A2B2C2D2F313331302F2E2F3237416088A8B7BF
+C0BDB5ABA09BB1D3E8ECE8E3DBCEB5957D7371727475736F6A
+646167778BA0B2C0C6C2BBB1A393827469625B534C46423E39
+332E2B2B292928282828272829262525252424242627282827
+272828262324282B2C2E2F2E30353B3E403F3D3D3D3D3C3937
+36353637383938383A3A393636373737373736363633333334
+3434343334363B3E3E3F43474A4C4D4C4A4845434344494F4F.
+39403D393A3D3D3D3B3A3735363736353333323234383B3B3B
+3A38363739393837393B3A35323131323233333436393B3B3A
+3A3938373635343231302E2C2B2A29292A2B2A2B2C2D2D2C2C
+2D2E2E2C2B2B2C2D2E2E2F3133312E2D2E30333C557EA6BAC0
+C1C1B8A3866D6F859CACB7BFC2B89F7D6157595C5B5853504E
+4B4E6287AABEC5C7C8C7C0B5A4928274685D565049443F3A35
+302C2C2C2C2B2A282626282927252525252524242527272727
+272726262525272A2B2C2E2E30353B3F40403E3F3F3D3C3A37
+3737393A3A3A39393A3B3A3837363737373637383735373839
+3837373637393C3D40464B4E4F50504E4B4743404042464948.
+3A403B38393D3F3D3B3A3736383835313133343536393A3A3B
+3C3C3A3839393938373737342F2E2E2F303132343638393837
+36353435363534322F2D2D2C2B2B2A2A2A2B2C2D2E2E2D2E2F
+30312F2B2A2B2E2F2F2E2C2D30312F2D2E303034466995B2C0
+C7CAC7B79C82808C999A969596907F6A574F4D4E4D4B4B4C4F
+576A83A2BCC9CCCECCC7BFB5A69685746457504C47423C3631
+2E2D2D2D2D2C2A292727282928242527282625252526262727
+272727262728292C2D2F2F2E2E333B4243413F3E3E3C3A3837
+383938393A3A3A3B3C3D3C3938373739393737383A3B3B3D3E
+3E3C3A37383C4143484C4E4E4D4C4C4A4644434342403F403F.
+3F423C37383B3D3B393836373938353334353736363838383A
+3B3B3A38373637373633312E2C2A2C2E2F3133353638383735
+3535343434343433302E2C2C2C2B2B2B2B2B2D2E2F2F2E2E30
+33322E2B2B2C2E3031302C2B2D2E2F2F2E2E2F3442608AAEC5
+CFD2D1CCC2BBC3D1D8D1C6BDB3A38E7F7670675E5654596270
+869EAFB9BFC6CED4D1C6B9AD9C8978695E544D48443F38322E
+2D2D2D2D2C2B2A292727272828262728272626262727272828
+2827272727282A2C2D30323030343B404444403E3D3C3A3838
+393A3A39393B3C3C3C3C3C3B3A37373939393A3B3B3B3C3E3F
+40403D3C3D414647494B4C4B4846444242444646433E3B3B3C.
+43433B35343637373534343538393735363839373434343536
+3839393734333130302F2E2C2A292A2B2C2E30323436393836
+353636343333312F2F2E2D2C2C2C2B2B2C2D2E2F30302D2D2F
+31312C2A2C2D2F31312E2B2B2B2D2F302F2E2D323C557EA9C6
+D3D5D6DADFE3E9ECECE8E5E3DFD7CABDB09E89786E6B6F7C90
+A8B5B7B8BCC5CECFC8BBAB9C8C7C6D60554B45423F3A34302E
+2E2F2F2C29292B2A2928272726262727252525262626262727
+272626262626292C2D30312F30343B4043413E3C3A39393A3C
+3D3D3C3B3B3B3B3A393A3C3B3A3939393A3A3B3B3B3A3B3D3E
+3E3E3E3E40434545454747464542424141434444413C393839.
+41423B34333536373632323234373A39373636393837373738
+3836363633302E2E2F2F2E2D2B2A292A2B2C2E303334353538
+39393735333231302F2E2E2D2D2D2E2E2E3031313233312E2E
+3133302C2B2D2F30302D2B2A292A2C2C2D2D2E2F32415D88AF
+C6D1D6DDE6EDF2F1EDE7E3E1DFDAD1CABFAD96827670738197
+A9B1B5B7BBC0C4C5BDB1A3928374675B524A44403C3732302F
+2F2E2E2D2B2929292A29272627272626262525242425262726
+252424242426282A2C2E303031343A4042423D3B3938383A3C
+3D3D3D3D3E3D3C3B3A3A3C3D3D3D3B3A3A3A3C3D3D3D3D3E3D
+3B3B3C3D3E4042434344464543413F3D3C3C3B3D3E3D3C3A39.
+3A413D37333334343537343232343638373536383837373737
+3533343332302F2F2F302F2C2C2E2C2B2A2B2C2E3031323235
+393B3A373532302E2D2E2E2E2D2D2F30323234363939352E2B
+2E32322E2C2C2E2F312F2A27282A2A2B2C2E30313133405F84
+A6BFCDD5DFEAF2F1ECE4D9CCBEB0A299968E82787270758089
+959EA6AAADB1B6B7B0A49A8D7E706358514B44403D38363331
+2F2C2A2C2B2A2A2A2928272627262626262525242425272928
+25242525262728292A2D30323233373C3F3F413F3C3B3A3A3C
+3D3D3B3A3A3B3C3D3E3F3F3D3C3C3C3C3B3A3A3B3C3B3C3C3B
+3B3B3B3C3C3C3D40434443403C393837363637393B3B39393A.
+40403833343738363131313030313232313030323434343433
+302E2E30312F2E2E2E2C2B2A292A2C2B2C2C2D2E3031323435
+383A393633322F2F2F2F2C2C2D2E313231323336393A352E2C
+3134312F2C2C2D2E2E2D2B29292A2B2C2D2F2F3030333C4D6A
+8CACC3D2DDE8EEECE7E0D2BA9C7F6C686C6E707172747A8185
+8A93999B9FA6AAA9A49887786D645C524842403E3B3834312F
+2D2C2B2A2A2A2A292827282827242526262525252626282929
+26242526262729292A2D303132353A3F4344423F3C3A3A3D3F
+403E3938393B3D3D3D3C3B3B3B3D3F3E3B3A3A3A3A3A3A3A3B
+3B3B3C3C3C3B3C3E40413E3A37363434343435373839383A3B.
+3F41393333373736343332302F303132312D2C2F323231302F
+2F2F31302E2D2C2C2C2B2B2B2C2C2D2C2C2D2F302F2F323536
+3738383634322F2D2D2E2E2F2F2F3032323333343535332F2C
+2D3132302C2B2B2B2B2B2A2A292A2B2C2D2F31313133384152
+6C8BA7BFD0DFEAEAE5E1D7C3A789746E7274767A7F8486878A
+8F929291949A9F9E9788776B615A534C443F3C39393734302D
+2B2B2928282828292928282827252627262424252627292927
+25252626262628292A2C2F3234383E444A4B473E3A393A3C3F
+413F3A393C3F3F3D3B3B3D3D3B3A3A3A383738393A38383939
+383737393B3B393A3B3B393734333232323435363838373839.
+3A3F3832313437363532323031323436342F2B2C2F31312F2F
+30302F2E2E2D2B2A29292A2C2C2C2D2D2D2E3031302F333839
+393839393936322F2E2F3030302F303334363635353535312D
+2B2E30312F2B2928292B2B292828292B2C2F31312F30343941
+526985A3BED3E5ECE9E8E5DED1BEABA09C9793929395969595
+9593918C8C8F939289796A60595149433F3C39353535322F2C
+2B2B2928282828282827272828252628272524252627292926
+2526262625262729292C2E3034383F484E4F473D3736393C3D
+3E3D3C3B3E404141404142403B393937353537383A3938393B
+3A393838393938373737363534343434333435373938363639.
+3C3D352F2F323535343333323334353736322E2D2F30302E2D
+2D2D2C2C2C2C2C2B29292A2C2D2B2B2C2D3032333335373A39
+39393B3C3B393531313133333231323436373736383937302B
+2B2E30302D2A2829292A292728292A2A2B2E30312F2E313438
+42546C8CADCAE2ECEEEEEEEEEAE4DDD7D3CAC0B8B1ACA69F9C
+9A96908B8A8A8985796A5E544C45413E3B37343231302F2E2C
+2B2A2827272929282727272625252526272625252626272726
+2626272727272829292C2F3031353D474D4C44393435383A3C
+3C3D3E4042424447494A443E3B3C393635363839363536393A
+3A39393939393736353534343435363534353637383736373A.
+3E3D342E2E3236363636363534343434353432302E2E2E2D2C
+2B2A2A2C2D2D2D2C2B2B2D2F2F2A2A2B2D303337393C3E3E3E
+3E3E40403E3A37353638383532303236393A37373C403D322A
+2B2F32312C29292A2A292828292A2B2B2A2D3133312F2F3134
+3943557195BCDEEDF1F2F4F5F5F2F0EDE9E4DCD1C5BAB1A79D
+9494928C87837F76685C544B443F3C3B3733303030302F2D2C
+2C2C2B2A292929282828262525252626262626262626262728
+292726272727282B2B2C2E2F31373E4549473F3A3838383A3C
+3F424546464545484B49433F3F3D393636373633333437393A
+3736383B3B38363535353535363737363636383939393A3C3F.
+393D352D2C2F33353332333434343434333331312F2D2C2B29
+29292C2F2F2E2D2D2D2E3032312C2A2A2B2E31353A3D414848
+4440404142403D3B3B3B3E3F3E3D3C3D404042454647463D31
+2E3236312D292828292A292727292A29292C3033332E2C2E31
+34363B49658EBDDFF1F5F5F6F7F8F6F4F3EFE8DBCABAB0A8A0
+9B96918A827A736A5C4F4944403D3B383531302F2F31302C29
+29292A2A2A2A29282827262627272525262525252525262727
+272626262627282B2B2D2F2F31363D444A4F4E453E3B3B3C3F
+44474748484546494A46403F413F3A3736363635353436383A
+3836383A3B37363838353536383A3A3736393B3D3F40413F3F.
+353A342D2B2C2E2F313233333334353533323130302E2C2927
+27282A2B2B2B2B2B2C2E2F2F2E2C2B2A2B2D3033373C434748
+454141444645413D3C3E4143423F3F4146494C4E4F514E4435
+2D2E34332E292728282827282A29292A2B2C2E2F31312E2D30
+32323137455F8BBCE1F6FCF9F6F6F9F9F6F2ECE0CDB8AAA39E
+9890877D736B655D5348423C39363534353432303031302E2B
+2B2A2929292A2A292928272525252525272626252425262727
+262627272627292C2D2E303031343B444A4F514B44403E3D3E
+42464B504F4E4E4E4B45413F403C363335363636373838383A
+3B39393A3C3B3A3B3B3B3A3B3F42423F3C3C3C3D404242403C.
+3537302B2A2B2C2C2E3234343334353433313031312D2A2828
+29292A2929292A2A2B2C2D2E2F2E2A292A2C2F3134373C3E40
+3F3E3F4041403B3636393B3C3C3A3A3C3F41444A4E504B3F32
+2C2D30302C29272728292A2C2D2D2C2B2B2C2E2F30302E2E30
+32302E313B4B6B9BCDF1FEFBF5F4F5F6F5EFE5D7C5B3A59C97
+8F83776C6158534E48413C38343334343534322F2E2E2E2C2A
+2A2A29292A2A29292928272525252526272725242526262626
+2627272727282A2C2D2E30323335393D43494C4844413F3D3E
+4147505757534F4B4541414240373232353839373637373738
+393A3C3E3F3E3C3C3E3E3E3E40414040403F3E4043433F3A37.
+3739312B2B2C2B2B2B2D303434353635333333312F2D2B2A29
+28292A2B2A2A2B2C2C2C2C2D2E2E2B29292A2C2F3134363738
+38393A3C3E3D3733303234353434343537383B404448473E33
+2B2A2D2C2B28282829292B2D2E2E2E2C2B2B2E2F2F2E2D2F31
+33312E2F343C496CA0D5F5FCF6F0EFF2F1EBDDCBBBAFA59A8D
+8071645A514C4844413C3936333233343534322E2A2B2C2C2C
+2B2A29292A2A29282726262626262526272726242425262727
+2727272727272A2D2D2E30323233353B424A4D4944413E3E40
+4347515856524E48454546433B353334383A39373739373435
+373A3C3B3B3B3A3C3D3E3C3B3C3C3D3F40413F3F3F3D3A3837.
+3A3C352E2D2D2D2C2B2C2F343636353432313131302E2C2B2B
+292929292A2B2C2C2B2A29292C2C2B2A29292B2E3134353635
+34343436393A393432323131323231323334363B3F42423E37
+2E292C2B2927282A2A2A2B2B2D2E2E2D2C2D2F302E2B2C2E31
+33322F2F3235394A6C9FD1F1F7EFE7E7E8E1D1BFAEA2978A79
+665B544E47423F3E3C3A37353332313132322F2C2B2A2A2A2A
+2A2A29292A2B2A282725252525252525272826242426272726
+252526262627292B2A2B2F313131343C43494A474543424242
+43464C5252504D4A494949453E3938383A3C3B3A3A38373637
+393A3A3B3B3B3B3A38373637393A3B3C3F413F3C3A3A393939.
+3A3B35323232302C292A2E313536353332323232302F2D2D2D
+2C2A29292B2C2B2B292828292B2B2B2B2A2A2B2D2F33353535
+36363739393837353535363737373A3D3F3F3F44494D4D483D
+2E262A2B29292A2C2E2C2B2B292A2C2D2D2D2E2F2C2C2C2E2F
+31302F2E3032343D50739FC7DEE4DED7D2C7B6A6988A7B6C5F
+534A443F3C3A3B3B3A38353333333231302E2C2C2B2B2A2B2B
+2C2C2B2B2B2B2B2A2725242425252525272827262727262626
+2526262727282927282C2E303131343C454745434243464745
+4243464A4D4D4B48484A4D4B463F3C3B3C3E40413E39363437
+3A3B3B3B3C3C3C3A37343536373736373C41413E3C3C3C3C3C.
+3F3D35323334312C282A2D3236363433333332312F2F2F2F2E
+2C2B2B2B2B2B2A29282828292B2B292828282A2D2F32333233
+3536373A3E40403C393A3F444848484B4E4C4E515658564E3E
+2C292B2A29292A2D2D2C2A2A28282A2C2C2C2B2A292A2C2F30
+302E2D2D2D2F31353E527192ACB9BAB3A79C8E83796E625750
+473F3B393636383938353435343433312F2C2B2C2B2B2B2B2C
+2E2E2E2D2C2C2C2B2826252525252424252626272827252828
+26252729292828292B2C2D2D2C2E343D444746474848464340
+3D3B40424548484645474A49433D3C3D3F4141403D3735383C
+3D3D3D3C3B3B3B3B3A373535383A3C3D3E3F4040403F3D3D3F.
+424136303132302C2A2B2E3234343435353533312F2F30312F
+2B2B2C2C2C2A282727282829292A29282727292B2C30333536
+353434383F4547443F3F43484C4E5054585A5C5D5E60615A48
+3126262929292A2B2C2B2A2A292A2A292828292927282B2C2D
+2F2E2C2A2C2C2D31353B46586D7D85847C7167605B56514C47
+443D383535353636363536373532312E2D2D2E2C2B2B2C2D2E
+2F302F2C2D2C2B2A2928272727252323242426272929262627
+2728292827282A2A28282A2B2B2C323C494C494745423E3936
+373A3E3E3E414243434545423F3B3B3B3C3D3F403E3936373C
+3E3D3A3838393B3F3E3B3937373A3E403D3C3E424545424145.
+4240342E2E32322E2B2B2C2E31313234363532302F3031312F
+2E2E2E2C2C2A29282829292929292827272828292B2F333635
+34333436393B3C3D3C3C3F44494E535A60676A696967635A4C
+35252327292A2A2B2C2C2A27272828262526282A2827292B2B
+2C2D2D2C2B2B2C2E3033373D4751595E5E57504B4847454441
+3F3C38353436373734333536343231302F2E2E2C2D2E2E2E2F
+2F302F2D2E2D2C2B2B2A282726242425252525262828272527
+2929282627292A2827282A2A2A2B313C484B463F3C3B3A3734
+3537393C3C3E4143434344423C383838393A3A3B3B37353539
+3B3A363335383A3C3B3A39383737393A393A3C4041403E4048.
+403D312A2C30312E2A29292B2D2F32363736312F2E3031302E
+2F2F2F2E2D2B2A2A2A2A2A2A2A2928292A2A2A2A2C31353635
+333334353738373435373B3F41454D565F6566666767635B4C
+372723272A2928292A2B2A292726262625262729292627292B
+2B2C2D2C2C2C2C2E2F3032353A4046494947423F3E3E3E3E3D
+3B3937373736353432323232313030302F2E2E2F2F2F2F3031
+312F2F30302E2D2C2D2B282624252626272727272727262627
+2727272727282A2827292B2A2A2C313A434643413F3C393735
+36383A3B3C3F42444545433E36343536373736363735333334
+3637363537383936363738363535353434383A3B3B3B3D4045.
+3C39302A2B2E302E2A2A282A2C2F3236393A363331302F3030
+302E2E31312F2D2D2C2C2C2B2C2B2C2E2F2F2E2E3135383C3B
+37353637393A373436393B3D3E404750585E5E5D5F615F584E
+413229262627282727282A2C292827262627282826282A2929
+2A2A2B2C2D2D2D2E2F2F2F313336383A3C3B3A393939393937
+36373736363533323030323433302E2E2F2F2F2E3033333130
+2F2F30312F2E2E2E2D2C2A2826252728282625262727262726
+252627282929292B2B2B2A292A2C30363D4141403F3F3D3A38
+393A3B3D3F4242403F3E3D3B37353738363435373633313134
+3638373535373736373736353434343435373837383B3E4042.
+3A372E292A2E31302D2B2B2C2E313233343536353334343434
+3535353533312F2E2F31312F2F323334353739393B4148504F
+4743454B4F504D484C5052514F5052585E636361626360594E
+42312724262727252425262728282728292927272829282828
+2929292A2A2B2B2C2D2D2E2F30303236393A37363636373737
+333335373836343332303031302E2E2F3132302F3032313030
+3131313131302E2C2C2C2A2725252829272525252626272725
+242426282929272829272829292A2F363B3F3F3E3E3E3D3A38
+37393D3E4041403F3D3C3C3D3D3B3734323232333332323335
+36353433333334353535353332323336373737383A3B3D3E40.
+3A352B282C30313131312F30323332313133383A383637393A
+3B3B3C3D3C3B393736383A3B3A3A3D40424447494B4E535753
+504E4F54595B5C5B5E625D565254585E62625C5C5F63635E55
+49332625282926222224252728282727282827252528282728
+292A29292A2A2B2C2C2D2E2F2F2F2F363C3D3B393737363634
+3333333435343332323333302E2E2E31323231313030303032
+3435353433322E2D2D2D2A2725262727272726252525272826
+2324252727282928282829292A2C30353C3E3F3F3E3D3C3A39
+3B424748464342434444444444423B35313233343433333333
+3537373532323232323334343535363836343437393B3C3E3F.
+38362B272A2F323333333130303131313132373A3C3B3C3E40
+414241413F3F4040404142424242424242424244484E525559
+5956565A5F63676B6D6A615855575C6164645E5C5F63635F58
+4C372825272826232325262728272728282726262728282727
+28292A292B2C2D2C2C2C2C2C2E2E30363E4444423E3A373636
+34313030323332323131302F2E2F3133333333333132333436
+373839383433312F2D2B292725272727262525262626252524
+242527282827282B2828292B2B2B2E33393C3D3D3F40403F40
+434748464341424447494C4B473F3733343534333232313030
+31333433312F303133343435353536373634353536383A3C3E.
+35332B28292D31333533302E2E2F2F2F2F313535383A3C3F41
+4242413F3D3D3F41424342403E3E3E3F3E3D3C3C40454B4E4D
+4C4E52585D61646666645F5956585B5F615E5B58585A5A5853
+4A3A2D25252626252526262625252729282725262828292828
+29292929292B2C2C2B2B2B2C2D2E31374250554F443C393835
+3333323132323131313030303132333536363535363838383A
+3C3D3E3C3835312F2D2B2A2826262626262524242525242425
+252526272727292A2727292B2A2A2F353D41403F3F4041403F
+40403E3D3D3F414346484A48413A373636353332323333312F
+2F3132312E2E3133333333333435373736343232323537393C.
+352E29282B2E303333302E2D2E2E2D2D2F3234323333353739
+3B3C3A383738393B3B3B3D3E3D3D3D3C3B3A3B3D40454B4D4D
+4E545A5E6265686A6A686866615C595B5D5A5755565756534E
+463D322A262526262625252626272728282625272829292929
+2A2A292928282A2B2B2B2B2B2C2E323C4D636A5D4D4341413C
+37353434343332313030313132343638383635363A3E3F4042
+4344433F3B36312F2D2C2B2826242525262524252525242425
+25252525252728292827292A2A2B2F363D42413E3D3D3E3E3D
+3C3B393A3C3E414446474A483F3A3937363535343232323232
+3232312F2E2F3130303133333334343635333230313437393B.
+352F28272B2F323432302D2D2F2F2D2C303437373735343435
+3638393734343638393938393A3C3E3E3E3D3E40464E565D5E
+5D5E60646667676667696B6A655E5B5D605C5452535555534E
+48433D31292526272625242627282827272727272627292A29
+28292A292828282A2B2B2B2B2B2C313D54737F735E514C4A45
+403C393837353333313132333434363838383A3C3F44474A4B
+4A4845413C3733302D2C2A2826242526272725252626262628
+282523232527292A28292A2B2B2B2E333B40403E3C3A383838
+393936373C3F40403F4042433F3C3936353637363433333538
+39373432323131313132323232333436373635343437393939.
+342D28272B2F31312E2B2B2D2F302F2E323939363635353637
+393A3B3D3B3B3D404242414346484A48484A4B4D52595E6264
+63605F5F616263636164696B645A5559605C58585957534E4A
+474743382C25232425252527292A29272627282927272A2927
+262728292828282A2B2C2C2C2C2D303A4F748B88705950504D
+4A47413D3A37343332313436383A39393A3C3E3D40484D4E4E
+4C4A46423E3934302E2D2B2825232425262727262423242525
+25252424242627282928292A2C2E31353B3E3B3D3D3C3A3836
+36383A3C3E3F3E3C3A38393B3C39363536363636363535373A
+3A393735343634323131323436363537393A3939393B3E3F40.
+373029282B2D2E2E2E2C2B2C2E32363A3B3A37353435383C42
+454748484544474A4B4B4C4E4F4F4E4C4C4E505254565A5E5E
+5E5B5653565E625F5C5F625F5955585E605D57585D5E5B554E
+494742392D252223242526282B2C2B292726282A2926272827
+2525282829292A2B2C2C2D2D2D2E313B568399927D695E5957
+544D46423E3A3736363A3E3D3D3D3E3F3E3D3E434C53555554
+53514C45413E38332E2B272524252525262626252525242524
+232323242527292A2727282A2A2C32393B3A393A3C3C3A3838
+3B3E404447484745413E3B3A3A373A40423E383536393D3E3E
+3D3B3A393939383738393B3D3E3F40424241434446494A453D.
+38312A292B2C2D2C2C2C2D2F323436383A383435383A3D4146
+4B4D4E4E4E4D4C4B4A4C4F5356534F4E4F504F4F50555D6366
+645E544E545E625D595C5F5E5A57585D5E5954575B5C595351
+514E483E32282324262728282A2A2928272727282726272826
+2527292928292B2A2A2C2C2D2E2F31375283A5AA9C88776A60
+5D564E474241403F3E3D3F4243424141404144474D565B5B5A
+5A5B564E453E3A352F2A272524252524252526262625242423
+222222242627292825252729292A2F353838373A3D3D3D3E3F
+44494E566067645C524A454546464A4F504A3F39393C3E3E3D
+3B3A3A3A3B3C3F40414246494B4D4C48484B4D4D4E4E4B443C.
+39342D2A2B2D2E2F2F2F31363B3D3E3E3D3B3A3C3F4243464B
+505354535251504F4F505256595955545454514E4D525B6165
+65615750545E615A55585E5F5D59585A5C585354565755514E
+4D4A453E362D26242628282726272728292826262727262626
+272728282929292B2C2C2C2D2E3031344C7EADC1BBA7928277
+6F6357504D4B494746464648484847464647494C535A616462
+616260574B423E38312B272524242425252424252626262625
+23232324252728292626272827272C313537373C414546474B
+51575B636D737167584D4B4E50515456555047414040404140
+3F3E3D3D3E42484C4E4E505150505254585F646460584E4644.
+39362F2D2D2F30313233373B3E41424140414140414345484C
+4E4F505050504F4F4E4E4F5257585552505051515051565F62
+62615B54565E605955585E615E585456585552525456544F4B
+49443F3B342C25232527272524242527282826252527282726
+2627292A2A29292A2B2B2B2C2D2E30354874AACBCEBAA3948A
+7F6F615B58565350504E4D4B4C4F52504D4C5055595E646767
+676763584E463F37302A272726252525252525252626252524
+242323242527282A272526262526292C3134373E454B4C4D50
+565D646B6F6A6158514E51535255585855514C4A4C4E505357
+5349413F40464D535656565352545B67747E85858075655750.
+3C37323031313334373C3D404141404042444242404144484D
+4F4E4C4E4F4F50504E4B4A4C4F5050504E4B4B4E4F53596060
+5E605D5552555958585B5D5D5A54504F4E4F515354534F4943
+413F3B38312A26252626242424252627282827292927272828
+282728292A28292A2C2D2E2E2E2D2E32446AA2CCD8CAB4A295
+8D81756D68635F5B555455575A5B5B575250545A5D626A6E6F
+6E6B675F5550473C312B272626272725252323242424242323
+2323232425262728282525252524262A2F32373C4043424246
+4B4F575C5B534B484B4F505357595754504D4D545C6163676A
+5F4C3F3C424B545B5F616364686E757D848882797169605850.
+3B39333032353636373B3D3E4143434141424242434546484B
+4F504F4A494E555553504D4C4F4E4946484D4F4D4E52555A5D
+5B58534F505659565252545757534E4D4D4B4D50504D4A4743
+4040403E362B24242728282626272828272527292928292929
+292928282829292B2D2E2E2E2E2F3032375386BCDBDAC5B0A2
+A09E95887A6E67615D5E6465625E5C5A59595C61686F757878
+7878756B5E575247382C27282A282726252323232324242323
+232424242628292826262727252425272C3033353839373639
+3D3E43484945413F3F40464F595B554C474A545F6767676A6B
+5F4B3B384151626B6F7171717274787973695E5753504B4645.
+3C3933313438393938393D404241414245484646474A4D4F51
+5250494342464B4E4D4A494B4D493F3939404547494D545D61
+615F5954555A5D5A5755565554514D4B4C4946464B4F4C4136
+33393F3E352A22222527272725252728262425272828272829
+282828292929292A2B2C2D2D2E2F303339517FB3D5D9C6B3AA
+A9A69E92867A6F646064686766666564676A6B6C727C83847F
+7B7970665F5B554A3B2E2624262A2926232324242425242223
+23242425262829282625262625252425292D2E3133302E2F33
+353334373836353435363A40464A49474954636C6C645C5956
+4E443E424F6170716E6B6B6A686562605A534F4D4A443F3D3F.
+3C373334383B3C3C3E404244444343464C5152535456575756
+53514B44414446443F3C3F4548413A373535383A3C414D5C62
+625D544F51585B575455575855514F4F4F4B4B4D4F4E463930
+313D433D2F231F232725242424242525252425252526272827
+2727292A2A2A2A2A2A2B2C2E2F313133405A89B7D3D4C4B5AC
+A8A59D91867E797470706F6E6C6C6F727374757C8184868686
+86817569635F5A4D3C2E252225252525252525252424242425
+25252425282A2A272525272625242526272A2B2D2E2C2B2C2E
+2E2E2D2E3031302E2E3033353A40454D5962615851524E4844
+43485362747D7E7C7A76706A65605D5C5C5F60584A3F3B3F46.
+3D3B37373A3E40414142474A4A48484B535B60605F5E5D5A58
+595A53463F414647413B3C43463E36343332333332323A4F5E
+625D544D4E5557524C4D5054565553514F4C48494E4F463830
+303A3F3C2F2420222525242423222324242425252526252728
+2828282A2B2A2A2A2A2A2B2D2F313438465B80A7C4CDC5BCBA
+BAB7AEA3978F8C867D7A797A797A7B7C7C8085898E908F8E8F
+908D8171645D5A524535282222242425262829262424242525
+252525272A2D2C2825242424232222242527292A2A29292929
+2A2B2B2C2D2E2E2E2D2D2D30343C44505B5D5141393A393839
+3E4B5C6F80898F92959287766762666A686562584A41424951.
+3D3B3837393D3E3E3F41474B4E4D4A4A50585B5C5A595A5B5C
+5B59544B4747484A463C373B3F3C353537383734302E2F3B4C
+56554E4A4A4D4F4A434043494E525657514236374148443C33
+303337362E2622222324242423232222222324252627272726
+2829292829292A2B2B2C2C2E3034394352627B99B5C6C7C3C2
+C6C5BFB3A79E9A958C87898583848789898A8E949A9C9A948F
+909592816E655F564A3C2F2623232526272828262524232424
+242425272B2F2E2925232423232223232426272A2A28272728
+28282A2D2D2D2E2F2F2C292B30383F44474641382F2B2C2E31
+374253657482929EA6A69A836A5F61696C64544540444E575B.
+3E3C3836383C3E3D3D3F464B4C4A46464B545958534F4F545B
+5F5B524B494C4D4C44362D2E343734383D42423D342C2A2E36
+3E45494C4E4D4C4A4845413D3B3C4249493D2E2A2F373C3A35
+302F30302B2622222425262623222121222324242527272727
+27282827282A282A2D2E2F32373E47546575889EB3C2C6C7CA
+CCCBC7BEB2A7A1A09F9D9B938E8F949998999FA6A7A4A09EA0
+A3A59E8C776960574A3C312925242526252728282625262626
+252425272B2E2C27232322232323222324262729292727292A
+2A2B2D2F2F2E2E2F2F2B272930383A36313033332E28292A2D
+313A45525F71879BA39D8D7B6D676970776C513F404C575E60.
+403B3634373B3B393B4045494A4845474E54574F4A484E5860
+615A504C4E5250463A3231343835343B464C493E322B2B2D2E
+3137404849443F42444139333235393F413A2F292A2F343634
+312F2E2D292524242425262522212122232425262625252626
+2729292828292A2C2E31353B4452606E7C8897A7B5BFC5C8CB
+CFCECBC4BBB5B2B0ADACABA7A3A6ABACACAEB3B7AEA4A0A3AA
+AFB0A78B736B665B4A3C332A25232424252728272625262626
+252424272B2D2B272323232424242324262728282727282929
+28282B2C2D2F302F2D2A292B3137352E29292C2E2D2A29292A
+2E343D49586E869693857974716D6E76725F49434B565B585A.
+433F39373A3D3D3C3D42494B4A4644454A51524C4849525B5D
+59514E4E504D453D38383D43413A373C47515147362C282B2D
+2C2D31373B3E40403D36302F3335373B3D38302B2B2D303333
+302D2B2B272425252523232323232323232425252525262626
+27282727292B2B2E33383F4A5A6B7C8F9FA6A8ACB7C6D2D5D0
+CCCDCCC7C2BFBFBDBAB7B5B2AEB0B8BEBDB9B7B8B4AFAEAEAB
+AAADAE9E8476716D5F49342826242526262627292A27252627
+26252526292B2B282422232425252525252727262627292A29
+282727292A2A2A2B2B2B2B2C2E302F2C2A2A2C2D2C2B2A2A2A
+2C323A434C5C799AA498816F67696D6B5E504A4E5557565458.
+4745403C3B3C3C3F4144494C4D4B4846464A4B49494A4F5456
+524C47464745403D3B3C4145433C3A3E47505148392F2B2A29
+2A2B2E303134383A352F2D2F3133343739362F2C2D2E2F3030
+302F2E2B262425262525242425252323242526252526262627
+2728292A2A2C2F353C455364788CA2B7C6C7C1BFC5D0DADCD5
+CFCECEC8C3C1C2C3C2C1C1BBB5B5BDC5C6C2BEBDBBB8BBBBB7
+B4B5B6AE9D877B756851392925262727262626272928262729
+28252426292B2A2624232424252524242526262526272A2B29
+2726252727282727292A292B2C2C2C2B2B2B2C2E2E2C2B2B2C
+2F33383E475977949C917E6E666461584E4A4F5555524F5159.
+4A453E3A3A3A3B3D42474C4E4E4D4945434444484E51505050
+4D4946413F3C3B3B3D4144433E3A3C424B514F44352D2C2B2A
+2C2F31312E2F3538363332323131323739352E2B2C2D2C2D2E
+302F2925222225262624232324242425262726252526272829
+29292B2C2E34404D59647388A3BACAD8DCD9D2D0D4DDE3E2DA
+D4D2CDC8C5C5C7C9C9C8C6C2C0C2C4C7C9CED0CECBCAC8C2BE
+BEC0BEB4A39087796248342A2828262525252627282726282A
+282626292C2C282523232424242424242424242425282B2A28
+27262627282726282A2B2A2C2E2D2D2E2F31333636312E2F33
+383D444E5E7388928E847B756E605043444E5757504A4D5862.
+47453F3A363636373A3E44494B4B484645464A505353504D4A
+484644413D3A393A3D424646413B3B3F454B4D493D332D2A29
+2B3033333030333534353737353231343634302D2B2B2C2C2C
+2C2C2A2521212324252524242424242324252627262627282A
+2B2B2D303743586B767C879DB6CDDCE7EAE6E1DDDDDFE2E0DA
+D9D6D0CBC8C7C9CDD0CFCDCCCECFCFD1D6DCDDD9D3CFCBC7C3
+C0BFBEB3A49E99886C513F332B262525252424252626262A2E
+2C2826282A2A272523242424242424242525252425272A2C2B
+2B292928282827292B2C2E323535383C42454646443D3A393A
+3E45505D6A78858B8D8F908D806648363C4B55544C484F5F69.
+4545403A3635363839393E4446464647494A4A4F5355514A45
+444444423E3B3B3D4043464948423C3D424648463F38302826
+2B32353532313232302D303436353536383632302E2D2C2C2B
+2A282725232323242627272625242323242728272527292B2B
+2C2E333C4B637B85868A9AB3C8D5E1EBEFEFEBE7E3E0E2E4E5
+E1DAD1C8C5C7CACDCFD0CECFD5DBDBD9DCDEDFDDDCDAD3CAC4
+C5C8C7BEB0A9A2958067503E322E2C2B272425272827272E34
+30282527292A282623232323232324252728262424272A2E2F
+30302E2D2D2C2C2D3034363A414547494B4C4D4D4C4A4B4E51
+545A616A75828E94999C93836F5741383D47514F4947526268.
+4A483D363435373838373D403F3E42494D4B4A4C50514C4542
+4342403D3B3C3D404142444949433D3E3F4245484840322825
+2A3134322F2D2D302F2C2C2F323537393B38363432302D2B2B
+2B2926232223252525262625232323262828272627292A2A2C
+31394454697D87858695AEC6D7E0E7EFF2F1F0ECE7E3E3E7E8
+E9E3DCD3CFD0D0CDD1D9DEDEDDDFE2E3E2E3E3E3E3E1DED8D2
+CECDCDCAC3B4A595836F553C2E2B2D2A2726282A2A26293033
+2E2926282B2B272421232424242425252627252526272A2E32
+3737383A393B3E4141424349525B5E5E5C585453585F697174
+7A82898F94A0ACAFA3896B554B464342444B504D4646505A59.
+49443C373636373839393B39383A40474A4846484D4C484340
+4040403D3C3C3D3F4041444747413E3F40414447463F332926
+2A3032312F2F30312F2D2C2D3034383A3D3D3A3734312E2C2C
+2A26242526262524232222232525272929282728292A2B2D34
+41556F8998979496A3B6CADAE4E8E9EAECF0F2F0EAE8E9EBE9
+E7E3DEDADADDDEDEDDDDE0E3E5E5E6E7E6E1DDDADEE1E0DBD6
+D3D1CCC4BAB0A79F907553382C292A292726272929282D3536
+2E2624282C2B26232324252625252424252626262627292A2C
+3035393F4346494B4A4B515A626A707273737271757D848788
+8C95A0A49D93959988695147474A4E504D4D4D4844464E5453.
+4B453C3735343537393A3A3937383E4448494846464745423F
+3F40403D3B3837393E43484B49433D41444442413F3B332B28
+2A2D303335333030312E2C2C2E31353C42433F3834302F2F2E
+2C28272525252525242423232325292A28272728292A2D3442
+587593ABB4AFADB2BCCAD6DEE3E7E7E6E8EDF1F2F0ECEBECED
+EAE7E4E1DFE0E1E1E0E1E5E9EAE9E9EAE9E5E2E4E5E5E5E0D8
+D1CDCAC6BCB2ABA28E6D4A36302D2C2C2926262829292C3233
+2D2726282A2824222425252625242323232425262728272626
+292C2E32363B40464C4F525A6A787F7F8185888B919BA09D97
+918F908F877A70767567554B4C5255575654504944464D5353.
+4A453E3835333335393D3D3D3C3D41474A4A4946444443403E
+3E3F3E3D3C3A393A3F474D4F494443464947413A3632302D2B
+2B2C31373A38322D2D2E2E2D2E30353F45433B332F2F2F2D2B
+2A28272523232425252423222325282826252628292E384C64
+7C95ABBAC1C4C6CAD1DCE6EAE9E7E6E8EDEFF1F2F1EEEDEDEE
+EDEBE8E5E3E4E5E6E8E9E8EAECEDEEEEEBE7E7E6E5E5E4DFD8
+D2CFCCC6BCB0A59274553F332E2A292A282626282A2D313532
+2B262629292522212224252525242322232425272827252425
+272B2D30323435383C414751647881838E9CA4A29FA4A9A89E
+8D7C72717471676B716D6055565E6467645F574F4C4C4F5152.
+413E3C3935313032394142403F41464B4F4D4A48464443403F
+3F424342424140434A5154514B4C505350483E35302F302E2A
+2A2D333B3E3A332C2A2C2D2E2F32363D403B332F2E2F302E29
+26252524232222232425242425262727252526292E364B6782
+99AAB8C8D4DADCDFE4EAEDEFF0EEEBECF1F5F4F1EFEEEFF0F0
+ECECEBE9E8E8E8E8E8EAECEEEEEFEFEEECEAE9E7E7E8E6E2DC
+D7D0C9BEB1A5987E5C44392F282428292828282A2E32383730
+2927282A292320212324252625242323232425262625242424
+272B2F3031302F3034373A4354677185A4BCBCAFA29EA4A69A
+826A5F626B6C696F7069605B5C636B6D645C585653504D4E53.
+3A39373534333133383E42403F40464C4F4E4B474747474545
+484C4D4945464B545D5F584F4D515458544A3D353232322E2C
+2D2F353C3F3E382E27282B2C2E32353A3E38322E2E30312F2A
+262424242424242425252525242627262526282C34425C7C9B
+B2C0C9D3DBE0E7EAECEFF2F3F2F1EEEEF1F4F5F5F4F2F1F0F1
+F1EFEDEBEBEBECECECEDEFF0F1F0F0F1EFEAE8E7E7E9E8E2DD
+D8D1C6BCB2A89D8A694A3A312824262828282A2F3334353631
+2B282829272321222324252525242424252525242323232224
+26282B2B2C2D2E2F303133363F4B5B769FBFC0AB95888D9490
+816E5E555660696C67605A5659626B6C5E56565755504B4B51.
+3A38343334343334363A3D3D3F42484D4F4C47474A4C4C4E50
+51525150565C5C58575B5E5B5751515654493E363332332F2D
+2D30373E403D362D2827282C2F3135393C393632302F2F2E2A
+2523242425252524232323232426272725262A3038537AA0B7
+C1C8D3DFE7E8E9EEF1F3F3F4F5F6F4F2F1F2F4F7F7F5F2F3F3
+F3F1EEEBECEFF0F0EFEDEFF1F1F0EFEFEEECEAE8E6E7E5DFD9
+D6D3C9BCAEA39F8F6D48332C2A292C2D2C2B2C2D2E2F333730
+29272727262322202123252626242222232424242423222121
+232527292A2B2C2E30313332353B4E6D97B6B8A69590929089
+7E746B60585A69706D655E5B5E6467605A5A5B5A5753515254.
+3D3833303235373838393D42474A4C4B494544494C4D4E5153
+5352576067655E5B5F686B63564C4C4E4C443A34313334322E
+2D31373D3F3D362D2726292B2E3236393B38363534312E2A27
+2524252424242423232325252525252526282C334571A6CAD7
+D9DBE2EAEEEEEEF1F5F4F4F5F5F5F5F6F4F3F4F5F7F8F7F6F4
+F4F2F0EEEEF0F2F2EFF0F1F2F2F2F3F1EDECECECECE9E6E0DC
+D9D3C6B8ACA7AC9A71472F292B2E32302B2727292B2C31322C
+27262728252221212223242425252424242425262523222120
+212326282B2C2D2E2E2F3032343D53718E9D998C83848A8E8E
+867D766F69686D7270686261636561575B6568645D57585F67.
+403D3631303336373A3C3E43484A4B4B4946464A4E4F4E5051
+504F556064625F626C7370635348464746413A353132363531
+3032373D403D362F2B29292A2D32363839393A3A3834302C28
+2726262423232425252525252424242527292C334C76A4C8DD
+E5E8EAEEF0F0F1F3F6F6F5F6F7F8F6F6F5F5F6F8F9F8F6F7F7
+F7F4F2F1F0F0F2F3F1F1F2F3F3F4F4F2EEEBEBEBECEAE7E1DC
+D9D3C7BDB7B2AFA07F5635282931322F2B282727282A2C2E2B
+27252627262322212223242425252524242425282825232222
+23242526282A2B2C2D2E2F303338475B7081898983808898A4
+A3988D867C736E6F757B7B766D68656161636464605D5E6775.
+42403A34313235383C4044474A4A49494947484D504F4C4A48
+474A515A5B5B5B626C716D604F44404243403B363130363734
+3234393F413E37322F2C2A2A2D313437383B3B3A3836322E29
+24232525242323242424252525252526282A2C354E77A4CADF
+E7EAECEDF0F2F3F4F6F7F7F6F7F8F8F5F4F4F5F7F8F8F6F7F8
+F8F5F3F2F1F0EFF0F1F3F3F4F4F3F2F1EEEDEEEDEBE8E6E3DF
+DAD3C9C1BEB8AEA08865412B29333A383129252628292A2B29
+26252626252423232323232324252524242527282725242323
+232322232427292B2D2E313333353D4C637D8C8D827A808B94
+95918E8B837B79787B838B8C88817B756E6C68686A6A6C7581.
+413F3E3A3634363B41474D51504B4848484A4A4C4D4C494442
+4348525A58565B646D6D6557483F3F41413D37323034393734
+34373B3E403F3A34302E2C2C30343738393A3B3A3937322C27
+2525262524232323242526272625262A2D2F364A74A7CADEE6
+EAEDEFF0F1F0F3F7F7F7F7F8F8F8F8F6F5F5F7F8F8F7F7F8F8
+F6F2F1EFEFF0F2F3F1F2F3F4F4F3F2F0EDEEF0EEE8E7E7E5DE
+D7CDC0B6B4B0AA9A816143312D333C3B3128232427292D2D2A
+25242526242323232322222224252525252728282523232423
+232121212326292C2D2E3137393C404B5C6E78766C6B788184
+848890959491939391949BA1A29D97928E887F797674757D86.
+42403E3E3D3B39394049505353504C4B4948484E52504B4846
+464E555B59504E5761635C514439383B3C3A363334383D3D38
+333234373B3D3B3833302E2F32373D3F3C36363838352F2926
+25262625242323232425252526272A2D2F35466799C2D4DFE7
+ECEFF2F2EFF1F7F8F7F7F7F8F8F7F7F7F7F7F8F8F7F6F6F7F6
+F5F1EEEDF0F3F5F4F4F4F5F5F5F3F0EDECF0F0EBE9E9E8E4DE
+D4C5B5B3B7B0A3907864503B2B273036322A232024292C2D29
+24222324222120212121212223232324262829272625242321
+20201F212325282B2D2E31363B40444A545E65696E757B7D78
+74777E85898A88807E8085888684868A85796F6D727C858A8B.
+4A464645433E3A393C424A525857524E4C4B535D605A524F4F
+51535B6261564E50585D5A514437363B3E3C3937383D41403A
+332F30373E41413D3833302F333A3F403E39393A38332E2A26
+24252526262625252525262627292B2D303C567A9EC0DEEEF1
+EFEEF0F3F4F2F4F6F8F9F8F7F7F8FAF7F7F8F8F7F6F6F6F5F4
+F4F1F0F0F2F5F7F7F5F2F3F4F5F5F4F1EEEAE8E9ECEAE8E5E1
+DBCDB9B2B4B0A38A6C54463B30282B2F2D28232224272D2F2B
+2522242524232220212224242423232224282C2B2824242424
+232220202124272A2C2D30373F45494E515355585955565753
+50545F6A6D6F6E6766696C675E5B5F696D6C707684959C9386.
+4D4E4D49423D3A383A4047515B5F5B544E4F5D65635F5F6363
+5D585F6B70675C595B5D5A52473C383B40413E3C3C3D3D3D39
+3534373C3F403F3D3A3734383D40403E3C3D3C3C37302A2626
+25262625252424242628292B2D2E2C2C35476386A7C8E6F3F2
+EFEFF1F4F5F4F5F6F7F8F9F9F9F8F9F9F8F7F5F5F5F5F4F3F3
+F4F4F3F3F3F4F6F6F5F4F4F5F5F5F3EFEDECEEECEBE9E7E4E0
+DBCFBCB1AFAB9C82634A3D39332A2A2C2C28242325292E302B
+25242526252323222223252524232222262B2F2C2825232324
+24232322212225282A2B2C31393F4141414346494B5155544F
+515C6566605F687885877A604847586F7D818189969C917768.
+4D50514A423C3A3A3C41444C5961625D5756636D6B64646765
+5E5962737B75685F5E5F5C544B403D414647443F3C3B393935
+353A3F41403E3F3D3A38393C4143423E3B383839352D262223
+262626262626262628292B2C323330313E56759ABBD8EDF2F0
+F0F3F6F6F7F7F6F8F9F9F8FAFAF9F9F9F9F7F6F6F6F6F5F5F5
+F4F4F3F3F4F6F8F7F5F4F4F4F5F4F3F1EEEDEEEBEAE9E8E7E4
+DED3C2BABAB2997A5B4438312B282C2F2E2A2523262A2E2E2C
+282625252322222222252625242424262A2D302F2C29262626
+262524242323232427292B2F34393F42403E4048556865564E
+576A787568637294AAA3866044425873878F8D92968C755D59.
+4D4E4E49413A383A3E41424855646C6B645E646E716A63605D
+5A5963757E776A5F5C5E5E5950453F424546433E3B39363535
+363A3E414241403B383A3D3E3F3F403F3E3633322E2A252323
+2526282827272828282B303234343336435E81AACBE1EEF1F1
+F2F4F6F8F9F8F8F9F9FAFAFAF9F9FAFAF9F7F5F5F5F5F6F6F5
+F5F4F4F4F5F6F7F7F6F4F5F4F4F4F4F2EFEDECEDEBEAE9E7E4
+E0D7C9BFB5A68D735D48362A26272C2E2D2A2625262A2E2E2C
+2825242322222223242526262526282B2C2E3234312D2A2A2A
+2A282625242323232326282C323A4247423B3B485D6E66524B
+5B748280766F748C9B947A5D4C4D5F788D948F898073656169.
+4B4C48423E3A37373A3F3F435066797F776C696C6F6E6B665F
+5B5F6B777B7469605F62625E564C464545413C393A3B373639
+3C3D3F4143423F3A373B3F414040413E38302A292625242425
+252527292929292A2C3034363636393F4B6284AFD2E6EFF1F1
+F2F5F7F8F9F7F8F9F8F9FAFAFAF9F9F9F8F7F5F5F6F6F6F6F7
+F6F6F6F5F4F4F5F7F7F7F7F5F5F5F4F1EEECEDECEBEAEAE7E1
+DAD0C3B8B1A68E735841302827292C2C2C2B292725282D2E2C
+28242322222324242425262525282C3033383D3D37302C2C2C
+2A28242324242323242426292C31373C3C383A475B6054494B
+5B6F7D7E766C6D7D8886786A636570889897887A7372788289.
+4848433F3E3B39393D43444555728C93897A726E7077777067
+6265707874686160626563615E575049413936394042403D3E
+3F3F41424342413D3B3D4043413D38322B2825242424242324
+2526282927282C31353A4148403B3F4859769DC5E1F1F4F2F2
+F4F6F8F9FAF8F8F9FAFAFAFAF9F8F8F8F8F8F7F6F6F6F6F6F6
+F7F6F5F3F3F4F7F9F9F6F6F6F5F4F3F1EFEBE9EBECEBE8E5E0
+D9CDBFAEA39B876746302A2F32302D2F302C2724272C32322D
+26222222222325272727282A2D333C454B4A3E322A282A2A29
+282826252524232222232425272A2E33363A414F606C6E6E70
+777C7E7E7F82889196979797928C8C91908981818896A4B0B3.
+4A47433E3A3736383E43424250708D94877A7B828889867F76
+71757A76706A6665676A68635F574D453D3A3C4042403B393D
+43474746454546433F3C40423E372E28262627252322222326
+27272727282A2E363F444B514E49484D5F81A8CCE7F3F3F0F1
+F4F7F8F8F7F8F9F7F8FAF9F8F8F8F9F8F8F8F8F8F7F6F6F5F5
+F3F3F3F5F6F7F8F9F8F7F6F6F5F4F2EFEDECEDEBEBE6E0DBDA
+D9D2C6B2A19A8B694632303638323032342E2725272B31312C
+25222324252627292B2F363B3F4243433F38302C2B2A2A2827
+2727262524232221222324242425282D34393D42494E5C6A72
+777C81878F9CA7ABAAA9AAAAA69F9DA7AEACA8A7ABB1B5B9C0.
+4B49443E393635373B3E3C3E48627C837666697F949C9A938A
+817D7976736D68686A6B6B68655A4E46403F4243413C39373C
+454B4C4C4C4C4A443F3D3F403A312824252727252322222325
+26262727272A313A43484E555E605851618BB9D7EAF3F2F1F2
+F5F8F8F8F9F9F9F9F9F9F9F9F9FAFAF8F8F8F8F8F7F6F5F3F4
+F4F6F6F6F6F6F8FAFAF7F7F7F5F3F1EFEDEDEBE8E4E2DEDBD8
+D5D1C8B6A69A896D4F3C3838373634312F2B2727282C30302B
+2521232526282B2E323940403C3836343434332F2C2D2E2E2C
+2B2B2A272424232322222222232425272B30363B404446494B
+525C68758697A0A0A1A6ACACA59D9DA7AFB4BAC2C6C7C6C5C3.
+4D47413B373435393E3F3C3C425263696153516E93A5A1968D
+8A88827A7574726D696A6D6E6E67594C444444433E3A393B40
+44484C4F4F4D47403D3C3B38322A2422242526262523242527
+27262626272D37434F565C66737164596997CAEAF4F3F2F3F5
+F7F7F8F8F9F9FAFAFBFAFAF9F8F9F9F9F9F9F8F7F6F5F5F5F6
+F6F6F5F5F6F6F7F8F7F8F9F8F4F2F2F1EEEBEAE9E5E2DDD9D6
+D5D2C8B7A699896E513D37393C3B352E2928282929292B2B29
+252325292D31363A38383835343537393C4044484A49453F3A
+3938322E2C2A2726242322222222222325282C31373A3A3939
+3B40464E5961676D7E919EA19D9A9DA4A9ABAEB9C7D0D2C9BD.
+4A443D37343334363B3F3D3C3E444D53544F4A61859898918D
+8F908D8583817C7671727477787264544A46423E3937373C3F
+4145494D4E4A433E3A36322E2C282523242424242525252626
+262626262A313C485562717D857F7066759DCFF5FDF4EFF1F5
+F7F7F7F8F9F9F9FAFBFBFAF9F9F9F9F9F8F8F8F7F6F5F5F5F7
+F8F8F5F5F6F8F8F7F7F8F9F6F5F5F4F1EEEBEBEAE7E3E0DBD7
+D6D2C7B5A49A8C72513931363B3A332C282628292927282928
+27292E343A3B3D3E3C3B3C3E434C54585B5E62615C554B3F3A
+393A35312F2E2A2724232424232221222324262A2D31333737
+373A3E4143454B54627589928D847F838B8B878996ABBBBDB2.
+463F3A3733313233373C3D3D404447484947455C7D8F8F8889
+929A9C97928A837D7C7C7A746F6A655B544F463B353437393D
+3F44494C4D4A423B35302C2927252424242425252526262626
+2625272A2D333D4959718B988E7E777C96C1EAFDF8F1F1F4F7
+F9F8F6F7F8FBFAFAFAFAFAF9F8F8F8F8F9F9F9F9F8F7F7F8F9
+F7F7F8F8F7F7F8F9F9F7F7F7F6F5F4F2F0EEEEEDE9E5E1DFDE
+DCD8CCB59F9F967A543933393A39332D282526282828282A2C
+30373D414344485461676763636A71716D68605650483F3531
+32302F2F2D292624232324252525242322222325262A2F3335
+36383B3D3D40444C56657A868479706E7071706A697285979D.
+463D36323131323234393F424345454645423E475A656F7882
+8B8F8F8F8C877F79726C6A6A6763605B554F48413B393A3E3E
+3F42474B4D4A41342B26242526262423232425272625252526
+2827262B323C4859728D98938A8B96ADCBE5F4F7F5F3F6F8FA
+F9F8F8F7F8FBF9FBFBFBFAF9F7F6F8FAF9F9F9F8F8F8F8F9FB
+F8F8F8F8F8F8F9F9F9F8F6F4F5F4F3F0EEEEF0EEE6E1DFE0E2
+E0D5C6B8AEA08665493B37383937332F2A2727282B2C2F353A
+3C3E4554636C71767B7D786B616062615852524D47433C342F
+2E2F2F2E2C28252323232223242425252423222224262A2F31
+3334353536393B3E46515C656B72766B61615F5853596D8591.
+4439323132343434373E44474946424143433D3B3D414A5766
+76889497938A7F77726F6F6D635F60605B544D46423F3F4241
+41454A4D4B4336292324252526262523232427282826252728
+2828292C3442577087949595A8B8C2CFDFEEF4F5F7F9F9F8F7
+F7F8F9F9F7F7FBFCFBF9F8F8F8F9F9F9F9F9F9F8F7F8F9F9F9
+F9F9F9F9F8F8F8F8F8F7F6F7F5F4F3F1F0EFEFEEE9E7E5E6E4
+DED5C8BBAD97785E4E433A3435342E29282828292E34394045
+4E627784817670716E6A66615E5D6065686966605A57534C44
+413E3B38342F29262424232323232322222223232425272B2E
+3032323234373A3D41464A4F545A5E605D59544F5058657276.
+483E35313236393B3E4446484B4A4743413E3A37363A40464E
+5A6B7E8C918D86807E7D7A74696161625F5850484445464543
+4346474642392F262223242526262525252629292625272928
+25252B32394B6789A1A59FA2B5C7D6E0E8EFF2F4F7F9F7F6F7
+F9F9F8F8F8F8F9FAFBFAF9F8F8F8F8F9F9F9F8F7F6F7FAFAF8
+F8F9F9F8F8F8F8F9F9F7F6F6F5F4F4F1EFF0F0EFEBE7E5E3DE
+D6CDC4B7A89676554038373837312926282B2D3037404C5965
+6B70716D696B737769636D7D87847B75787E7E77736F645445
+3D3836322D282524232323232524242423232324242526282B
+2C2E313436393F434442403F42484F5558565352555B5F5E59.
+49433D3837393B3E41454344474A49453F3B3736383C3F444A
+50575F697C888884868A887E70625C5E615F554A45494E4B46
+4547453F362F28252324252626262626272828292827272827
+25262C3542577390A6B4C3D7DAD7DAE1EBF3F5F3F5F6F8F7F7
+F8F8F7F8F9F7F6F8FAF9F8F8F9F9F8F8F8F8F9F8F8F8FAFAF9
+F9F8F8F8F8F9F9FAFAF8F7F7F8F7F5F3F0EFEFEEE9E5E0DCD6
+CEC6BEB4A38A6648393A3F403A302B2B2F31343A434D596263
+5D58585A616B7479788295A5A494827C868D847060554B4036
+2F2C2A27252221212222222324252525242424252525252729
+2B2D3034373A4146443E3B3B3D4247494B4B4A4B5055544E47.
+4A4643413F3D3D3E3F424243454645413D3A38373A3C404549
+4C4F5052677B83838383827D7468616164635D544F50534F4B
+4B4B45392D26232425252525262728282727282A2928272727
+282B2F394A627C97B2C6D6E6E8E3E1E6EFF5F6F5F5F6F8F8F8
+F8F8F9F9F9F8F7F7F8F9F8F8F8F8F6F7F8F9F9F9FAFBFBFBFB
+FAF9F8F8F7F9FAFBF9F7F6F7F7F6F5F3F1F0EFEFEAE6DFD9D3
+CEC8C2B79F795846414345413B3335393A3B3F454A4C4F5354
+504E525F7184939BA1ABB3AF9E87746C6E6B5B483B34302D29
+26262523212020212223232324242423242425262726262627
+292C2F32363A3F42413E3C3D3D3D3F41434343474C4C494748.
+4B4A4A494644434140414245484845413F3E3E404140414549
+4E52504B556C838D8B827A76716C67676A6B68615954535251
+514C4134282221232425262627282726272A2B292827272828
+282C3642557190AEC4D1D9E4E6E7E9F0F6F8F7F5F6F9FAF8F8
+F8F9FAF9F7F6F6F7F8F8F7F6F7F8F7F5F8F9FAFAFAFBFBFBFB
+FAFAF9F8F8F8F9FAFAF8F7F7F8F8F6F1EEF1F3F0ECE7E0D8CE
+C4BCB5A68F75615247413E3C3B3E424543403F444848464446
+4D58657892ABB7B7B1A89B876E5B52504E45372C2828272727
+26262523212122242424242323222223252626262627272828
+28292D323537393A3B3C3D3E3E3D3C3D3F414143494F535659.
+504E4C4A474442403E3D3E43494C49433F404042464A4B4948
+4B4F4F4B4A5B768077675D5F6B7575706F757B7A6D61595B5A
+5245372C242122222324252626272728292A2A282726262626
+292E3743577497B7CCD7DDE1DEDEE8F4F9F9F6F5F7F8F8F6F6
+F9FBFAF8F7F5F7F8F9F7F7F8F8F6F5F7F8F9F9F9FAFBFBFBFB
+FBFBFAFAF9F9F9F9F9F8F6F6F7F9F7F4F2F3F3F1EEE9E3DBD4
+CDC6BEAE91796E675C4E4544484A4A463F3A3A3D4244424048
+5B748DA8BBBEB19A83756C6052453B3633302D2B2B28262424
+242525242321212225262625242324242525262626282A2929
+2827282C303235393D3E3F3E3C3B3A3B3C3D3C3D4047546982.
+4F4F4E4C49453F3B38393C43494A4744434444464A4D4E4D4C
+4B4C4B494F5F6F7069635E57515664707A8285847E7770695B
+48382B25232424222223242527272727272828262527292829
+2E353C476284A6C1D2DCE4EAE9EAF0F5F8FAF9F7F6F7F9F9F8
+F9F9F9F8F7F6F7F7F7F7F8F8F7F7F7F9F9F8F9FAFAFAFAFBFB
+FBFBFBFBFBFAF9F8F8F7F6F6F7F7F6F2F0F1F3F0EDE9E3DCD4
+CCC4BDAD91796C63564D4D5255524B433C393B44515C636B83
+9AA7A9A59C8A735A4D4C4B43372F2B2C2E2E2B272525252423
+24242423232222232525252424252526262627282827292B2A
+282728292D31373C3E3F3F3E3D3E3F3E3B3938383B40495A74.
+4E4B4C4D4B453E3837393E45494A494848494A4B4C4C4D4E4C
+49474A4F59646A6A67635A4F46495564717B82848586806C53
+3C2B2220222423222324242526272726272928252527282A2E
+353A3F4C6B8EAABED0E3F1F5F1F2F4F7FAFAF9F9F9F8F9F9F9
+F9F9F9F9F7F6F6F5F5F5F5F6F6F7F7F8F9F9F9FAFAFBFBFCFB
+FBFAFAFAFAFAF8F7F7F8F7F4F5F6F6F4F1F1F2EFEBE7E2DDD6
+CBBFB3A38F806F5C4F4D54595345403F3D404C627B91999A9B
+988E83786A5542383433302D2A2828282A2A26232222232222
+22212121212122232424242526272726262728272727282828
+292827282C343B3E3E3F3D3C3C3D40423F3C3A38383C414853.
+4D4A4B4A47423B393B4146484B4D4D4C4D50514E4B4B4A4746
+4549505960615D5B5C5A534B494E54585E6A778186877F6B4B
+31232123232221212325252626262727282826252627292B30
+363C414B6283A4BED4EBF6F6F4F4F6F8F9F9F9F9FAFAF9F9F7
+F7F7F7F7F6F6F5F4F4F4F5F6F7F7F8F9F9F9FAFBFBFBFCFCFB
+FCFBFBFBFBFAF9F8F8F8F8F6F7F8F6F2F0F3F4F1EEE8E3DDD5
+CBC1B8AC98847469635F5A53493D3A3E47576C8292988E7E72
+6B645A4D41352D2B2929282726252425252421212122222222
+22212020212122222324242426262626272828272727272728
+282726282C313A4244413C3837393D4142413F3C3C3D3F4244.
+4A474443423F3C3D4147494A4D52545353534F4A494B4B4947
+484E565D5E59545355575656595E5E575660707F8682755E40
+2A222325242221202225262626262627282927262728292C30
+353A3E43506D94BFE2F5F8F5F3F6F8F9F8F7F9FBFAFBF9F8F6
+F4F3F3F4F5F5F4F4F3F3F4F5F7F8F9F9F9FAFBFBFBFBFCFCFC
+FCFCFCFCFBFAF9F8F8F7F8F8F8F8F7F4F2F3F2F2EEE8E3DFD8
+D0C9C0B19987827E7364564B433F3E4A5E72818681725E5552
+4D42362C2726282A2726272625232222222222222223232324
+23232121212122222323242526262626272829292726282827
+272828292B2E364044433F3B38373A3F4243423F3E3F434646.
+4B453F3C3D3F404242474A4C4E51555653504B4645494F5150
+4E525856515153565A5F626260605A5155667781858273593D
+2A212124242121212222232424242525262627272728292D31
+37393A3C43536D97CCF2FCF8F5F6F9FBF9F7F7F8FAFBF8F6F7
+F6F3F1F2F4F4F2F2F2F3F4F5F6F6F7F9FBFAFAFBFBFBFBFCFC
+FBFCFBFBFBFBFAF9F8F8F8F8F9FAF9F7F4F3F5F5F1EDE8E5E1
+D8CDC6B79B8D8B8779644E42434E515667767A6E5B4B42403C
+342A2625252525262727262525252424232323232222222223
+23232222222121222223242626262727272829292727282725
+25272828292A2D32393E41403C3A3A3B3D3F41414041464C50.
+463F3C3B3D404244464B4E4D4D4F54565554504C4C51565653
+50525555535355585C5D5C5E63635E5F6B7B86867E72614630
+2521212222232323232222232424252727262626272A2D3136
+3B3D3E414347557AB2E2F9F9F2F3F8FAFAF8F6F5F9FBF9F8F6
+F6F5F4F4F3F1EEEFF1F3F4F5F7F9FAF9FAFBFBFBFBFCFCFCFD
+FDFCFCFCFBFBFAF9F9FAFAF9F9F8F8F6F4F4F6F5F1EDEAE7DF
+D3C6B8A799938B79614B4145546972706B6052453C36312C29
+27262524242323242628292827282826252524222121212121
+21222324232222222222232425252627272727272726262728
+272625282A2B2A2D353C3F3E3D3D3D3D3D3D3E3F3F4144494C.
+423D3D3E42444342454B51514E4D50555A59524E5055585957
+585E63635F5E5E5C5A5B5F656A70777E8384817A6E5B432F25
+2223232323242524232223242425252525252527292C303338
+3C404241404149608CC2ECFBF7F3F3F6F8F9F7F7FAFCFBF9F7
+F5F5F4F2F0EEEEF0F3F4F4F6F9FAF9FAFBFBFBFBFBFBFBFCFC
+FCFCFCFBFBFBFBFAFAFAFAFAFAF9F8F5F3F4F3F2F0EFECE9DF
+CCB8A69E978C78614E474D59605C56534D453D362E28262426
+262524232324272A2C2B2A2825252626252524232221202021
+22222121212121212223222323242527282928262627272827
+252526272828282B31393F4243424444413F3F3F3F3F3F4143.
+49464445494B4947474A4D4E5254565A5F615A55555B626666
+66696E6F6F6C6A6B717C868C8D8D8C877F766F6758442E2322
+24242322222325242323232425252626262526282C2E31363B
+3E4042414141424B638DBDE4F3F4F0EFF3F8F9F8F8FAFCF9F7
+F5F4F2F1EFEDEFF1F3F3F5F7F9FAF9FBFBFBFBFCFCFCFCFCFC
+FDFDFCFCFCFBFBFBFBFAF9F8F9F9F8F6F3F2F2F2F0EFEDE7DA
+C6AE9B91897B6A5B524E515552433A393B3831292423242323
+2324242527292A2B2928272525252525252525232221202021
+21222222212121212122232322232426282827252626262726
+25252628272626292F353C4245474748494744413F3E3F3F40.
+51525151504E4B494D52565A61676F74736E6863656D757A79
+797E848889888A91999D9B989C9A8E7C6A5C5248392B232122
+242424232323222121222425252626262625272B303334383D
+3F42444444424348556A88AED2E8EFEFEFF2F8F9F9F9F9F8F6
+F5F3F0EDEBEDF1F4F5F7F8F8F8F9FAFAFAFBFBFCFCFCFCFDFD
+FDFDFCFCFCFBFBFBFBFAF8F7F7F6F4F2F1F1F1F2EFE9E4DAC8
+B09781726A655F574F4945423D342D2B2A2926232222212022
+23252728282726242425252525242423232323232322212020
+20222322222120212122232322232425262726242425252525
+242526272727282A2F363E4345464749484848454242444444.
+54565758575555575F666C71767B7F807C776E686C72777A7D
+82858586898C91969B998D7F7971696056493A2E2624232424
+252524232322221F20232627272625262727262B32383A3B3D
+4145494C4B4A4B4D515863738DADCADDE8EFF2F4F5F5F6F6F5
+F2EDE8E5E7EEF4F5F5F7F9FAFAFAFBF9FAFBFBFCFCFCFCFDFD
+FCFCFCFBFBFBFBFCFBFAF8F7F6F6F5F4F2F0EFEFEBE0D2C2AB
+8D7365636461594E423A36332F292624242321202020211F23
+2728272524222122232424242424232323232322222221201F
+20232323232220202223232222232323252626262525242424
+242527282827282C30363E4850514B4646494A49494A4C4B47.
+5C5D5F62625F5D5C64707B7D787371726E665F606263636569
+6E6E6D707677757474736D645C56535046392C242324242425
+25242221212223212124282B2A2826252626272B3135383B40
+44484C52545453504E545E626267768EB0D3E9EFEEEEEFF1F2
+EDE4DCDEE6EFF5F7F6F7F8FAFBFAFAF9F9FBFCFCFCFBFCFBFB
+FCFCFCFDFDFCFCFCFBFBF9F7F5F5F6F5F3EFECEAE0D0BEA68C
+73625E5E5A534D453A312A282728252120201F1F2021202325
+26262525242222212325252424242424242422222121212120
+20212424232120202224232323232324242526262625242525
+25252628292B2A2C2F343A48575B51443F454C4E4D4C4E4F4D.
+5F5D5F6264656262636C7374716E6A67625956575A5B595A5F
+636361656968625E5E605E564D4B4E483D3025202125242525
+2322202021232222222326292A2925242424272C3235363940
+474A4B4D51534F4B4D566068665F544F577093B5CEDCE5E8E9
+E6D8C7C7DCF1F6F4F4F7FAFBFBFBFBFBFBFBFCFCFCFCFCFCFC
+FCFCFCFBFBFBFBFBFBFAF7F5F4F4F3F2F0EEE8E4D7C3A28166
+595A646552413C3B37312C282523232120201F202021202424
+23222122222322212224252424232323252623212020212121
+21202022222222222222232323232323222325272726242323
+2425252627292A2A2D32383F4851554C41414A535756514B46.
+6A65616263666A6D6C6B68676563615F5B5654586062605C59
+585A5D5F5B5654545452504D4845453B2D2522232424242425
+242321212021222324252728282623222223272E3335373B41
+4645464B54565148464D5963615B544D494E5A697D98B4C5CA
+C6BBB6C5DFF1F5F3F2F5FAFDFDFDFCFCFBFBFCFCFCFCFCFDFD
+FCFCFBFBFAFAF9F9F7F7F7F3F1F0F0F0F0E8D9C7AD8E6E5851
+51514F4C46413D38312C292523212121212121212222212221
+21222222222121212324252524242524242523222020212121
+20212122212121222324242423222121222527292824222425
+2626262526282B2D3136393D444E534E464851595C5A54504B.
+6860585960696E706B635F6061615F5A534F51586266635B54
+50525657524F4F514F4B49494740362A232224242424252525
+242321201F202326272727272625232222242B3235383B3F43
+4A4B494B50504A4342464E5553514D4D50525152585F676E77
+808A98AEC4D5E6F0F3F3F5FAFDFCFCFCFCFCFDFDFDFCFCFCFC
+FCFCFBFAF9F9F9F8F5F3F2F0EEEDECEEEEE0C2A28266524B4A
+474140454A483F332A26252423222324232221202020212122
+232323222020202326282A2724232424252524232221212121
+21222222222121222324242424232322232426272826232426
+262627262628292B2D3033373D4753544E4C50565A5A585450.
+685D5659646F736E655B5556595B5A554F4D505B676B675E54
+4D4C5254524F4D4C4A49484641382D25222425242323242423
+2321202022232426272726252423232223272E34373B3E4043
+4B4F4D4844444544434447494B4D4B4D515657585655524A49
+4E5864738399B8D4E4E9EBF0F6F8F8F9FAFBFBFBFAFAFBFCFD
+FDFCFBF9F8F9F8F5F3F4F2F0EBE8E8ECE9CB96736459504943
+3E3E49545243342A2625262626262624222120202121232424
+2525242221202225272A2B2825242323242525242424242221
+20212223232322222323242423232323232425272826242526
+262626262627292B2B2B2D3138435158575351545758575352.
+6459565D6973756D5F524B4D5458544B464A54606967615A53
+4E4E5356524F4B49474645443C2F2623242526252424232222
+23222121222326272827252424242424272D34393C3D3E4046
+4E555650453F4042434546434142464C545C5E5B58544C433F
+42474B4E5663718293A0B3CBDEE5E6E7EAEDF0F2F5F8F9FCFD
+FDFBF8F4F3F4F4F3F1F1EEEAE6DED2C3AC89645150504A4341
+454A4C463A3029252526272828262422211F1F212222232526
+2728262322222326292B2A2825242525262727242527262320
+21212223232222222324232323232222222326272827232425
+2628282725272A2C2A2B2C2F353F495153504D50565754504F.
+6056555C6872746B5C514D4F5353504C48484F5C63625C5550
+4D4F5457544F4A48484A4A4131242123252727272524232424
+242423222223252626262625242323252830353C434645464C
+535859544A3F3B3E454D4B3F383C464E53565A5A5249454549
+4C4C4B4C4D4D4A4F59636D7784919EACB7BCC4D1DFE8EBEBEC
+EFF1F1EDEBEDEFF0EEE8E5D9C8B5A38F775E51515149434449
+483F342D2B2B29292B2C2C2925202020202020212222232425
+26272726252425282C2A282625252526272625252627262321
+20202122222223232424242424222221222325262728262526
+2727262627282A292A2B2E31363B3E41474A50555857524B44.
+655C55545B6773776B59505051504D4B4B4B4E545A5D5B5652
+4F4E50514F4B48464749473C2E232123242526272523212224
+252322212123252626262626242222242B32363D444949484C
+5252514E4B433D3D41413C3942494B49494B4B4745454B5051
+4F505356585A534F4F51514F4F555F686F75787F8A959DA6B0
+B9BFC8CECDCACDD3D1CDBFAD9B866E594E4E4F494344454139
+312D2D2F3032322F2A2726252422201E1E20201F1F21252426
+28262424262829292B2B282525262625272727242222222221
+21212121212222232324252424232222222325262727272727
+26262626262727282A2B2C2E3134383C3D3F454D5355524C44.
+635C5755545760696E6E6A635A5350505151525252555A5E5E
+595552525151514F4D49433A31272223242425262523212223
+24232222242627272524242424232325282F363D414446494E
+504E4D4B4744403A393A3A36373E434445484944403E40454C
+54585856575D5E5A595654535253535152545555565B61686E
+6D6B707D85837E80898E87796D63564B474A4944454A463C30
+2B2D333A3F3F3830292423242322211F1F2020201F20222225
+272726242426292A2A2B2A2826262626272A29262324242423
+212021232222232324242525242423232222232527282A2928
+27262626262626262829292A2C2F33383B3C3D3E41454A4C49.
+5C5754545455575A616B72716A64605D5A57565556585A5C5C
+5B5A59565250525350483C3029252425252423232221202122
+2322222325262727242323222324262A2E32373D414243484C
+4C4844444442403C39353235393D3E40424544403D3E41464C
+52565756565759595A5B5A5755545353545454535354585C5C
+534D4D53595B5C5C5C5D5C58524D4C4C4D4F504E453B322D2E
+3238404541362B25232222211F1E1F20201F1F20201F212527
+2827252425282B2D2C2B282626272726272A28242425252422
+20202224232323232324252525252322212123252828272626
+2625252526272727272828292A2E33383A3B3B3C3E40424141.
+595250555B5D5D5C5E656B6A66656668686667696A6B6A6762
+5E5E5F5D575352514C42352C2524252525252423211F202221
+2121212224262524232222232527292D30363D424241424444
+413E4146453F3935323030373A3B3B3D41433F3A3C434A5254
+515054565554555757555453575C5C59534F4E4F5253555758
+504B4B4F54585958565652494547494D555E5D4A3429282E36
+3C40433C2F2420212322201F1F1F201F202120202121222527
+282626282A2B2D302E28262628272524262827232426262422
+21202122232323242425252425252423232324262729272524
+2525252526262727272728292A2D3136393A3A3C3F42444240.
+5C5451565D646767656668676463656768696A6A6E74787670
+6B6B6E717273716A5D4C3A2C23222223232424222120202020
+21202021232525242221212325272A2D31383D3E3D3D3F403F
+3C3A3E46484138302C2C323C40403D3C3C3C3A373C454B5152
+4F525B5C544E4F4F4D4D505559595A5B5A5653515050525859
+524A474A5155555355554F464140434D5A5A463027292D3339
+3D3C352C2621202121212120201F1E20202021212222232527
+272727292B2E30302A27272929262323252727252526262422
+21212123242424242424242525242424242424262729292626
+26262625252526262627282A2B2B2C30363A3B3B3D42474745.
+5B585A6065676869676767676766646364676B6D6D72777774
+727581909FA4A39B8361422C24222424252524211F1D1E2121
+2020212222232321212122232527292D31393C3C3C3D3F4140
+3C3B3E41403B332D2C2F353B45463F3632333537414B505455
+55535050576459463D4551534F48474B52555554524F4F4F4C
+4C494644474A4C4E524F443C3940515D563F2B23272E333637
+332C282522222121212121201F1D1F20212020202122252829
+2726282A2E32332C2525282B2A272423262826242426272623
+2220212325252525262626262525242423232325282B2A2826
+242424242527272727272828292A2D30373B3E3F4144454443.
+505052575E6264656B70706D6A696868686865646A7174726D
+6A6C737B7F807F78644A342823232424232221202020202221
+212121222222211F1F21222223262B31353B41423F3B38383A
+3D403F3B37302B2A2E353D4243403B35302F323A45494C4F50
+515455524F4A42404348494B4E4E4846474B4C4946484A4B4A
+4A47484A4B4E514E433C3C424B4F4A3F332926282D3132302B
+262422222121212020201F1F1F1F1F20212120212225292A28
+26272A2E33362E2422272B2C2A262425272624252525242322
+23232424232425292C2C272425252525242425272929262526
+2625252424252627282626292B2C2E34404341404141414142.
+4E4A4B4F555B5D60666B6A676667696C6C676363676B6C6C6C
+6C6A6C737C807E76634A342926262624222120202122212121
+21212121222222201F20212121232930363A3D3F3F39343336
+3A3D3F3D38312B292B2F3437383837322F3033363C42464A4B
+4D525A5D54484242464848484B4C46444A4E4B434043464646
+46413F3D3D4145453E373E4B514A3E352F2A292C2E2E2C2A27
+242323212020212121201F1E1E1F2021202122232326292A28
+2626292C2F302C2423272B2D2B282525282927252526262627
+292A29282525272A2E2F2B2525262626262525262829272627
+27262525252525262626272828292B303A4346454544434141.
+4C4746484C4F51555A616361616160606163656666686A6B69
+666361666B6F7370624C362A28282623222222222221202021
+2122222222222221201F21212122262D3537393C3D39343032
+373D3F3D37302A2B2F3131313031322F2B2A2D343A4144474B
+4F5254585D55484244484B49474747474B4E4C45403F404140
+403F3F3B37383C3D3A3A4345413C3632302F2F31302D292726
+262423211F1F202221201F1F1F1F1F20202123242425272927
+2627292D302F292323272B2C2C2A262527282927282B2F3335
+3430292627292B2D2E2D2B2929272526262626282A2A2A2927
+26262626262626252526262627282929323F484A4947444547.
+4746484A4947484B4E52565C5F605F5D5B5D61625F5C5D5E5A
+555252535353534E4335292424242422212121212121202122
+22232222212121212121201F20242931373A3B3A37322E2F35
+3C403B352E2A292E33333231312E2B292A2D3239424747454B
+52524D4E5351494344484A494A4D4D4B4C4C484341403E3D3E
+3E3C37313033373A3C3D3E383233383A37312D2C2A29272524
+252422201F202020201F1F20201D1F212323232425272A2924
+24282C2E2D2A2522252A2F2F2C28262729282B323D413E3832
+2E2B26262A2D30312F2B28292C292626272828282929282828
+27252526272626262627272727282A2C35434D4E4B494B4D4C.
+46434445464748494A4F52545456595A5A585555524F4E4E4D
+4A4948494A4A49453A2E252225252624222120202021202121
+21212121201F20212020202021252A3036393935312D2C2E33
+393B38322C28282E3333312F2F2E2B28292E353A3E44484447
+50524B464A4F4A4340464A4845484E4F4B433D3C404546433E
+3D3934312F2F33383C3C373132383E3F362C26282926252424
+24232220202020202020212120202021232424242527282824
+24272B2B28252527292C2F302C28282B2F3139464F4B3C2D27
+272828282B2E30302D29292A2E2C2927262627272728272625
+2525252627262526272829282728292A2F3C4D55534F4E4F4C.
+464140414346494B4B4F514F4A4A4D5052524D4A4A49474749
+4948494B4E4E4B44392D2420232625242322211F20221F2022
+21201F1F2021232120201F202124272D343635332F2A292C2F
+323533302C2B2C2E3132302C29292726282E3335353941403F
+444C4C45404042434246484540414648443F3A373B4449463E
+37312F2F32333335373734363A3E3930282627272725242222
+24252422211F1F202222212122232322212224252627272624
+24252828252325282D2E32322D2829303D494D4E493C2D2322
+2627292C2D2D2D2D2C2B29282A2C2B2A272527282724272828
+262526272727262626272727282927282D3343505454575B57.
+4841404446484948494C4C4B4A4A4B4D4F4E4B4A484543464A
+4B4B4E51504B4742372B212024262321201F1F20201E1F2021
+1F1F1F20202024242120202023272B32363734302C29292C2F
+2F2E2A292A2D303232302E2B29282727292D303435373C4044
+474947423F43464847444241403E3D3C3A3C3835373D3E3B35
+302F3031343636343134373B37302927282725242525252524
+2322211F202020202121202122232324242426282927232325
+272728262424282C2F3132302D2E343E4B4E4338322D292729
+2C2D2D3032302D2C2D2D2B29282A2A2A292727262626272728
+26262727272727262526282929292A2C2E36424D5457595B57.
+443E3F424243434343454748494A4B4B484543434444454749
+4B4D4E4F4E49443C3126202124242322201E1E1F1F1F1F2020
+1E1E1F20212122222021222324282F3538352F2B2A2A2B2D2D
+2B2827282C2E3032312E2A282A292826282D313438393D4145
+4848474443434348463F3C3E3F3E3935363836323335363635
+3131343736312F30343B372E27262727272525262625242323
+22212020202120212121212123242525252729282522222426
+2826232325282D3032333232343A424642362F2E3133322E2B
+2B2B2C2D2D2D2D2D2F2F2C2A292A2B29272626262525252526
+26272829282727272627282929292B2D303A48565E60605D5B.
+493F3B3B3E4142424142464A4C4A4745424140404346474747
+4A4D4D4B4A494742392E25202224242422201E1E1F201F1E1E
+1F20201F202122202020212122252A303637342F2A28292C2E
+2D2825272A2C2D2E302E2A27292A292727292C31383D3F3F3F
+3F40434645413E3F3F3C393B41413A34343635312F31343331
+31333839342D2B2E33342F2823242627282725242424232322
+2120202020201F202222222223242526262728282623232326
+2827242223272C31323434373C3F403D39322F30343838342D
+2827282A2A292A2D3132302E2C2A2A29282727262525242424
+25262829292626262727272727282A2A2B303A47545E626364.
+4D423B3C3F4344434140434A4D4B45403E4144444749494849
+4C4D4B4B49484A494133251E2025242322212020201F1F1E1E
+1F201F1F2021211E1E1F20202022272E343533302B28292D31
+2E28252527292B2C2E302C27282B2A2A292A2B3037403C3635
+363A404748403A3C3E3C37373B3B342F3031312E2F3335322E
+31393E3B322A282D32302A2625262727282723222323222222
+2120202121201F1F2022222222222425252628282622222226
+2828252223272D323331323A43433B363536383B3B3733302D
+2B2826272A2C2C2D2E2E2E2E2C2A2827272727262525232222
+24272828272727272727262727282827282B2F384552595B5A.
+433D3D3F42434545423F3F42434240424548494948484A4C4D
+4D4E4F4F4D47423A30251F202322212120212121201E1E1F1F
+1F1F1F1F1F1F1F1F1F20202023292F3332302C2B29282A2C2B
+2824242628292B2E2F2D29282A2A2A2A2B2C2F343B3A343132
+373E45473F3534353534343432302E2F2E2C2C2E3133313032
+3636332F2C2B2D2D2C28252526272827252423212020202020
+202021201F1E1F212222232221232526262727252223242527
+26242325293033302F2E3236363434373B41403A312B2A2D2D
+2A28292C2F302D2A292B2B2B2A282725262625242323212224
+272928272729292625262728282727292A2B3039434C4F4E4F.
+4C433E3F4345454444444442403F40414446474849494B4D4C
+4A4A4845403D3830282421202021222322212121201E1E1F1F
+20201F1F201F1D1D2021202023282D32322C2B2B2A29292A29
+25222426282A2C2D2D2B2928282828292A2B2E323737363131
+33363B403B322E2E31333332312E30312C292B2F3031323333
+33302D2D2F302F2A272526272728272524242422201F202121
+20202121201F1F212323222222242627282623222323232424
+22222122273035332E2D31333232373F45453D322B292E3333
+2E2A2E2E2E2F302F2C28292929292726242323222222222425
+2829292827272929262526272726272828282A2F343A3F4244.
+584C44424446494C505253504C484644434446494D4D4E4F4E
+4A4545443D342C272524232221202021222221201F1F1F1F1E
+1F1F1F201F1E1E20201F202122242A2F31302D2927272A2C2B
+2724222426292B2D2D2C2A292929282727292D323432322F2E
+313436363632303233323333322F2E2F2D2C2B2C2E30333330
+2F2F2F2E2D2D2D2B2927262829282626262523232222212120
+20202121201F1F202120202123232425252624222120212224
+23232223272C32323130303133353C4549443A332F2F323738
+342F30353937312D2928292927252625242323222222222223
+25282A292827272727262627272727272828292C2F3438393B.
+574F4F52555757585A5A5A55504D4D4D4A4B4E515353514E49
+44413E382F2926262524211F1F2021212122211F1F1F201E1D
+1E1F1F1F1F1E1E1F1F1F202122262C2E2E2D2B2827282A2A28
+25242627282A2C2C2B292828282827272A2D303131302F2D2D
+30323333302F3132313133322F2D2D2E2C2B2B2C2E3032312E
+2D2E2E2E2D2B2A292A29282726252525242322212020202122
+21202020202020212221212122222223242221212021212223
+2424262A2D2F2F30313233363D4347463F3733323336393A39
+3531333636312B282627292624222222232323232222222324
+2627292929272828282828282827272828282A2E3236383839.
+57575E66696967666666635D59585959545153575A5D5A534B
+433D352D2726262624212020202121202020201F201F1E1E1E
+1E1E1F20201E1D1F2020202124282D2F2C292725272A2A2724
+242527282A2C2B2A28262628282625282B2E2F2F2D2A29292B
+2D2E30312E2C2F2E2F30312F2D2C2D2C2B2B2C2F31312E2C2D
+2E2E2F2E2C2A2A2C2D29262424242424242222212120202121
+2120202020212121222121202122232322201F1F20211F1F22
+242429303434302E3134363C4548453D3734333435383A3935
+312F2E302F2B28242324242321212121212222222222232425
+26282A2928292928282929272627282827292C2F34393C3C3D.
+5F595A61676866666A6F706D6966656667646062676A696560
+5A51463A302B2A2B292622202122212121201E1E1E1E1E1E1E
+1E1D1E1E1F1E1D1E1F20201F2124292C2D2B28262527282726
+23232426292B2B2B2927262828272526282A2C2D2D2C2A2827
+282B2D2E302F2B2B2C2D2E2E2D2D2D2D2B2A2B2D3133302C2C
+2C2B2C2D2C2C2C2D2D29252223232324242323232220202122
+2222212121202021212121202022222323211F1E1F20201E20
+212324282F3434303032363A3E4142413D3935343638393834
+2E2A2A2B2E2E2C272321212021212021212222212122222324
+25262728292A282829292827262627282827292C2F343A3F42.
+645B58595D61636666696A676362626365696C7075746F6D71
+736B573F35343430292320202220202120201E1D1E1F1F1E1E
+1F1F1F1F1E1D1D1E1F1F20202021272C2C2926232324262725
+23232426292B2B2B292726272726252425282B2C2A2B2A2827
+292A2A2C2E2C2B2B29292C2D2D2B2B29292B2D3031302C2929
+2A2B2C2C2C2C2B292624232323232323232322212121212222
+2323232121212121222322211F20232221201F1F1F1F1F1F1F
+202122272E32322E3035393C3C3B3C3C3B393535393B393531
+2D2A2B2B2B2A27232020202020212222222221212222222223
+24252628292927282A28262627282827292A2A2B2F343B4347.
+605A5C62696C6A656161606060605F5F636A7077756E6B6E6F
+695A463936302B25211F1F21211E1E1F201F1D1B1C1D1E1F1F
+1F1E1E1D1C1D1F20212020222325292A272423222324252423
+232326282B2B2A272425272825222224262828272727282929
+292A2C2D2C29282626292B2A282829292C31312D292727282B
+2C2D2E2D2A26242324222122232323232423211F1F21222121
+21222221212121222221202021242221201E1E1F1F1F1D1E1F
+22282D30302E2D3035383A39393A3B3A36323334343333322F
+2E2C29262321201F1F20211E1F212221212121212222222223
+242426282929272A2B282728292827282B292A2C313A454B49.
+6A64646B7276746F6B6B6867676765646465697177726A6667
+6761504038302822201F1E1F201F1D1E1F1F1E1D1D1F1E1E1E
+1F1F1F1E1D1E1F1F1F2021202124282A292725252525252423
+232426272A2B2B282524252524232424262727252526272929
+292A2A2A2B2A282625282A2927272A2B2B2D2D2B292725272A
+2E31322D272424262524222121222324232221212121222322
+21212122222121222221202123252422211F1E1F201F1D1E21
+252930322F2B2C2F32383A3B3B3B393834323435322F2E2E2F
+2E2A2320212121202020212020202121212122222323232323
+232426282A2A2A2B2B29272626282827282B2B2C2F35404B52.
+79716E737A7F7F7A76757472706F6E6B6A6C727A7E7A726B68
+67625544382F26211F1F1F1F1E1D1D1D1E1E1D1D1E1E1D1D1E
+1F1F1F1D1C1D1F1F1F1E1F2122232628282524252424242424
+24252626272929262322232424242323242526262625252728
+2929282829282827262728272627292C2D2D2B28262627282A
+2F31302A25242424242423222222242423211F1F2223222222
+212021212120202121202020212222222221201F1E1E1E1E20
+24282F33312D2C2E303334373A3A3736353333333232312F2C
+29242120202020202020202120212120202122212223232323
+232325282B2E2D2C2C2A28262527282828292B2B2D31394653.
+7A73747B82837F7D7B7B7A797774716E6F757C807F7A736C65
+5D5344342A24201F1F1F1E1E1D1C1B1C1D1E1E1E1F1F1E1F1E
+1E1E1D1D1D1D1F1F1F1F202123252728272524242424242525
+25262525282926232122232423222324252525252526272728
+292A2928272726262626262727292B2D2B29272626272A2E2F
+2E2B282626262524242322222323232221201F212223222222
+2121201F1F1F20201E1E1F202120202021201F1E1F1F202122
+272E3232302F3031303033383C3D39343030333333322F2A25
+21202122212020202020202121212121212122232323232323
+2425272B2D2E2C2B2A2928262627282828292A2B2E343E4953.
+746C6C737C7F7F7D7A7B7E7E7C7A7877787B7D7B7A78756F67
+5A4B382A211F1F1F1E1C1D1E1D1D1C1C1C1D1F1F1F1E1F2020
+1D1C1D1E1E1F1F1F1F20212122252626262523232324242324
+25252526272724212022242423212225262524242426272727
+292928262525242424242526292C2C2B28252526282B2E302D
+27252526262625252524242323222121202020212222212121
+202020201E1E20201E1D1F21201E1F20201F1D1E1F1F212325
+2A3032302F3033323131353C413F39322E2E3131302C282420
+1F202221201F1F1F2020201E1F212221212122222323232324
+2526282B2D2C2C2C2A2927262627272829282A2B2E34404E56.
+776C65646B767C7C7D7F807F7B777473737475747677756F6B
+69635236231C1D1F201E1C1C1E1D1D1D1D1D1E1E1E1D1C1D1F
+1F1E1D1D1C1D1E201F1E1F2122232527272625232324242524
+24242424252626242120202223232222252625242423252728
+29282727272523232223242425282A2B2726272727292E302C
+25242525252525252626242425242221202020222322222121
+21202020202020201F1F2021221F1F2122201E1E1F1F202223
+272A2E30302E2C2D2E3033383D3F3C36312E2E30302C272322
+212020202121201F1E1F20211E1F2224232221212223232324
+24242526292B2D2E2C2B2927272627282826282A2B2C313A47.
+746861646F777877757679797875716F707376767878737072
+706245281C1B1E21201D1C1D1D1D1D1D1D1D1D1E1D1D1D1E1F
+1F1E1E1F1E1D1D1F1F20212021232627272624222323232323
+23232424252524222120222423232223242425242323242729
+28262627272524232323242426282A29262527292A2C2E2B27
+25262625252526262626252525242321201F1F202221212221
+20202122211F1F1F2020201F21221F1F20211F1E1F20202128
+2D2E3032322F2E31312E3035393A38343132312E2A27242221
+2020212322211F1F2021211F20222122232222222323222323
+24242426292B2D2E2E2C2A2828272627282928292B2C2F3745.
+6C6563676C6F6E6C6A67686B6E70747A7E7F7D746E6D707069
+54331D181E21211E1C1B1C1C1D1C1D1D1D1E1E1D1C1C1D1E1E
+1D1D1D1D1D1D1E1F2021202022242525242321212223232323
+24232526252321202021222122222323242423232223262727
+26252627262524242424252627282725262829292929272525
+25242424252526262524252523212020202020202121202020
+2020201E1E1F2020202121201F1F1F201E1E1E1E1F2023282B
+2B2E323432302F2E2D30333535353433332E28252323232222
+22212121212020202020202021212121212222222323232424
+242526272A2C2C2C2B2928282829282727292B2A2A2D333F50.
+69636061656B6F6F686161666C6F72777B79736C69676A6B62
+4B2E1B181D20211E1C1C1C1C1C1B1B1B1D1E1E1E1D1D1D1D1E
+1D1D1C1C1C1D1F1F201F1E1F20222323242423222121222324
+24242426262321202020212121212222232322222223242525
+26262625252423222223242527282725252729292726252524
+24232425252625252525252422212120212121202020202121
+2121201F1E1E1F2121212120201F1E1F201E1D1D1F2124272A
+292B2F3131302E2D2E30333333313030302D27242323242424
+2322212020201F1F20201F1F20201F20212121232424242424
+24252628292A2B2C2B2A2A29282828282828292A2A2B2D3645.
+6B65616063686C6D675E5E656D6F6F6F6F6D6863646668675A
+41271A1A1E201F1D1D1E1D1D1B1B1A1B1D1E1E1E1D1C1C1D1E
+1D1C1B1B1C1C1E1F1F1E1E1F1F202224242423222020212222
+22232426262421201F20222020222222232322212121222425
+25252525242221222223242627272525262829282523242424
+24242525252625252525242221212020202020212120202021
+21201F20201F1F202221201F1F1F1F201F1D1D1E2021242829
+292B2E31312F2C2D2F313332302D2C2D2E2C25212122232322
+21201F2021201F2020201F1F1F201F20212121242626242323
+232425272829292B2C2B2A2928282829282828292A2A2B303A.
+645E5D606262605E5C5C636A6C69696B696157545659564B38
+251C1C1F201E1D1D1E1E1D1C1C1C1D1E1E1D1D1D1D1C1C1D1C
+1C1C1C1C1C1D1E1E1E1F1E1E1F222423232221202021222121
+2224252625221F1F2020202021212123232221212122232425
+26252423222122232325262726262625272827242323232324
+25252625252525262523222121212222222120202021212121
+201F2021202022222221201F1F201F1D1D1E1F21232526282A
+2C3133302C292A2E2F32312D2A292A2A282523201F2021201F
+1F202120202021202020211F1F212020212122232424222324
+24242627292A2A2B2B2B2A2928272729292828292A2B2E343F.
+535151505153555353545862676867645F574F4D4D483F3226
+1E1D1F1F1E1D1D1D1E1E1D1C1C1D1F1F1F1E1D1D1D1E1E1D1C
+1B1B1B1B1D1E1E1E1E1E1F1F20222424252523212021212222
+21222425242220202020202020212224242321212022242525
+25252525242424242526262626262726272826232223242425
+27272624242424252524222121222324222120202020212221
+201F20211F2022212020201F1E1F1F1D1D1E2023252526272A
+30322F2A28282A2B2B2D2C2A272626272724201E1D1E20201E
+1D1F21211F202120202123201F1F2021202021212222222223
+252525272829292A2A292929292928272728292828292C3139.
+4A46413E3C3C3F4346454647494C4D4E4F4F4B453F3B373029
+231F1E1C1D1D1D1C1C1B1B1B1C1D1D1E1E1E1D1E1F1F1E1E1D
+1C1C1B1B1B1C1D1D1D1D1D1E1F202021212324232222222221
+212121232321201F2021211F20212020212222222121222424
+24242424232323232324242425252525252525242323232425
+25262625252424242525232221202121222221212121212020
+20201F1F1F1F20201F1F201F1E1F1F1E1D1D1E212525232324
+2931312D272527292A29292A29262322232322211E1D1E1F20
+1E1D20211F1F2021212022222121201F1F2022211F20222122
+232425252627282929282829292A2A29282828282829292A2C.
+3F37343436383A3C3D3E3F3C3C3E3F4040403D362F2C292723
+1F1D1D1E1F1D1D1C1C1C1C1C1D1E1E1E1E1E1E1F1F1F1E1E1F
+1E1D1C1C1C1D1E1E1D1D1E1F1F212221212221212121212121
+212223242422201F2021211F1F20201F2021211F2023232425
+23232323222223232424242424252525262625242324252627
+28282524252525242422212121222221212020212121202021
+201E1E1E1E1F20201F1E1F1F1F1E1D1C1C1E21232524252627
+2828272727272728292828282623201F1F1F1F1F1E1E1F201F
+1E1F21211F1F1F202020212322212020202121212020212223
+2425262727262728292727282928282828282929292A2A2B2D.
+373031353738393938393A39373536373735302C282523201D
+1C1D1D1E1D1C1C1C1C1C1C1D1D1D1D1D1D1D1D1F1F1E1C1E1E
+1D1D1C1C1C1D1D1D1D1D1F1F1F202120202121212120202020
+2123232321202021211F1F1F201F1E1F1F1F1F1F2023232323
+22222223232323242424232323242526262524242525262627
+272623232424232322212121222221212120202121201F2020
+1F1E1D1D1E20201E1D1E1F1E1D1D1C1C1D1F22242425262626
+262525262727272727262524221F1E1E1F1F1E1E1E1E1F1F1F
+1F2020201F1E1E1F2020202121212121212120202021222324
+252527282826272829282726272828272728292828282B2D2E.
+3B322F32373A3A39393A3A393835343435332F292521201F1E
+1D1C1D1D1D1C1C1C1C1C1C1C1D1C1C1B1B1C1D1D1E1E1E1D1D
+1D1C1C1C1C1D1D1D1D1C1D1E1F1F1F20201F1F202120202021
+21232422201F1F2021201E1E1F1F1E1E1F1E1E1F2021212223
+22222222222223232323232323242525252524242627282724
+24252424242423232322222122212121212020202121202020
+1F1E1F1E1F1F1E1D1D1D1E1E1D1D1D1D1D1E20222425262625
+242423242627272625252423211F1E1F1F1F1E1F1F1E1E1E1F
+20201F1F1F1F1E1E1F20202021222121212121212122222223
+24252525262727282927262627272727272728282726282A2C.
+3A332F313538383737343230302F2E2E2E2E2A26222020201F
+1D1C1D1D1C1C1C1B1B1B1C1C1C1D1C1B1B1C1D1E1F201F1C1D
+1D1D1D1D1E1E1D1D1D1D1D1D1D1E1F1F1F1F1F1F2021202020
+212021221F1E1F201F1E1F1F1F1D1E1E1F201F1E1F22232222
+22222122232222232222212223242524242323242627272525
+24242424242424242322212021222121212222222222222120
+1F1E1E1F1F1D1D1E1E1E1E1D1D1C1D1D1E1F21222325272524
+232323252627272523232221201F1E1E20201E1D1E1E1E1E1F
+1F20201E1E1F201F1F1F20211F202120212122222222232323
+2424252527272727282725252627272627272727272727292A.
+37333538393836353635322E2A2A2A2A282623211F1F1E1E1D
+1C1C1C1C1C1B1B1B1B1C1C1C1C1C1C1C1C1D1D1E1E1D1D1D1D
+1D1D1D1E1F1F1D1D1C1C1C1D1E1F201F1C1D1F20201F1E1F20
+2120201F1F20201F1D1D1F1F1E1E1E1E1E1E1E1F20211F2021
+21202223232222222121222425262524242425252525252423
+232323232323222121222322222323232221202121201F1F1F
+1F1F1E1D1D1E1F1F1E1D1C1B1B1B1E1F202221212324242424
+232323242626252422211F1E1F1F201F1D1D1F1F1E1D1D1E1F
+1F1F201F1D1E2021201F202120212121212223222121222323
+24242527282825252726252525252626262626272727292B2D.
+3531323537363738383633302C292A2A272320201F1E1D1D1C
+1C1C1C1C1C1B1B1B1B1B1C1D1E1E1D1D1D1D1D1E1F1E1E1E1E
+1E1D1D1D1D1D1E1E1D1D1C1C1C1D1F1F1E1D1D1D1D1F201F1E
+1E20201E1E1F1F1F1F1F1E1E1E1E1D1D1D1D1E1F1F20212020
+21212122232322212021232425252525252524232323242424
+2424232221212121212223232222222222222122232321201F
+1D1D1D1D1D1D1E1E1C1B1B1A1B1D1E1F212121222324242424
+232323242526252422201E1E1F1F1F1F1F1F1E1E1D1D1D1E1E
+1E1E1E1E1E1F1F20201F20211F202221202121222223242424
+24252627282725262626262626252525252627272728292B2B.
+413A323032353637373634312E2B2A282523211F1D1D1D1D1D
+1C1C1B1B1B1B1B1C1C1C1C1D1D1D1E1F1F1D1C1D1E1E1E1D1D
+1D1D1D1D1D1D1D1D1D1D1D1D1D1C1D1E1F201F1D1D1E1E1F1F
+1F1F1E1E1E1E1E1D1D1D1D1D1D1D1D1D1D1D1D1D1E1E1F1F20
+1F202223222323222020212224262626262524232222222324
+25252423212020212121222323222323222222222323232221
+1F1E1D1E1E1E1D1D1D1D1C1B1B1B1B1D1E2022232222222223
+242423232223242422211F1E1F1F1E1F201F1E1E1E1E1F1F1F
+1F1F1F1F1F1F1F201F1F1F1F20212020222221212121222324
+25252525272A2A27262727272626262526262627272727292B.
+3C36323132343433322F2E2C2A292825211E1D1D1D1D1D1C1C
+1B1B1B1B1B1C1C1C1C1C1C1C1C1C1D1D1D1D1D1D1C1C1C1C1C
+1C1C1C1C1C1C1D1D1D1D1E1D1D1D1E1F1F1F1F1E1D1E1E1F1F
+1E1E1D1D1D1D1D1D1D1D1E1E1E1D1D1D1D1D1D1E1E1E1E1F1F
+20212323232222202021232425262625242221212122232425
+25242221202020212222222222212222222121222221212120
+1E1D1D1E1E1D1D1D1D1C1C1B1C1C1D1E1F2021212021212122
+232322232322201F1F1F1F1F1F1E1E1F201F1E1D1E1F1F2020
+1F1E1F20201E1F20201F1F2021202123232322222223242425
+25242526282928262728272525262726262627282727282A2B.
+3835343536353331302D2B2A2926231F1D1D1D1D1D1D1D1D1D
+1C1B1B1B1C1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1C1C1C
+1D1C1C1B1B1C1B1C1D1E1E1E1E1E1F1F1E1E1D1D1D1E1E1F1F
+1F1F1D1D1D1C1D1D1D1D1D1D1D1D1D1C1C1C1D1D1E1E1E1E1F
+20212120212122212122232425262523222222222222232324
+23222121212121222323222121212222211F1F20201E1E1F20
+1F1D1D1E1E1D1C1B1B1B1B1B1C1D1F20201F1F202122202122
+23232221201E1D1E1E1E1E1E1E1E1E1F1F1F1F1F1F1F1F1F1F
+1F1F201E1F1F20202122212122212223232322222223252524
+2424242627282726262828262424252628282727272828292A.
+3D35333639393532312D2D2D2A241E1B1C1D1E1E1D1D1D1D1D
+1D1D1C1C1D1D1E1E1E1D1D1D1E1F1F1F2120202021201F1F20
+201F1E1E1D1D1D1D1D1D1D1E1E1E1E1E1F1F1E1D1C1D1D1E1E
+1F1F1E1D1C1B1B1C1C1D1E1D1D1C1C1C1C1C1C1D1E1E1D1D1D
+1E202121202020212121222325252524232221202123242424
+24242322212121212223232222212121212120201F1F1F1F1E
+1D1D1E1E1D1C1B1B1B1B1B1B1B1C1E2021201F202122232424
+2322201E1E1E1D1D1E1F1F1F1E1D1D1E1F1F1E1F1F1F1F1F1F
+1F1F1F1F1F1E1F212121212324232322212223232222222323
+23232425262828262627282725252627282826252627272728.
+3D3735373938332F2E2D28231F1D1D1F20201D1D1F1F1F1F1E
+1D1D1D1F20201E1D1E1F1F1F1F1F20202021222323221F1F21
+23211E1D1E1F21201C1C1D1F1F1F1E1F1F1F1D1C1C1C1D1E1E
+1D1D1D1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1D1D1D1D1E
+1F1F2021202020202021242627252321202122232323232424
+2425232220202122222222212020202020201F1F1F1F1F1E1D
+1E1E1D1D1C1B1B1B1B1B1B1B1B1E2021201E1E202224232322
+21201F1E1D1D1D1D1E1F1E1D1D1D1E1F1F1F1F1F1F1F1F1E1F
+1F1F1F1F1F2020202021232424232221222222222221212222
+23242527282A27272929272625262728282626272826242629.
+3934323332302D292623201F20201F1F1F1F1F1E1E1E1E1E1F
+1F1F1F21201F1E1F201F1F1F2121201F2224242322201F2022
+22201F1F2021201D1C1E1F1F1F1F1F1F1F1E1C1B1C1C1D1E1D
+1D1D1D1D1C1C1C1C1C1C1C1C1C1C1B1B1C1C1C1D1F1E1D1E1F
+20202020211F20222222232323222221212223242424242322
+2021222222222222222222212122222120201F1F1F1F1F1F1F
+1E1D1C1C1B1B1B1B1B1B1B1C1E1F201F1D1E20222221222220
+1E1E1D1C1C1D1E1F1E1D1D1D1E1F1F1F1E1E1E1E1E1E1E1E1F
+1F1E1F1F20201F1F2122212223232323222120202021222222
+23252728282727292A2726272828272729282524252628282A.
+3C35302E2E2D2924201F202020201F1F20201E1E20201F1F20
+201F1F21202020202020202021212021222425252321202021
+212020202020201F1E1E1F1E1E1D1D1E1F1F1D1D1C1D1D1C1D
+1C1D1D1D1D1D1D1D1C1C1B1B1C1D1D1D1D1D1D1D1E1E1D1E1F
+20202021212121212323232222222322232323232323222121
+22222323232322222322222221212222211F1E1F1F1F1F2020
+1F1D1E1D1C1B1B1B1B1C1C1C1E1F201E1D1D1E1F2021222220
+1E1D1C1C1C1C1C1D1E1D1D1D1E1E1E1E1D1C1D1E1F1F1E1E1F
+1F1E1E1F201F1F1F1F21212020212221212221212121202123
+23242628272626272828272728272426272726262627282829.
+3F372F2B292724211F1F1F20201F1E1F1F1F20202222212020
+201F1E1E20201F1F1F20202020201F1F21222222222221201F
+202121201F1F1F1E1E1E1E1E1D1D1C1D1E1E1E1D1C1B1B1B1C
+1C1C1D1C1C1C1D1D1C1C1C1E1F1D1C1C1C1C1D1E1D1D1D1E1F
+201F1F20201F20212223232221222223232423222121212120
+20222222222221222222222221202021211F1E1E1E1E1E1F1F
+1F1D1D1C1C1B1B1A1A1B1B1C1D1D1E1E1D1C1B1C1E1F20201D
+1C1C1C1C1C1C1C1C1D1D1E1E1E1E1E1E1D1D1D1D1D1D1D1E1E
+1F1F1F1E1F201F1E1F20201F1F202020202222212020202022
+22222326272828252526272728272324252626272626272828.
+332B28262421201F1F20201F1E1E1F201F1F2123242322201F
+1F2022212121202020202020212120202121201F20201F1E1E
+1E1F201F1E20211F1D1D1E1E1E1E1D1E1D1D1D1C1C1C1C1C1D
+1D1C1C1C1C1C1C1B1C1C1D1E1F1E1D1C1C1C1D1D1D1D1E1F20
+1F1F2021212021222121212121222324242323212020202121
+2121212121212121212121212020201F1F1F1D1D1D1E1E1F1E
+1D1D1C1C1B1B1B1B1B1B1C1D1E1E1D1C1C1D1D1E1F1F1E1D1B
+1A1B1B1B1C1C1D1E1E1E1D1D1E1E1E1D1D1D1C1D1D1D1D1D1E
+1E1E1F1F1F20201F1F20211F1E1F2121212121212121222222
+23242627282827262627262626252424242526272827272828.
+34272122242321201F1F20201E1D1F2223202021212222211F
+1F20222422222221212021232423232323232221201F1F1F1F
+1D1D1D1D1D1E1F1F1D1D1D1D1D1D1D1E1E1C1C1C1C1C1C1D1E
+1D1D1D1D1D1C1B1B1B1C1D1D1E1E1D1C1C1C1C1D1D1D1F1F20
+20202021222020212121212121212223222121212121212122
+2321212121222222212121212121201F1F1E1E1C1D1E1F1F1E
+1E1E1D1C1B1B1B1B1B1C1C1E1F1F1C1B1B1C1E1F201F1C1B1C
+1A1B1B1B1B1C1D1E1E1E1E1E1E1F1E1D1D1D1D1D1D1D1D1D1D
+1D1D1E1F1F1F1F1F1F1F1F1F1F20201F1F2121202021222222
+22232527282826272829272523232425252626262526272728.
+392A201F21212021212121201F1F2022201D1D202120212221
+2020202021222323232424252625242526262524252625211F
+1D1C1C1C1C1B1C1C1D1D1E1E1D1C1C1C1D1D1D1C1B1B1B1C1D
+1E1E1D1C1C1C1C1C1C1D1D1D1D1D1C1C1C1C1D1D1D1D1E1E1F
+2020201F202321212120212121222222222222212120202121
+22222120212122222222201F1F20201F1D1D1F1E1E1D1D1D1D
+1E1D1C1C1C1A1A1A1B1B1C1D1E1E1C1C1B1C1C1D1E1F1F1C1B
+19191A1A1B1B1C1D1E1E1D1D1D1D1E1E1D1D1C1C1D1D1D1D1D
+1D1D1D1E1E1E1E1D1D1E1F1F1F1F20201F1F21211F1F222221
+21222427292926252727262423222223252525252626262627.
+2E221E1F2122221F1F20201E1E2022201E1D1F212424232221
+20212323222324252627262523232426272828272624222120
+1E1D1C1B1B1B1C1D1D1D1D1D1C1B1B1B1C1D1D1D1D1C1C1C1D
+1D1C1C1B1C1C1C1C1C1C1C1C1D1D1D1C1C1C1C1C1C1D1F2020
+201F2021202121212223232323222121212121212121202021
+2121222322222221212120202020201F1F1F1F1F1D1D1D1D1D
+1D1D1C1B1B1B1B1B1C1C1D1D1D1C1B1B1B1C1D1D1E1D1C1B1B
+1A1B1B1B1C1C1D1D1D1D1C1D1D1D1E1E1D1E1D1C1C1D1E1E1E
+1D1D1D1E1F1F1F1F1F1E1D1E1F2021202021211F1F21222021
+22242628282726262625242423232324242425262627272828.
+251D1D2021201E1D1E1E1E1D1E2022211F1E20232423222223
+24252524252626262525242323232325262625221F1E1E2122
+1E1C1B1C1D1E1F1E1D1E1E1D1C1C1B1B1D1D1D1C1C1C1C1C1C
+1C1B1B1A1B1B1B1B1B1B1A1B1C1C1C1C1C1C1C1D1D1E1F1F1F
+1F1F1F1F1F2020222323242220201F20212020212122222220
+20212121222221202020212121201F1E1E1D1D1E1E1E1E1E1D
+1D1C1C1C1B1B1B1B1C1D1E1E1D1B1A1B1C1D1D1D1D1C1B1A1A
+1A1B1C1C1C1C1C1D1D1D1C1C1D1D1E1E1D1C1C1D1D1D1D1D1E
+1F1F2020201F1F1F1F1E1F201F1E2121212121212021222122
+23252627282725262525242424232323242425272727262728.
+2E241F1E20201E1C1C1D1D1D1E202224232120222422212123
+2526252525252627272624232120212222211F1E1D1D1E2020
+1F1D1C1D1E2022202020201E1D1D1C1C1C1B1B1C1D1D1C1B1B
+1B1B1B1B1B1B1B1B1B1A1A1A1B1B1B1B1B1B1C1C1D1E1F1F1F
+1E1F1F1F1F20202123242423211F1F20222020212122222221
+2020212121212020202020202120201F1E1D1D1D1D1D1E1E1E
+1E1D1D1C1C1B1B1A1B1C1D1E1E1D1B1B1B1C1C1C1C1C1C1B1B
+1A1B1B1B1B1B1C1C1C1C1D1C1D1D1D1E1E1D1D1D1D1E1E1E1E
+1F1F201F2021201F1F20201F1E1F2120202121222222202021
+23232324252626272525252524242424242425252526262627.
+2E231D1F21201E1C1C1D1D1E1E1E1F21232221212121212224
+2526262524242526262422201E1F1E1E1D1D1C1C1C1C1D1F1F
+1F1E1D1E1F20201F1F20201E1D1D1D1D1D1C1C1C1C1C1C1C1C
+1C1B1B1C1C1B1B1A1A1A1B1A1A1A1A1A1A1A1B1C1C1D1E1F1F
+1E1E1E1F2021202223232221201F1F21222020202121212121
+20202020202120201F1F21212020201F1E1F1F1E1D1E1F1E1D
+1D1D1D1C1C1B1A1A1B1C1D1E1C1C1B1B1C1D1D1D1C1B1B1A1A
+1A1A1B1A1A1B1B1C1C1D1E1D1D1D1D1E1F1E1E1E1F1F1F1D1E
+1F1F1F2021202020202020201E1E1F201F2021222121212021
+21212122242525262625242423232424252526262525252526.
+231E1F21201E1D1D1D1D1D1D1D1F232523201D1D2023252628
+2A2A2725252322201F1E1E1E1D1C1B1B1A1A1B1B1C1C1C1D1D
+1E1F1F1F1F1E1E1D1D1E1F1E1D1D1D1D1C1D1D1D1C1C1B1C1B
+1C1C1C1D1C1B1A19191A1B1B1A19191A1A1B1B1C1D1F1F1F1F
+1F20202123242321201F1F1F20201E1F2121201F2022201E1E
+202220202020202020202020201F1F1F201F1D1F1F1F1E1D1D
+1C1C1C1C1A1A1B1B1C1D1D1D1D1C1C1D1E1E1D1C1B1A1A1A1A
+1A1B1B1B1B1C1C1D1D1D1D1E1E1E1E1E1E1E1F20201E1E1F1F
+1F1D2022202020202021221F1F202120202121222323222121
+22222222242526262523232324242425252627262525262727.
+27201E1E1F1F1E1D1D1D1D1D1D1E1F201F1E1E1F202224272B
+2C2B2927211F1F20201E1E1F1F1D1D1D1D1D1C1C1C1B1B191B
+1E1F201E1C1C1E1E1F1E1D1D1D1E1E1D1C1C1B1B1B1B1B1B1C
+1C1C1D1D1C1B1A19191A1B1B1A1A1A1A191A1B1B1C1D1E1F1F
+20212223252522201F1F2020201E1F21211F20212120212120
+1F202220202021202021212121201F1F1F1F1F1E1C1C1C1C1C
+1D1D1D1B1B1A1B1C1D1D1E1D1D1D1D1E1D1C1C1C1B1B191A1A
+1A1B1B1B1B1B1C1C1D1E1E1D1E1E1F1E1E1E1E1F1F20201F1E
+1F20201F212221202121202020202021212121222222212120
+20212121222324242425242424252525252526262625252526.
+2D221D1D1E201F1D1D1F1E1D1D1D1E1F1F1F1E1E1F20222323
+232322211F1F2020201F2122212122211F1F1F1F1E1C1C1C1C
+1D1D1E1E1E1D1D1D1F1F1E1D1D1D1D1E1E1C1C1B1B1B1B1C1D
+1D1D1D1C1C1C1B1B1A1A1B1B1C1C1B1B1A191A1B1C1D1D1F20
+21212225262322201F1F1F201F1E1E2020202021222221211F
+1F2122212020202020212120201F1E1F201F1D1D1D1D1D1D1D
+1D1D1C1B1B1B1C1D1D1D1E1D1C1B1D1E1E1C1B1B1B1A1B1B1B
+1B1B1C1C1C1D1D1D1D1D1D1D1E1E1D1D1D1F1F1F1F1F1F2020
+201F1F21212021212121212221202020202020212222212121
+21212222222323252526242323242426262626262626252526.
+261F1C1D1E1F1E1D1D1E1D1D1D1D1D1E1F201F202020202223
+2222201F1F201F1F1F1F20201F1F201F1E1E1E1D1D1D1C1B1C
+1C1D1D1D1D1D1D1E1E1D1D1D1E1E1D1D1D1C1C1C1C1B1C1C1D
+1D1D1C1C1C1B1A1A1A1A1B1B1B1B1B1A1A1B1B1C1C1D1F2020
+222323222221201F1F1F1F1F201F1E1F212020202121202020
+202021212020202020212020201F1E1E1F1F1F1D1D1D1D1C1C
+1C1C1C1B1B1B1C1C1D1D1D1D1B1C1C1D1B1A1A191A1A1A1A1A
+1B1B1C1C1C1C1C1C1D1E1E1E1E1E1E1E1F1F1F1F1F1F202020
+20212120212121212222222221201F20212020212121202021
+22222223232324242424242323242424252626262625252627.
+241D1C1E1F201F1B1C1D1D1D1D1D1E1F20211F1E2020212223
+23211F1F20201E1D1D1D1D1D1D1C1B1C1D1D1C1C1B1B1B1B1B
+1B1C1D1D1D1D1D1D1C1C1C1D1D1E1D1C1B1B1C1D1D1D1D1C1C
+1C1C1C1C1C1B1A1A1A1A1B1B1B1B1B1B1B1B1B1B1C1D1F2122
+2121212120201F1F1F1F1F1F20201F1E20212120202020201F
+2020202021212121211F1F1F1F1E1E1E1F1F1F1E1D1D1D1C1C
+1C1C1B1B1B1B1B1C1D1D1D1D1C1C1C1C1C1B1A191A1A1A1A1A
+1B1B1B1C1C1C1C1C1D1E1E1E1E1E1E1F1F1F1E1F201F1F2020
+2021202021212020212222232322201F1F202222201F202121
+22222223232323242424232323242526262625252525262627.
+2F261E1C1E20201E1C1C1D1D1C1C1D1E1E1F1F1F2022222222
+211F1E1F1F1E1C1C1C1C1C1C1C1C1C1C1C1C1C1B1A1919191A
+1B1B1C1C1C1C1D1D1D1E1E1D1C1D1D1C1C1C1C1C1C1C1C1C1C
+1D1C1C1C1C1C1B1B1A191A1B1B1B1B1B1B1B1B1B1C1D1E1F20
+202020212120201F1F1F201F1E2021201F2022212020202020
+212120202020202121201F1F201F1F1E1E1F1F1F1E1D1D1E1D
+1D1D1D1D1D1C1C1C1D1D1E1E1D1D1D1C1C1B1A19191A1B1A1A
+191A1B1B1B1C1C1D1D1E1E1E1E1E1E1F1F201F1E1F201F1F1F
+21211F1F212121212121212223222221212122222121212121
+21222222222222232424242524242425252525252525262626.
+2E221C1C1E1F1F1F1D1C1C1C1B1B1C1D1E1F20222121211F1E
+1D1D1D1D1C1C1C1D1D1D1E1E1D1E1F1E1D1C1B1A1919191819
+191A1B1B1B1C1D1D1E1D1C1C1B1B1B1C1C1C1C1C1B1B1B1B1C
+1C1C1C1B1B1B1A1A1A1A1B1A1A1B1B1B1B1B1B1C1E1E1F1F1F
+20201F1E1F1F1F1F1E1E1D1E1F20201E2021201F20201F1D1E
+2121201F20201F1E1F22201E1D1E1F1E1E1E1D1C1C1C1C1C1C
+1C1C1B1B1A1B1C1D1D1D1C1C1C1C1D1B1A1A1919191A1B1A1A
+1A1B1B1B1C1C1C1C1C1D1D1D1D1D1E1E1D1D1D1D1E1E1E1D1D
+1E1F202221212121201F1F20201F1E1F21202021221F202221
+21222222212122232323232323242424242323232425262626.
+201B1D1F201F1D1D1E1D1D1C1D1D1E1F22232221201F1F1F1F
+1F1F201F1F2021201F1F201F1E2222201F1F1E1D1C1A181819
+1A1B1B1B1C1E1F1F1F1F1E1C1B1B1C1C1C1C1C1B1B1B1B1B1C
+1C1C1C1C1B1B1A1A1B1B1B1B1C1B1B1A1B1C1D1F1F1F1F2020
+1F1F2021201E1E1F1E1F1F1F20211F2021202020201F1F2021
+1F2021202021212020201F1F20201F1D1D1E1D1D1D1D1D1D1D
+1C1C1C1C1C1C1C1C1C1C1C1C1C1D1B1A191A1A1A1B1C1B1B1B
+1C1D1C1C1C1C1C1D1E1E1E1E1E1E1D1D1D1D1D1D1D1D1D1D1F
+202221222221201F1F2021211F2021202021211F2024222221
+21212222212122232323242424242525242424242424252727.
+271D1C1D1F1E1D1B1B1B1B1B1C1D1E202223201E1E20222425
+2525252422201F1F1F1F1F1F1F202223212020201E1B1B1B1A
+1A1A1A1A1A1A1C1C1E1F1F1E1C1B1B1B1C1C1C1C1C1C1C1C1B
+1B1B1B1B1B1B1A1A191A1B1B1B1B1B1A1A1B1B1D1D1E1E1F1F
+20201F1D1F20201E1E1F1F1F20201F2021201F20201F1E1F21
+21202121202020211F1F1F1F1F1F1F1E1D1D1D1D1D1D1D1D1C
+1C1C1C1C1B1C1C1C1D1D1C1C1B1B19191A19191818191A1B1B
+1C1B1B1B1C1C1D1D1E1D1C1C1D1E1F1E1E1E1E1D1D1D1E1E1F
+1F1F1F1F1F1F1E1D1E20201F20201F1F20201F1E20211F1F21
+21212222212021212223232323232424242423232424242525.
+291F1C1D1E1D1D1C1B1A1B1B1C1D1F2123201F202124282B2D
+2B2624252321202021232527282A2C29252221201F1D1C1C1C
+1C1B1B1A18191A1C1E1E1F1E1D1C1C1C1C1B1B1B1B1C1D1D1C
+1C1C1B1A1A1A1A1A1A1A1B1B1B1B1B1B1B1B1C1C1D1E1E1E1F
+1F1F1E1E20201F1F1F201F1F20211F1F2020201F1F1F1F2021
+201F2020201F1F2020201E1E1F1F1F1E1D1D1D1D1D1D1C1C1C
+1C1C1C1C1C1B1B1B1C1C1D1D1C1B1A1919191A191919191A1A
+1B1B1B1C1C1C1C1C1D1D1C1C1D1E1F1F1F1F1E1E1E1E1F201F
+1D1E20211F1D1D1D1D1E1E1F1F20201F1F1F1F1E1F20201F1F
+20212122222221222323232323232323232424242524242425.
+211B1C1D1D1D1C1B1A1A1B1C1E20222221202022272C31322E
+2822242728292B2C2A292A2C2D2E2C2722201E1E1D1C1B1B1B
+1B1B1B1A19191A1B1C1E1E1D1C1C1C1C1B1B1B1B1C1C1D1D1C
+1B1A1A19191A1A1A1A1B1B1B1B1B1B1C1C1C1C1C1D1E1E1F1F
+1F1F1F1F1F1F1F1F1F1F20201F1F1F202020201F1E1E1F1F1F
+1F1F1F1F1E1E1F1F1E1E1F1F1E1E1E1E1D1C1C1C1C1C1C1C1C
+1C1C1C1B1B1B1B1C1C1D1D1C1B191818191818191919191A1A
+1A1A1A1B1B1B1C1C1D1D1D1D1E1F1F1F20201E1E1E1F1F1F1E
+1D1D1F201E1D1D1D1E1E1F201F20211F1E1F21201E1E202120
+21222222232323232424252525242424242424242425252526.
+211A1A1C1D1D1C1B1A1A1B1D1E2022211F2022272B30312C27
+262A32383936322F2A27262522232224252524222222211F1C
+1A1A1A19191919191B1B1C1C1C1C1C1B1B1A1B1C1D1D1D1D1D
+1B1A1A1A1A1A1A1A1B1B1B1B1B1B1B1B1B1B1B1C1D1D1E1E1E
+1E1E1E1E1E1F1F1F1F1F1F1F1F20201E1E1F1F1E1E1F1F1F1F
+1F1F1E1E1E1F1F201F1E1F201F1D1D1D1D1D1D1D1D1C1C1C1C
+1C1C1D1C1B1B1B1C1D1D1C1B1A18181818181818181919191A
+19191A1A1B1B1B1C1C1D1E1F1F201F1E1E1F1E1E1E1D1D1D1D
+1D1D1D1D1D1D1D1E2021211F1F21211F1E1F1F1F1F1F1E2022
+22212222222122242324242424242424252423232324242526.
+2D261D1A1B1D1E1D1B1B1B1C1C1E2123221F1D252C302D2725
+2A3541443F39312B2825211F1C1C1D1E1F20212122272D2F2B
+241F1C1B1A19191A1B1A1A1B1B1B1C1C1B1B191A1B1C1D1D1C
+1C1B1B1A1A1A1A1A1A1A1B1B1C1B1B1B1A191A1B1C1C1D1D1D
+1D1D1D1E1F1F1F1E1F1F1F201F1E1F20201F1E1F1F1F1F1F1F
+1F1F1E1E1E1E1F1F1F1F1F201F1E1E1F1E1D1C1C1C1C1C1C1C
+1C1C1C1C1C1B1B1A1B1C1D1D1C1A181718191817181917181B
+19191A1A1A1A1A1B1B1B1D1E1F1F201F1D1D1F1F1E1D1D1C1C
+1D1D1D1D1D1D1E1E1E1E1F20201E1E1F201F1D1E1F1F1F1F1F
+1F202121202021222323232324242424222222232323242525.
+271E1A1B1D1D1C1B1B191B1D1F2123232021272E2C27272E37
+3B3A3635312B25211F1E1D1C1D1D1E1F202121232932383128
+211E1C1C1C1B1A1919191A1B1B1B1C1D1B1B1A1A1B1B1B1B1B
+1B1B1B1B1A1A1A191A1B1C1C1C1C1B1A1A1A1B1C1D1D1D1D1D
+1E1E1E1E1E1E1E1F1F20201F1F20211F1F201F1D1D1F1F1F1F
+1F1F1F1F1F1F1F1F1F20201E1E1F1F1E1C1D1D1D1D1C1C1C1C
+1D1D1C1C1B1B1B1C1C1C1C1C1B191818181818181919191919
+19191A1A1A1A1A1B1B1D1E1F1E1D1D1D1D1E1D1C1C1C1C1B1C
+1C1D1E1F1E1E1E1F1F1F20201D1E1F201F1D1E1F1F1F1F1E1E
+1F2021201F2021212223222223232221222323242526262626.
+1F191A1D1D1C1A1A1A1B1D202323212124282828282E323432
+3335312B24201D1D1D1D1D1F222325282928272A2F322E261E
+1C1D1D1C1B1A1919191A1A1A1A1B1C1C1B1B1B1B1B1C1C1B1B
+1B1A1A1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1C1D1D1D1D1E1E
+1D1D1D1D1E1F1F1F1F201F1F1F20201E1F1F1F1F1F201F1E1F
+201F1E1E1F1F1E1E1F1F1F1E1E1E1D1D1D1D1C1C1B1B1B1B1C
+1C1C1C1B1B1B1C1D1E1D1B1A19191918181818191919191919
+1A1A1A1A1A1B1C1D1E1E1D1D1C1C1C1D1D1D1D1D1D1C1C1C1C
+1D1E1E1D1D1D1D1E1E1E1E1F1F1F1F1F1F1F1E1D1E1E1E1E1F
+201F1F20212020222323232423232322222324252626262626.
+261C191A1B1C1A19191A1B1D2022212023292B2D2B29282A2D
+3136362E231C1B1B1D1E2023262A2D2D2C2B2927272724201D
+1C1C1B1A191919191A1A1A1A1A1A1B1B1B1B1B1B1B1B1B1B1B
+1B1B1B1B1B1B1B1B1B1A1B1B1B1B1B1B1B1B1B1C1C1C1D1D1E
+1E1E1E1D1E1E1E1E1F1F1F1F1F1F20201F1F1F1F1F1E1F1F1F
+1D1D1E1E1E1E1E1E1E1E1E1E1E1D1D1D1D1D1C1C1B1B1B1B1B
+1C1B1B1B1B1B1C1D1E1D1C1A1918181819191919191A191919
+1A1A1A1A1B1B1C1D1D1D1D1C1C1C1C1C1D1D1D1D1D1C1C1C1C
+1D1D1D1D1D1D1D1D1D1D1D1E1F1E1E1E1E1E1F1F1D1D1D1D1E
+1F1F1F20201E1F212222222324232222222323242525252525.
+201B1A1B1C1B1A1A191A1B1D20212122272D2E2C292524272C
+32332F261E1B1C1E2126292D2D2D2D2C292623201F1F1F1E1E
+1D1C1B1A1919191A1A1A1A1B1B1B1B1B1B1B1B1B1B1C1C1C1C
+1C1B1B1B1B1B1C1C1B1A1B1B1B1C1C1C1C1C1C1C1C1C1C1C1D
+1E1E1E1E1E1E1E1F1F1F1F1F1F1F1F2020201F1E1F1F1F1F1F
+1E1F201E1E1E1F1F1F1E1E1D1D1E1E1D1C1C1B1A1B1B1C1C1C
+1B1B1B1B1B1C1C1D1D1C1A1A191A1A1A1A19191819191B1B1B
+1A1A1B1B1B1C1D1D1D1D1C1B1B1B1C1C1C1D1E1E1E1D1D1D1D
+1E1E1D1E1E1E1E1D1D1D1E1F1F1E1E1D1D1E1E1E1E1E1E1E1F
+1F1F1F20211F1F212222222424242322232324242423232424.
+1D19191A1A1A1A1A1A1B1D1E1E20232526272726242325292E
+2E271E1C1D1F252A303438372F221E1F212223232629282320
+1F1F1E1C1B1C1C1C1C1C1C1B1B1B1B1B1B1C1C1C1C1C1D1D1C
+1D1D1D1C1C1B1B1B1B1B1B1C1D1D1D1C1C1B1B1B1C1C1C1D1D
+1D1D1D1E1F1F1F1F1F1F1F1F1F1F1F1F1E20201E1D1E201F1D
+1E20201E1D1E1F1F1F1F1D1D1D1D1D1C1B1B1A1B1B1B1B1B1B
+1B1A1A1B1B1C1D1D1B1A19191A1A1A1A1919191919191A1A1A
+1B1B1C1D1C1C1C1B1C1C1C1C1C1C1C1C1D1D1D1D1D1D1D1D1D
+1D1C1C1C1C1D1D1D1D1D1D1E1D1D1D1E1E1E1E1E1F1F1F1F1F
+1F20201F202120212223232323222122232424232222232426.
+191B1C1C1B1A1918191B1D1D1E20222322232323232324272A
+28221D1D20262D343D42403726191B222A3033302B2A2B2723
+2120212325262522201E1C1D1D1D1D1D1C1C1C1C1D1D1D1D1E
+1E1D1D1D1D1D1D1D1C1B1A1A1B1D1D1D1D1C1B1B1B1C1C1D1D
+1D1D1D1D1E1E1E1E1F1F1F201F1D1F20201E1E1F1F201E1C1E
+1F1F1F1F1F1F1F1F1E1E1E1E1E1D1D1C1B1B1B1C1C1C1C1C1C
+1B1B1A1A1A1B1C1C1B1A19181818181818191919191919191A
+1B1C1C1C1C1C1B1C1C1D1D1C1C1C1C1C1C1C1D1D1C1C1C1C1C
+1C1D1D1D1D1D1C1C1C1D1D1D1D1D1D1D1D1D1D1D1E1F1F2020
+1F1F2122212222222122232322222223242423232221222324.
+29221B18191C1C1A18181A1B1C1D2024242323222323232628
+27241F1E2329333D4244443C2F242127303534302C2D302E26
+2023292F312F2C2A2A26211E1B1B1C1C1D1D1E1F2020202021
+2221202020201E1C1D1C1C1B1C1B1B1B1C1C1C1D1C1B1B1C1D
+1D1E1F1F1E1E1F1F1F1F1F201F1E1F20201E1D1E1F1F1F1E1C
+1F20201E1D1E1F1F1F1F1F1E1D1D1D1D1D1C1C1B1B1B1B1B1C
+1C1C1C1B1B1B1C1C1C1B1A1917181A1818181818181919191B
+1C1C1C1D1C1B1B1B1C1D1D1D1C1B1A1A1A1C1D1D1C1C1C1C1C
+1C1D1D1D1D1E1D1D1D1E1F1E1B1D1E1E1E1E1E1E1E1E1F1F1F
+1F201F1F202322222221212122212021222324242323232324.
+1B17191C1C1B1A1A1A1A1B1B1D1F2122212223252727272726
+2423272C35404649453A2C23202326292A2C313434302A2628
+2D343733303135332D221B1A1E202123232225292B2E323637
+35312F2C2A26221F1E1E1D1C1C1C1B1B1B1B1C1C1C1D1D1D1D
+1D1D1E1E1F1E1F1F1F201F1E1E1F201E1D1E1F1F1F1E1E1E1E
+1E1E1E1D1D1D1E1E1E1D1D1D1D1D1D1C1C1C1B1B1B1B1B1B1B
+1A1A1B1B1C1C1B1B1A19191919191919181818181819191A1B
+1C1C1C1B1B1B1B1B1C1D1D1C1B1B1B1B1C1C1C1B1B1B1B1B1B
+1C1C1D1D1D1D1D1D1E1E1D1D1D1D1D1D1D1D1D1D1D1E1E1E1D
+1D1E1E1F20211F202221212121212121222121222323232324.
+1B18191B1B1A1919191A1B1C1E2021202023282A2C2D2B2725
+282F373B43505649311D161A1F1F2229313738322A2427303A
+3930282A3643412E1C181D242B30312F2E3545535D646B7171
+6C625B544D42382F2824201E1E1C1C1B1B1A1B1B1B1C1D1D1E
+1E1E1E1F1F1F1F1F1F1F201F1E1E20201F1E1E1F1F1F1F1F1E
+1E1D1D1D1D1E1E1E1E1D1D1D1D1D1C1C1C1B1C1C1C1C1C1B1A
+19191A1B1B1B1B1B1A1A19191919181818181819191A1A1A1B
+1C1C1B1B1B1B1B1C1C1C1D1C1C1B1B1B1B1B1B1C1C1C1B1B1C
+1C1D1D1D1D1D1D1D1D1D1D1E1E1D1D1D1D1D1D1D1E1F1F1E1E
+1E1E1E1F20201F202222202021212121212121222223232324.
+201B19191A1A191919191A1B1D1F1F1F1F2025292A2D302F2C
+2D32383B4A59553F2517151B1F20252A3034322B2528303231
+2D27273140493F28191A242F383D3D3A425E809699979AA0A2
+9C928A827A7064574B41382E27211E1C1C1C1B1A1A1B1C1D1D
+1D1D1E1E1F1F1F1F1F1F1F1F1F1F201E1E1E1F1F1F1E1E1E1E
+1E1E1E1E1E1E1E1E1E1E1E1E1E1D1C1B1B1B1B1C1C1C1B1B1A
+19191A1A1A1A1B1A1A1A19191818181818181818181919191A
+1A1B1B1A1B1B1A1A1A1B1B1B1B1B1B1B1B1B1C1D1D1D1D1D1D
+1D1D1B1B1C1D1D1E1D1D1D1F1F1D1D1D1D1D1D1D1D1E1E1E1D
+1E1E1F1F20201E1F2021212021212121212121212122222323.
+1A191A1A1A1A1919191A1A1B1E1F1F1F1F2124272D3233302E
+2F34425257482F1E181A1D1E21262A31312B26272A2C2B2F2B
+272938494937221A222D39404143526F8FA7B0B0ACABAFB1AE
+A59C9992887E766E645A50453A2F25201E1D1C1B1B1B1B1C1C
+1D1D1E1E1F1E1E1E1E1F1F1F1F1F1F1F1F1F1E1D1D1D1D1E1E
+1E1E1E1D1E1E1E1E1E1E1D1D1D1C1C1B1B1A1A1A1B1B1B1A19
+191919191A1919191919181818181918181818181919191919
+19191A1A1A191A1A1A1B1C1B1B1B1B1A1B1B1C1C1C1D1D1E1E
+1D1C1B1B1C1C1D1E1F1F1E1D1D1D1D1D1D1D1C1C1C1C1D1D1D
+1E1E1F1F20201F1F2122202021212020202121212121212222.
+1918191B1B1A1918191A1B1D1D1E1F212224292F302F2B2B2F
+363F46402F1F191A1C1E21262C35352E28292D2E2A28262426
+36484D3D24192132404545475B80A3B7B9B8B9B8B8B9B6AFA9
+A6A6A1958B847F776E645E5A5245382F27211E1D1D1D1D1E1E
+1E1E1E1E1D1D1E1F1F1F1F1F1E1F201F1C1E1F1E1E1E1E1E1D
+1D1E1E1E1E1E1D1D1E1E1D1C1C1B1B1B1A1B1B1B1C1A1A1A1A
+1A1A191A191919191919191918181818181919191919181818
+191A1B1B1B1B1B1B1B1C1C1C1C1C1B1B1B1C1C1C1C1D1D1D1D
+1D1B1B1B1B1B1B1B1C1C1D1D1D1D1C1C1C1C1C1C1B1C1C1D1E
+2020201F20211F222321202020212021212121212121222223.
+19181A1B1B1A1919191B1B1B1B1B1E212426292D2F2F2B2828
+2A2B2A28221E1C1C1D20262B303B3C2E211C1F242A31302726
+364745321F1A263A4C4E48506F9ABAC0B8B7BCBFC0BFBDB7B1
+AFAFABA39C969089817B76726F6A635A4E3F332A2523212020
+1F1E1F201F1D1F1F1F1F1F1F1E1E1F1F1F1F1E1D1D1D1E1F1E
+1E1D1D1E1E1E1D1D1D1D1D1C1C1C1B1B1B1B1B1B1B1B1B1B1A
+1A1A1A19191919191919181818181818181818181819191819
+191A1A1A1A1A1B1B1C1C1C1C1C1B1B1B1B1B1B1C1C1C1C1C1C
+1C1C1C1C1C1C1C1C1C1C1D1D1D1D1D1D1E1E1D1C1C1C1D1E1F
+1F1F20201F1F212221201F2020201F20222020212020222322.
+1E19181A1B1B1A1919191A1A1B1B1B1C1E2024282F322C2728
+2E2F26201F201F1E1F242B31373E392C1E181A222C33302727
+37434031201D2B3E4E4E4D556E92B0BDB9B8BDC5C6C4C2C1BC
+B7B3B2AFAAA6A19A948E8A86837F7E7A73695D50453A302925
+24232322201F1F1F1E1E1F201F1E1E201F1D1D1E1E1E1F1F1E
+1E1E1E1E1E1E1E1E1E1E1D1D1D1D1C1C1B1B1A1B1C1B1B1B1B
+1A1A191A1A1A1A1A1919191919191918181818181819191919
+191919191A1A1A1A1B1C1C1C1B1B1B1B1B1B1C1D1D1D1D1C1C
+1C1D1D1D1D1D1D1D1D1D1D1E1E1E1E1F1F1F1F1E1C1C1D1D1D
+1E1F20201F1E20222221201F20202120202121212121212122.
+1918191B1B1A19181819191B1B1B1B1B1D21262A2B292A2C2D
+2B241F201F1E1F22293542453B2D1E1718212A2E2F2B25262E
+3530241D22344A5550506A8EA8B4B5B4B6BFC6C9C7C4C2BFBB
+B9B7B2AEABA7A39D989492918E8A8680796F655D564E46403A
+332D282523221F1F1F1E1F1F1F1E1F1F1E1C1D1E1E1F1F1F1F
+1E1E1E1D1D1D1E1E1D1D1D1D1E1D1C1B1B1A1A1B1A1A1B1B1B
+1A191819191919191919181718191918171818181818191818
+18191A1A1A1A1B1B1B1B1B1B1B1B1B1B1B1B1B1C1C1D1D1D1D
+1D1D1D1D1D1C1C1C1C1D1D1D1D1D1D1E1E1E1D1D1D1C1C1D1D
+1E1F1F1F1E2021212020201F1E2021201F2021202122232224.
+16181A1B1A19181817191A1A1A1A1B1C1E22272725252E3632
+251A1C22211F212935434B422C1813171D2834372A1D1B2326
+241E1B1D273A4F5047547EA6B6B5B1B0B4BDC4C5C4C2C0BDBB
+BAB7B2AEACAAA7A29B97979593908C867E77706B666463625F
+5A52473C322D27232120201F1F1F1F1F1E1D1D1D1D1D1E1E1E
+1E1D1E1E1D1D1D1E1D1D1D1F1F1D1C1C1C1B1B1B1A1B1B1B1A
+1A191918181819191919191818181818181717171819181819
+18181A1A1A1A1B1B1A1A1A1A1A1A1A1A1A1B1B1B1C1C1C1C1C
+1D1D1D1D1C1C1B1B1C1C1D1D1D1D1C1C1D1D1D1D1D1D1C1C1D
+1D1D1D1E1F20201F1E1F1F1F1F201F1E1F2021202122222323.
+1917191A1A1918181818191A1A1A191A1B1F252A28262B3334
+271B1B212221232935424637201415192029302F251C212321
+1E1C1B1E2533444A404B6F98B0B3B0B0B2B7BCC0C1BFBFBEBD
+B9B5B0ACABACABA7A09893929698969189827C78736D707678
+7877746F68604F3B2C24212120201E1D1E1E1E1D1D1D1E1E1D
+1D1D1E1E1E1E1E1E1E1D1D1D1E1E1E1D1C1C1B1B1B1B1B1B1A
+1A191919191819191919191818181717181816161719191717
+181919191A1B1B1A1A19191A1A1A1A191A1B1B1B1A1A1B1B1C
+1C1C1C1C1B1B1B1B1B1B1C1C1C1C1C1D1D1E1E1D1C1D1C1C1C
+1C1C1C1C1D1D1E1F1F1F1E1D1E1E1F20201F20212121212223.
+15161A1B19181717191917181919181A1D202528282D312D23
+1A191F2323242A33372F221816171A1E28302D20181F2A241B
+1A1B1D243241473F42648CA7AEACADAFB1B7BABCBBB8B7B7B6
+B2ABA6A6A9ABAAA59D95949C9E99938C86807C7976767B7E80
+84868585827D6C564230242020211F1D1D1D1D1D1D1D1D1D1D
+1C1D1D1D1D1D1E1D1C1C1C1C1C1D1C1C1C1C1C1B1B191A1919
+19191919191818181818181818171718181616171818161619
+19191919191818191A1B1B1B1B1B1B1B1C1C1C1B1B1A1A1A1B
+1B1B1B1A1A1A1A1B1B1B1B1B1B1B1B1C1D1D1E1D1B1B1B1B1B
+1B1C1C1C1C1D1E1F1F1F1E1E1D1E1F1F20201F1F2122222122.
+1617191918171818171819181819191A1C2126272C2D271E19
+1B1F232324292B261F1A1818191A21292A231A191F24211B1B
+1C1E24313F443E3D618CA9AFABAAACADB0B6BBBAB7B2B0B1AE
+AAA8A8A9AAAAA8A6A5A4A3A09A94928F8A837F7F818484868A
+8D8D8C8B877E715F4D3C2E241F1F20201C1C1D1D1E1E1E1D1C
+1D1D1D1D1D1D1D1C1C1C1C1C1C1C1C1C1C1B1B1A1A19191A1A
+1A191919191918181818171718181716171818171719191717
+1819181718191A1A1B1D1D1C1B1B1B1C1D1D1C1B1A1A1A1B1C
+1B1A19191A1B1C1C1C1B1B1A1B1C1C1D1D1D1D1C1C1B1B1B1B
+1B1C1C1D1E1E1E1E1F1E1D1E1E1F1F20211F1F202222212123.
+1A1718191918171717191817181919191A1E21252726221D1A
+1A1E2124252A2C281F1817191A181E26262019191E23211B19
+1C1F222A3743443D4E7396A8A8A3A2A5A8ABB0B6B7B3AEA9A5
+A5A7A8A8A9A9A8A7A5A4A2A19C999795918B85838487888888
+8B8F908F8D8A84786A5C4C3C2F27221F1E1E1E1D1D1D1E1E1C
+1D1D1D1D1D1D1D1D1C1C1C1C1C1C1C1C1C1B1B191A1A1A1A1A
+19191919181818181818181717181816161719181717181918
+181818181818191B1C1C1C1B1B1B1B1C1C1B1C1C1B1B1B1B1B
+1B1A1A1A1A1A1B1B1B1B1B1B1B1C1B1B1B1B1C1C1C1C1C1B1B
+1B1C1C1D1D1D1D1D1E1E1F1F1F1F20201F2021202021222122.
+1B171818191817171818171617181818191B1D212625201C19
+1A1D2023262C2D271F19181919191C1F201E1A181C22201A19
+1D2021242E40463D405D839BA09C9B9FA1A3A7ACAEABA5A09F
+A0A2A5A6A7A9A7A4A2A3A3A09C9C9B9995908B888787898A89
+8A8D90908E8B88847C706153443529222021211F1E1E1F1F1D
+1D1D1D1D1D1D1D1D1D1D1D1D1C1C1C1B1B1A1A1B1B1B1A1A1A
+1A191919191918181818181817171818171618191817181919
+181818181818191B1B1B1B1B1B1B1B1B1B1B1C1C1C1B1B1A1B
+1B1A1A19191A1B1B1B1B1B1B1B1B1B1B1A1B1B1B1B1C1C1C1C
+1C1C1C1C1C1C1C1D1D1E1E1E1E1E1F1F2020201F2021212122.
+171618191817171818161617181818191B1B1E1F1F1D1B1A1A
+1D2124272D2A221B19191A191A1A1B1B1B1A1A1C1E1D18181E
+2223262F3A3D3A415F7F92969494989B9D9FA3A29E9998999B
+9DA0A3A4A4A5A5A5A4A3A29E9C9B999693918F8D8B8B8A8A8B
+8D9192908B85817B72675B504337302C2A27231F1D1E1E1F1E
+1D1D1C1D1D1D1D1D1D1D1C1C1C1B1B1B1B1B1B1B1B1B1A1A1A
+19191919181819191818181717181817171819181717181917
+1718191818191B1C1C1C1C1B1B1A1A1A1A1B1B1B1B1B1B1B1B
+1B1B1A19191A1B1B1B1B1B1B1A1A1A1A1B1B1B1B1B1B1B1B1C
+1C1C1C1C1D1C1C1D1D1E1E1E1F1F1F1F1F1F1F202020222322.
+1617191A1817181918151517181918181A1B1A1A1A1A1A1A1A
+1D2226282A231C18191A1A1918191B1B1A1A1C1F201C16181E
+2123252C3638323D5F7F8E8F8C8D929495979C9C9893929395
+969B9E9FA0A2A2A3A3A19F9F9F9D9997949190908F8F8F8D8B
+8D90928F8986827B736A615950463D3C3F3D3328211E1F201F
+1C1D1E1E1D1C1C1C1C1C1C1C1B1B1B1A1A1A1A1A1A1A1A1919
+19191918181818191919181717171717181817161719191718
+1918181819191A1B1B1B1C1B1B1A1A1A19191B1B1A1A1A1A1A
+1A1B1B1A1A19191A1B1B1B1B1A1A1A1A1A1A1A1A1B1B1B1B1B
+1C1C1C1D1D1D1D1D1D1E1E1F1E1F1F1F1F1F20201F1F212322.
+1C1717191A1917171817151718181718191B19191919191919
+1A1E242825201C1A191A1A19191A1A1A1A1A1C1E201D171619
+1D1F22252A32323041617B8586878C908E8F94979692909293
+93929295999EA0A1A3A4A3A09E9C9C9B99959191939392908F
+8E8F91908C8A89837C76706A645D544E4A4E52504331231E1E
+20201D1C1D1D1D1D1C1C1B1B1B1B1B1B1B1B1A1A1A1A1A1919
+19181818181819191818181817171818161517181716171919
+181718181817181A191B1C1B1B1B1A1919191B1B1B1A1A1A1A
+1A1A1A1A1A1A191919191A1B1919191A1A1A1A1A1A1A1B1B1C
+1D1C1C1C1C1C1C1C1D1D1D1E1F1F1F1F1F1F1F20201F1E2123.
+17171919181717181816161718171718181918181918181919
+1B202629231C18181A1A1A191A1B1B1B1B1C1F211E1816171B
+1E1F2023282A2D374F6A7A7E7E81898D8B8C8C8E90908E8D8C
+8D8E9192969B9EA0A09F9C9999999A99989795939090909192
+9292918F8D8C8986827F7B77726C696661575457584C392A23
+22201E1D1D1D1D1C1B1B1B1B1B1B1B1B1B1B1A1A1A1A191919
+19191918181818181818181817171919171617181817181A19
+1918181818191A1A1A1B1B1B1A1A1A19191A1B1A1A1A1A1A1A
+1B1B1B1B1A1A191919191A1A1A19191A1B1B1B1B1A1A1B1B1B
+1C1C1C1C1C1C1C1C1D1D1E1F1F1F1F1F1F20201E1F20222322.
+1616191A18161717171617171717181817181A19181818191A
+1E2328241C1716191B1A18191B1A1A1B1C1E1F1D191616191D
+1E1F212324262F415C6E7373777C807E7D7F8284827F7F8081
+8283888D92969A9C9B99959496979797989997939092939291
+929393908E8C8B8986817D7B7C7D7E7B726458575B59504232
+27211F1F1F1E1D1C1C1B1B1B1B1B1B1A1A1A1A1A1A1A1A1A19
+19191919181818181818181818181817171817161718191817
+1819181718191A1A1A1B1B1B1A1919191A1B1B1A1A1A1A1A1A
+1A19191A1A19191A1A1A1A1A191A1A1A1A1A1B1B1B1B1C1C1B
+1B1B1B1C1D1D1D1D1D1E1F1F1E1E1E1F20201F1F2121212224.
+1B181819181818171717171617171818171819191818181819
+1B1E22211E19161719191818191B1A1A1B1B1D1D1A1816171A
+1C1E20222223262E3E515F676C6F717371706F707272727272
+75787D84898B8D919496959596949395979A9C9C9997969593
+92949696939190908D88858383878D908D86786B635D585855
+4F423328221F1F1F1E1D1C1C1B1B1B1A1A1A1A1919191A1A1A
+1A1A1919191919181818181818181717181817151719191718
+1919191818191A1A1A1B1B1B1B1B1A191919191A1A19191919
+1A1A1A1A1A1919191A1A1A1A1A1A1A191A1A1B1B1B1C1B1B1B
+1B1B1B1C1C1C1C1D1D1E1E1E1E1D1E1E1F20201F2021212122.
+1916181A191817171818161617181717171919171718181818
+191B1C1D1C19171617181817181B1918191D1E1B1817171718
+1A1C1F21232223253144555E61626667635F5F5E5F62656A6D
+7174787F8284868A9094959595939090949A9E9E9D9B989696
+989A9A97959797938F8E8D8E8F92969A9C978D80706259575D
+615A4B3A2D262220201F1E1D1C1C1B1B1A191A1A19191A1A1A
+1919191A1A191918181817181919161617181817181B1B1C1D
+1C1B1A1918191A1B1B1B1B1B1B1B1B1A1A1919191919191919
+19191A1A1A191919191A1A1A19191919191A1A1B1B1B1C1C1C
+1C1C1C1C1C1D1D1D1D1D1D1D1D1E1E1E1F1F20201F1F202122.
+17181919181717181815161718171718191818181818181818
+1A1B1B1A181716181919171719191717181918161718181719
+1C1F20202021232B3A474F53565A5A555051525051575E6265
+6A71777A7D82878C8E8F9091908F929495989B9E9C9B9A999A
+9A9896979C9D999695969898989B9FA099928D877F776B5B51
+52524B3F332B282723201D1B1B1B1A1A1A1919191A1A1A1919
+191919191919191818171819191617181A1B1C1E2327292C29
+26211E1D1D1C1B1B1B1B1C1C1C1C1C1B191819191919191919
+1919191A1A1A1A1A1A1A1A19191A1A19191A1B1B1B1C1B1B1B
+1C1C1C1C1D1D1D1D1D1D1D1D1D1E1E1E1E1F20211F1E202123.
+1617191A181616181816161818171718191817171919181818
+19181919181716171718171617181816161718171516181817
+191D202020201D202C374044474B4E4D48474647494B4F5459
+5D616A7073777C818486898B8B8F9394939295989B9C9C9998
+969393969BA19F9C9C9B989594959697989592919293928873
+5848403D39322B2523221F1C1B1A1A1A1A1A1B1A1A1A1A1A1B
+1B1B1B1A1A191918181818181919191A1C1E22262A2D323839
+37322D2A292724201E1D1C1C1C1C1C1C1B1918181818191919
+1919191A1A1A1A1A1A1A1A1A1A19191A1B1B1B1A1B1B1B1C1C
+1C1C1D1C1C1C1D1D1D1D1D1D1D1D1E1D1E1F20201F1F202122.
+1B171718191816161717181816161719181617191917171819
+19181819191717171718171717171716161717171616161617
+17191C1F21211C1B202931373B3E4244414040404145484D51
+555A6064696E73777A7B7E838A8D8E8E8D8E9093959797928F
+8F909194989EA2A19C96928E8B898B8E9092959A9E9FA0A19B
+8970543E332E2A24211F1D1C1C1B1A1A1919191A1A1B1B1C1D
+1E1E1E1E1D1C1B191818181819181A1C1F212326272A2A2929
+2929292B2E3030312E2824211F1D1C1B1B1B1B1A1917161819
+191717191A1918191A1A1A1A19191A1A1B1A1A1A1A1A1B1B1B
+1B1C1C1C1C1C1C1C1D1D1D1D1D1D1D1D1E1E1E1F2020201F20.
+17171919181717171717171718171717181717171817171818
+18181818171617181717171717161616171717161616161616
+171A1D1E1E1D1B1A1E242B2F3236393938383A3A3D4145494D
+53585D62686D727577797D8185888888898C90929493908D8A
+8B8E92969A9FA09E99918A84807E8185888C939CA1A4A6A8A4
+9681674A34282322221F1D1D1C1C1C1B1A191A1B1F24282A2B
+2D2C2A2724201D1B1A1A191818191A1C202426282929272625
+23201E1E2124282E3133343028211C1B1C1C1C1B1A18171718
+19181819191919191A1A19191919191A1A1A1A1A1A1A1B1B1B
+1B1B1B1C1C1C1C1D1D1D1D1C1D1D1D1E1E1E1F202020202122.
+1617191A181616181816161718181717181817171718171617
+18181716171717171616161717171616161516161616161616
+17191B1C1C1B1B1B1C1F24292D2F302E2E2F3234373B40464A
+50575C60666B717577787A7E81858687898C8E908F8E8D8B8A
+898B8E94999D9D98938E867A716D70767E858E979EA5ACAEAB
+A2947E644932242225272622201F1F1E1D1C1D2028353F3E38
+333231302D2B2825231F1C1A1919191B1D2024292C2E2D2925
+23211F1D1E1E1E2023292F302E2C27211E1E1D1C1A18181818
+19191919191818181919191919191919191919191A1B1A1B1B
+1B1B1C1C1D1D1D1D1D1D1D1D1D1D1D1E1E1F20201F1F202223.
+1C171819191817171717181717171818161717181817171719
+18161618181716171816151618181616161616161616171717
+161617191A1B1A1A1A1B1C1F23262727272728292C2F343B42
+484E545A5F656B6F7375777C7F7F8286888B8C8C8A87888989
+888686888B919695908B867D70655E5C5F67717D8B98A0A5AB
+AEABA29582694E382A29303433302D2D2C282626262B364043
+3F39332C2726282B2E2F2E2823201C191A1C1E212427282B30
+332E27211F1F1F1F1E1C1E20222424242322211E1C1A1A1A1A
+1A1A191819191919191A1A19191A1A1919191A1A1A1A1A1A1B
+1B1B1B1C1C1D1E1E1D1C1D1D1D1D1D1D1E1F1F20201F1F2122.
+1816191B191717181815161718161515161717171717181817
+16171918161617181715161717171716161615151616161616
+1616171819191A1B19191A1C1D1F212323232425272C323941
+4950555C62676B6E707476777A7D818587898A888481807D7C
+7C7B797B81898B8B87827B716250453F444F5D6B7B8B959CA3
+ABADA697846F5A44322B31373A39393A3C3D3B3228262D3B47
+483F352E28252122252B323635291F1A1B1D1E20222321242E
+36383229221F1E1C1E1F1D1C1B1A1A1C1D1D1D1D1C1A19181A
+1B1A1A19181818181919191A1A19191A1A1A191A1A1A1A1B1A
+1B1B1B1C1C1D1D1D1C1D1C1C1C1D1E1E1E1E1E1F2020201F20.
+1617191A181616171616161616171717161616171818171718
+19181616181816151617161616161616151515151616151617
+1717171819191B1C1B1A1A1A1B1C1E20201F2021242B35404A
+53585D6266696B6E707273767C7F808082868886817C767171
+7576797F84858686837A6B574639312F35415265758189919B
+A19E93877D6E5A45342D323A3C362E2B2F393D383230363E45
+4640382F2A27211E20262F36352D27242422201F2123242629
+2F343530271F1B1D1F21201C1A1A1A1A1A1A1A1A1A1A1A1B1B
+1A1A1A19191919191A1A1A1A1A191A1A1A1A19191A1B1B1B1B
+1B1B1B1C1C1D1D1D1D1C1D1D1D1D1D1E1E1E1F1F1F1F20201F.
+17161819181616171717161616161717171615161717171718
+17161618181615161616151516161616151515161616151516
+1616161617191A191A1A1A1A1A1A1B1B1D1E202123262E3843
+4F585D616566686B6E717375797B7B7B7C808384807C787370
+7071757A8085888A867F72625243362C292A313E4C5B6A7682
+8E91908B847B72655340322D3034332C2423282F363D444540
+3E4248402F262423221F1F242B2E2C29272929282422242628
+292A2D30302B231F1D1F20201E1D1C1B1B1A1A1B1B1B1B1B1B
+1C1B1B19191919191A1A1A1A1A1A1A1A1A1A1A1B1B1B1B1B1B
+1B1B1B1B1C1D1D1D1D1D1D1D1D1D1D1E1E1E1F1F1F1F20201F.
+17151718181715161717171716161617171615161717161718
+18161617171716161616161515161616161515151615151515
+161616161717191A19191A1B1B1A1B1B1C1F232A303536373D
+47545E62605F6065686C6F7274757675767A7E7F7C7876736F
+6E6E6E7076808A908D83776C61554737292121252E39475667
+768083827F7D7A72655544322A282A2B2928262423252C353C
+4146494334241D1F2425211D1F252826212023262727282A29
+27292A2B2C2D2923201D1C1D1E1E1C1B1B1B1A1B1B1B1A1A1A
+1B1B1B1A19191919191919191919191A19191A1A1A1B1B1B1B
+1B1B1B1B1B1C1C1D1D1D1C1C1C1D1D1E1E1E1F1F1F1F202020.
+15151819171515161616161616161717171717171717171717
+17171615171817161516161616161616161615151515161616
+1616161617181A19191A1B1C1D1E1F222936434746423C3A41
+4D565A5B5A5A5D6063676C6F71716F6E717678767271737472
+6F6C6C7079848A8D89827A72695B4937271E1E20252B344355
+646D7274777873695B4E3F332B2727292B2C2A26221F1F2228
+2E3437332A211E202425222021242623201D1D1F23292F312C
+282B30322F2A2623211E1B1C1C1D1D1D1C1C1B1B1B1B1B1B1B
+1B1B1A191919191A1A191A191919191A1A1A1A1B1B1B1B1B1B
+1B1B1C1C1C1D1D1D1D1D1D1D1D1D1D1E1E1F1F201F1F202123.
+15161819171515161616161616171717181816161818171718
+19181616181816161617161616151616161616161616161616
+1717171717171817191B1C1F22262B3543545D5950473F3C3E
+444C535756555657595D63686B6B6867696D6E6C6C6D6F7172
+6F6B6B6D71787E8181807D79756D604E36261E1E2123262B38
+47525A62686C6C655A4C413A342E2928292C2D2C2A25201E1E
+20222526242322212022232220212625221E1C1B1D20242B2F
+2E2C2D3134332E28241F1C1C1C1C1D1D1D1D1D1C1B1B1A191A
+1B1B1A191919191919191A1A191919191A1A1A1A1A1B1A1A1B
+1B1B1B1B1B1C1D1D1E1E1D1D1C1C1D1E1E1F1F2020201F2123.
+1E181617181716161718161515171816161718181616181918
+17171818161617181716161717161616161616161615151516
+17171717181816181B1C1F2329323D49525A6062615E574C42
+3C3B4149525351505154595C5F62646464636261616465676B
+6F706E686364696D6D707578797B7E7F755F432C201F222320
+2228323E4A555C5F5E595046403E3B342C292E32322D2A2824
+201D1B1B1D21252727231E1D1F222223262724201C1B1B1B1F
+23282A2A2C303435302A231E1C1C1C1C1D1D1D1D1D1C1B1B1A
+191A1B1B1A1A1919191A1A19191919191A1A1A1A1A1B1B1A1A
+1A1A1B1B1C1C1C1C1C1C1C1C1D1D1D1E1E1D1E1F1F1F1F2020.
+1715181A191716161818161617181716171919171718191817
+17191816161717171615161616161515161616161616161616
+17171819191A1D2329313B46525B5F5F5F656B6C6A635A4F42
+39373C464C4C4D4E505152555A5F61605E5C5B5B5C5E60656B
+6D6A635B5555595C60666E7780868989816C4F34231E202323
+1F2127303A444C4E4E4D4642403F3B352F2A2C333630292523
+211D1A1B1D22282A26211C1D20242222252725211D1B1B1B1C
+1D202225282A292B2B28231D1B1C1D1D1D1D1D1D1C1C1C1C1C
+1B1A191A1A1A1A1A1A19191919191919191A1A1A1A1A1A1A1A
+1A1B1B1B1B1B1B1C1D1D1D1D1C1C1D1E1E1E1E1F1F1F1F1F20.
+1516191A181616171717161617171717171818181717181818
+17161717181715161717161616151515161616161616161616
+1718191B1F273545535A5B5958595C616A767A7872685C4F40
+36353B414445474A4C4E50535557595A5B5A5856575B626668
+676159504947494D545E6B78838B909288755A412F26222222
+201F22272E363E4345454441403F3B36312E2F32322D272423
+22201C1B1B20252725221F1D1E202322232525231F1D1C1C1C
+1C1C1D1F2022242727231F1D1C1D1E1E1D1D1D1D1C1C1C1C1C
+1B1B191919191919191919191919191A1A1A1919191A1B1A1B
+1B1B1B1B1B1B1B1B1C1C1D1D1D1D1D1D1D1E1E1E1F1F202020.
+18161719191717171717161718171717181717181917171819
+18161718181616171817161616161616151516161616161617
+18191C212C39495861615B5450525A646E7B848580786C5E4F
+433A34363A3F434547484A4C4E5054565757555456595F6468
+6A6760584E443E3D3F4754667782898E8F8A7D6D5A43302522
+2121202021242A32383B3E40404141403B352E2A2C2E2D2926
+2523211D1A1B1D21242625221C1B1E202123242524211D1C1C
+1C1C1B1B1A1C1E212222211F1E1F1F1E1D1D1D1C1C1C1C1C1C
+1C1C1C1A191818191919191A1A1919191A1919191A1A1A1A1B
+1B1B1B1B1B1B1B1B1B1C1D1C1C1C1C1D1D1D1E1F1F1F1F1F20.
+17161718181716161817161718171617181716171818171718
+18181718191716171717161615151515151515151515151718
+1C232E3C464B4F545855504C4B4F59687683888681796E6258
+4D3E312D333B4041404044474B4F525352515152565C62696C
+6B6865625A483730323B495B6A747B838988867F735F463123
+202222211F1F21252B3036383A3E403F3C38332C29292B2A28
+2422211E1B1B1B1D222526231F1C1B1E2224252627231D1C1D
+1E1E1C1A19191A1D1F2222201F1F1F1E1D1D1D1D1D1C1C1B1B
+1C1C1C1B1A19191919191919191919191919191919191A1A1A
+1A1A1A1A1B1B1B1B1B1B1C1C1C1C1D1C1D1D1E1E1E1E1E1F20.
+15161819181616161717171917171718181617191918171718
+18171719191716171717171616161616161515151516171B24
+3647505352514F4B474547484B5362768388857B726B676259
+4B3B2E2B32393C3B393B40454B4E4F4E4D4B4C515963696D6C
+6B6D73715E402B262D3A47535F6A747D8080807C73624B3525
+20222322201F2022262A313536393D3E3C3932292526292924
+1F1E1F1D1A191B1E212424211F1C1C212526262624201D1A1C
+1D1E1D1B1A1A1A1C1F20201E1D1E1E1D1D1D1D1C1C1C1B1B1B
+1C1C1C1B1A19181818181919191919191919191A1A19191919
+1A1A1A1A1B1B1B1C1C1C1B1B1B1B1C1D1D1E1E1F1F1F1F2023.
+15161819181717171717181817171819181617191917161718
+18161618181617181918161617171716161515161616192130
+42505553504D463F3D3E3F3E414B5F7988867F7A746D686661
+594D3D322B2D31353636393E4146484A4A494B4D505860686F
+717273757160442D25272F3A47535F6A73777979767166543D
+292221242524211F1D20282E3134373A3C3B38322823232525
+24201E1B1B1B1B1C1F2122212120201F222627252323221F1C
+1D1D1E1E1C1B1B1B1C1D1E1F1E1D1C1C1C1B1C1B1B1A1A1A1B
+1C1D1D1B1A191818181919191919191919191919191A1A1919
+1A1A1A1A1B1B1B1B1B1B1C1C1C1C1C1D1D1D1E1F1F1F202120.
+1C161618191817161616161616161717171717171717171717
+18171616181816161718171516171717161616161616171E2B
+3C4A52524D46403E3C39393A3B3E4A6177837F79757575736E
+67615A51423229282D32323234393F414346484847474D555D
+646C7377777875644A33252329333E4754606A6E6F70727269
+57412E242122242523201E1E23282C3034393B3A3831292220
+2122211E1B1C1B1B1B1C1D1E1F1F1F1F202122232526242423
+1F1B1B1C1D1E1D1B1B1B1C1C1D1D1D1B1A1A1A1B1B1B1A1A1A
+1A1B1C1C1B1A19191919191818191919191919191919191919
+1919191A1A1A1A1B1B1B1B1B1B1B1B1C1D1D1E1E1E1E1F2020.
+15151819171616171717161616161616161717171717181817
+16171817161718171616171717161615151616161719223343
+4C4B443D383838373738393E47586C797A767373767A7B7872
+6B655E513F2E25252A2E303235383C3D3E4042434444484E56
+5F6972787A7B7A6D52382822252D37414A555F656A6E6F6B61
+513F2E242122232321201F1F2023272B2F313334332D241E1D
+1F201F1C1A1B1A1A1B1C1C1D1C1C1C1E20202124272626251F
+1B1A1A1B1D1E1E1C1B1B1B1B1C1C1B1B1A19191A1A1A1A1A1A
+1A1A1A1A1919191919191919191919181819191A1918191919
+19191A1A1A1A1A1A1A1A1B1B1C1C1C1C1D1D1D1D1E1F1F2021.
+15161819171616171717161616171716161818171718181717
+1718171716171716161616161616161615161616171B283741
+403B35323031333434363B485D727C776E6B6D74797D80817D
+766C615445362C2727292C2F32353838393A3C3D3E3D3F454C
+555F6870777C7E7768523B2B24262D343C454F585F6466625A
+5448392C252221212020211F1F1F2123272A2D2F2F2A231D1C
+1E201F1C1C1C1B1A1B1C1C1B1B1A191B1D1F20222426272620
+1B1A1A1B1C1E1E1E1D1C1B1B1B1B1B1A1A191919191A1A1A19
+191A1A19191A1A1A1A19191919191919191919191919191919
+191A1A1A1B1B1B1B1B1B1B1B1B1C1C1C1D1D1D1E1E1E1F2021.
+18161618181715161717161616161717171717171617171718
+171616181716161717161616151616151516161616181F2C36
+3936302C2C2E3032333540566D7A786E6463676F7981878A88
+81766B5F554A3F32292525272A2E3234343433343536373B3F
+434B56606A72797D7E75634C372A25242A303A444C535A5B57
+524F4940352B231F1F21211F1F1F1F1E1E2123262626221E1C
+1C1E1E1C1D1C1C1B1A1A1A1A1A191919191B1D1F2223242625
+201C1A1A1B1C1E1F1E1D1B1A1A1B1B1B1B1A19191919191919
+1919191A191919191919191919181818181919191919191919
+1919191A1A1B1B1B1B1B1B1B1B1B1C1C1D1E1E1E1E1E1F1F20.
+16161819181616171717171717161616171717171717171818
+1615161717171716161615151515161615151616171C273136
+342F2B2B2D30302E36486071766E625C5C626A75838C908E88
+7F71665D554B41372D242123262A2F313130303132312F3035
+3B434D57606B757C807F74604933241F242A303840484D4E4C
+4B4B4A494133251E1D1F21211E1D1E1D1D1C1D1E1E1E1E1D1C
+1C1C1C1C1C1C1C1B1B1A191A1A191919191A1B1E2122222322
+1E1B1B1A1A1B1C1D1D1D1C1B1B1B1B1B1A1A19181819191919
+19191819181818181819191919181819191919191919191919
+1919191A1A1A1B1B1B1C1C1C1C1C1D1D1D1E1E1E1E1E1F2021.
+14151719181616171717171717171717161616161717171717
+17171616161616161616161616151515161616161B242F3534
+2E2A2A2D2E2E313B586F756D605653535B66728493978F8275
+6D65625C524840372D231F2327292D3032323132312D2A2A2C
+313A444E57646F797F807969523A272023252A31383E424343
+474A52524837261D1D2022201E1F1F1F1E1D1B1B1B1C1C1D1D
+1D1C1B1B1A1B1B1C1C1C1B1B19191919191A1C1D1E20221E1C
+1C1B1B1B1A1B1B1C1E1D1D1C1C1C1B1B1919191A1918181919
+19181918171819181818191819191918181819191919191919
+19191A1A1A1B1B1C1D1D1D1D1C1C1C1D1D1D1E1F1F1F202123.
+15161718171716161616161616161717171717171718171718
+181715161817161617171616151516161515151619202B3436
+312B28292A2B324660716F62554D4A4C505C6B7D8B928D7F71
+696566645B504840382E25222123272B2E30333333322E2A26
+262A2F363F4C56626E787C796F5E4834282222252A2F35393A
+3E454E54534A3B2E251F20201F1E1E1E1F1F1D1D1C1B1B1C1D
+1D1C1B19191A1B1B1B1B1B1A1919181919191A1B1B1C1D1D1D
+1C1B1A1A1B1B1B1C1D1D1E1D1C1B1A1A191919191919181818
+18191818181818171819191717191A18171819191818181819
+19191A1B1A1B1B1B1C1C1C1C1C1C1D1D1D1D1E1E1E1F202020.
+1A161617181716151516171616161616161616161617171717
+1617171716161616161717171716161515161616171A243137
+332D2827282C384A606A65594E474342455265768185847F78
+6F67666562594F4840372E2723222122252A2E32353434322D
+272323262C343E4A56636E7578776E5C442F221E2125282B30
+363D444B4E4E4A443B2D211E1F201E1D1D1E1F1F1D1C1C1D1D
+1D1B1A1919191A1B1A1A1A1A1A1A1818181819191A1B1B1B1C
+1C1C1C1C1B1B1B1B1B1C1C1D1D1D1C1B1B1A19191919191818
+18191919191919181818181818181818181818181819181818
+19191A1A1A1A1A1B1B1C1C1C1D1D1D1D1D1D1D1D1E1E1F1F20.
+15151818171515171717171717171716161616171717181716
+16171816161817161617171616161615161616171C26313532
+2C27272A3343586562574A413B393B42556C797D7C79777672
+6E68655E574F484039332B2623201F20252A2E32353534322C
+252120232A323C4856626A7074736D5C412C211F2023262930
+373D4347484746423A2F251F1E1E1E1D1D1F1F1E1C1C1C1C1C
+1C1A1A19191A1A1A1A1A1A1919191818181819191A1B1B1B1B
+1B1B1B1B1B1B1B1B1B1B1C1C1D1D1C1B1A1A1A1A1919181818
+18181919191919181818181818191919181818181919191919
+19191A1A1A1A1B1B1C1C1C1D1D1D1D1D1E1D1E1E1E1F202021.
+15161818171515161716161616161616171717161616171717
+17171616161717171717161616161616161616171C26303430
+2A26262F4156635D4F453E3934313440587177747071747775
+6F6A645D544A44413D362F282422201F2024292E313333332F
+2A25222124272F3A47535C63686B6A5E4A352821202121252A
+2E363C4040414241403D362A201C1C1D1D1E1F1D1D1D1D1D1C
+1C1A19191A1B1A191A1A1A191918181819191919191A1A1A1A
+1A1A1B1B1B1B1B1B1A1A1B1C1C1C1C1C1B1B1A191918181818
+19191919181818181818181818181818181919191A1A191919
+19191919191A1A1B1B1B1C1C1C1C1D1D1D1D1E1E1E1F202021.
+1A161617181715151617161616161616161717171616161717
+1817151718181615161816151617171717171616181E2B3230
+2B27283041535A54463D3A37332F303B51686F6B686A717677
+736C655E544A4442413D362D2724221F1D1D1F242A2D313332
+2E2A2725222021262E3A4751595F615C4E40342B2421212122
+24292F34383A3A3B3E44484032231C1A1D1E1F1E1D1C1C1D1D
+1C1B1B1919191A1A1A1A1A1A19181819191919191919191919
+1A1A1A1A1A1A1A1A1B1B1B1B1C1C1C1C1C1B1A191919191919
+19191919181818181818181818181818181818181919191919
+1A1919191A1B1B1B1C1C1C1C1C1D1D1D1D1D1E1F1F1F1F2020.
+14151819171615161616161616171717171717171716171717
+18171517181615151617171616161616161616171C262F312C
+262835465251463C363433302D2E394F646B6562656C747976
+70665B534A43413F3B352E292522201E1D1D1E2124282D2F2F
+2D2B292522201F2229303A454E53534C43372E29262523211F
+20252A2F3233343840494C4436271D1A1C1E1E1E1E1E1D1D1C
+1C1A19191A1B1A1A1A1B1A19181819191919191919191A1A1A
+19191A1A1A1A1B1B1B1B1B1B1B1C1C1C1B1B18181919191919
+19191818181818181818181818181818181818191919191919
+1A1A1A1A1A1B1C1C1C1C1C1C1C1C1D1D1D1D1D1E1E1F1F2020.
+15151718161515161616161616171717181816161718171617
+181816161717161616161616161515151616171A222B302C25
+2734444E4C4136312F2D2D2D303C4F6369605A5D68757B776C
+61564F47403C3835302C292622201E1D1D1D1D1E2124282A2B
+2B2A2724211F1F20252B31393F413F3C36302B292724222120
+202225292D31363C4348484035291F1C1C1D1D1D1E1D1C1C1B
+1A191A1B1A1A1A1A1A1A1918181818181919191919191A1919
+191A1A1A1A1A1B1B1B1B1B1B1B1B1B1B1B1B1A191818181818
+18181818181818181818181818181818181919191819191919
+19191A1A1B1B1B1B1B1B1B1C1C1C1D1D1E1E1D1E1E1F202224.
+18161717161516161616161616161717171817161617181717
+17181817161617171716151616161616161616181C232B2C28
+272D373F413C36302C2D2C2B2E384A5C615952556372797469
+5C5149433D38332F2D2A282623211F1E1D1E1E1D1D1D212326
+2727282725222221212225292D313232312F2C2A2927252424
+2221212225292E32393F403F3C352C25201D1C1D1D1D1D1C1B
+1A1919191A1A1A1A1A1A1A191919181818181819191A1A1A1A
+1A1A1A1A1B1B1B1C1C1C1C1B1B1B1B1B1B1A1A1A1918181918
+1818181818181817181818171718191818191A191919181919
+191A1A1A1A1B1B1C1C1B1B1C1C1C1D1E1E1E1E1E1E1F202121.
+18151617171615151616161616161616161717171616171818
+1717171816151617171616161617171616161617191E252928
+23252C34383734302C2B29292D3748585B514C526372766C5E
+514A443E38332F2C2926252422211F1E1D1D1D1D1C1B1B1D20
+2426262726242423222120212225282A2C2B2A2A2929292826
+252321201F2124282E35383A3937332D251E1A1B1C1D1D1D1C
+1B1A19191A1A1A1A1A1A1A1918181818191919191919191919
+1A1A1A1A1A1A1B1B1B1B1B1B1B1B1B1B1B1B1B1A1918181819
+19191818181818181818171719191817181918181819181919
+19191A1A1A1A1B1B1B1B1B1B1C1C1C1C1D1E1E1E1E1F202020.
+14141718181616171717171716161617171717161617171617
+18171517181716161718171516171616161617191C21252523
+25292F31302E2C2B28272932404E5450484B596A726D5F4F44
+3F3B342F2D2A2825232220201F1E1D1D1D1C1C1C1B1B1B1E20
+22242424242424232220202122222425272728292828292926
+242322201F2023272A30323434332F27201C1B1C1D1D1D1D1C
+1B1A19191A1B1A1A1A1A191A191919191919191919191A1A1A
+1A1A1A1A1A1A1B1B1B1B1B1B1B1B1B1B1B1B1A191818181919
+1918181818181918181818181819191819191819191919191A
+1A1A191A1B1B1B1B1B1B1B1B1C1C1D1D1E1E1E1E1F1F202121.
+14151718171515161616161616161616161717171717171717
+17171616161617171716161616161616161616171A1E212321
+2225292C2D2C2B2825252A364652564E43455D71746754443C
+39342E2B28252423201F1D1E1E1D1D1C1C1C1C1C1C1C1C1C1D
+1E202121202124222323222221212020222325262727282926
+24242322201F202125272A2D2F32312C231C1B1C1C1C1C1C1C
+1B1A19191A1A1A1A1A1A191919191919181819191A1A19191A
+1A1A1B1B1B1B1B1B1B1B1B1B1B1B1B1B1A1A1A1A1919191919
+19191818191919191918181818181818181818181919191919
+19191919191A1B1B1B1B1B1B1B1C1D1D1E1F1E1E1F20202022.
+19131416181614141616161616161616171616161617171717
+161616161616161616161616161616161616161617181B1E1F
+202224272B2B292826252B35424E514C4548586A6D614F4037
+342F2C282523211F1D1D1E1E1D1C1B1B1B1A1A1B1B1C1C1C1D
+1D1E1E1F20201E2021212122222120201F2021212224252627
+272624222121211F1E1F232627292B2926201A1A1C1D1C1C1C
+1B1A191A1A19191A1A1A1919181818181819191A1A19191919
+1A1A191A1A1B1B1B1B1B1A1A1A1A1A1A1A1A1A191919191818
+18181818181818181817171918161718191817181919181819
+19191919191A1A1A1B1C1B1B1B1B1B1C1D1E1E1E1E1F1F2020.
+15141617161515151515151616161616161616171716161616
+161616171717171616161616161515151616161717181A1B1E
+202224282B2C2926272C3742494B494A53656B62524238322E
+2A262423201E1C1C1C1C1C1B1B1A1A1A1A1A1A1A1B1C1C1C1D
+1E1E1E1E1F1F1F202020202122212020202020202122232424
+2424232321201F1F1E202021222424211F1C1A1B1C1C1C1C1C
+1B1B1A1A1A1B1A1A191919191919191919191919191919191A
+1A1A1A1A1A1A1B1B1B1B1B1A1A1A1A1A1A1A19191919191818
+19191818181818181818181818181818181818191919191A1A
+19191919191A1B1B1B1B1B1B1C1C1D1D1D1E1E1E1F20202021.
+14151718161414151516161616161616161616161616161616
+161717171716161616161616161515151616161617181A1B1C
+1F2125282B2B29252935424747464D5D6D6F5E4738312D2925
+2321201E1C1B1B1A19191A1A1B1B1A1A191A1A1B1C1D1D1E1F
+1F1F1F201F1E1E1F2020201F2021201F1F201F1E1F21222222
+2222222120201F1F1F1F1F1F1F1F1E1D1C1C1C1C1C1C1C1B1B
+1B1B1B1B1A1A1A191919191919191919191A1A1919191A1A1A
+1A1A1A1A1A1B1B1B1B1B1B1A1A1A1A1A1A1919191919191818
+181818191919181818181818181818181818181819191A1A19
+19191A1A1A1A1A1A1B1B1B1C1C1D1D1D1D1E1E1F2020202023.
+19161616171715131415161616161616161616161616161717
+17171716161616161716161616151616161616161717181A19
+1A1C1F2226292926262F3A4143444B5D6F715F47362E2B2724
+201E1D1D1C1B1A19191A1B1B1C1C1C1C1B1B1B1C1D1D1E1F1F
+1F1F20201F1F1F1F1F20201F1F21211F1F20201F1F20201F20
+2120202121201F1F1F1F20201E1D1E1F1E1C1C1C1C1D1D1C1C
+1C1B1B1B1B1A1A1A1919191919191919191919191919191919
+1A1A1A1A1A1A1A1A1B1B1B1B1B1A1A1A1A1A1A1A1B1B1A1919
+1818191A191918181818181919191918181818181819191919
+1919191A1A1A1A1B1B1B1B1B1C1C1D1D1D1D1E1F1F1F1F1F21.
+16141617171514141516161616161616161616161616161717
+17161616161616161616151516161615161616161616171819
+18191C21262827242730393F41485A6C6F5C46372E2A27231F
+1D1C1C1C1B1919191A1B1C1D1D1E1D1C1C1C1D1D1E1F1F2020
+1F2021211F2021202021222221212121212121212121202020
+202020201F2021201E1E20201E1D1E1F1F1E1D1C1C1C1C1C1C
+1C1C1B1B1A191919191919191918181818181919191A1A1A1A
+1A1B1A1A19191A1A1A1A1B1B1B1B1B1A1A1A1A1A1A1A191919
+19191919191818181818181818181818181818181818191919
+1919191A1A1A1A1A1A1B1B1B1B1C1C1C1D1D1D1E1F1F1F1F20.
+14151617161515141515151515151516161615151616161717
+17171616161616161616161616161615151515151516161818
+181A1D222424252830353A404B5B655E49352C292623201D1B
+1B1B1B1B1B1A1A1B1C1D1D1D1D1C1C1C1C1C1D1E1F1F202120
+20212120202121202122222323242322212122222222212020
+20202020202020202020201F1F1F1F1F1E1D1C1C1C1C1C1C1C
+1B1B1A1A1A1B1B1A1A1A1919191919191919191919191A1A1A
+1A1A1A1A1A1A1A1A1B1B1B1B1B1B1A1A1A1A1A191919191919
+19191919191919191818181818181818181919191919191919
+1919191A1A1A1A1B1B1B1C1C1C1C1D1D1D1D1E1F1F1F1F2021.
+16151718171514151515151516161615151616161616161616
+17161616161616161616161616161616161616161616161718
+1918191D202221242A32373F4B565A503F31292623211F1C1A
+1B1B1B1C1B1B1B1B1B1B1C1D1D1D1D1C1C1D1E1E1E1E1F201F
+1F20201F202220202122222324242323222221222221212121
+212121212020202020202020201F1F1F1F1F1F1D1C1C1C1C1C
+1C1C1B1B191A1A1B1B1B1A191919191919191919191919191A
+1A1A1A1A1A1A1A1A1A1A1B1B1B1B1B1A1A1A1A1A19191A1A1A
+191919191A1A191919191919191818181819191A1919181919
+1A1A1A1A191A1A1A1A1B1B1B1B1B1C1C1C1D1E1E1E1E1E1E20.
+18141517181615151516161615151616161616161616161616
+16161717171717161616161616161615151515161616161717
+171718191C1F2123252A343F4B524E413227252523201D1B1A
+1B1B1C1C1C1C1B1B1B1B1C1C1C1D1C1B1B1B1C1C1C1D1E1F1F
+1F1F1F1F20201E202120202122222222222121212020202120
+202020202020202020211F1F1F201F1E1D1E1D1D1D1C1C1C1C
+1C1C1B1B1A1A1A1A1A1A1A1A19191919191919191919191A1A
+1A1A1A1A1A1A1A1A1A1B1B1B1B1A1A1A1A1A1A1A1A1A1A1A19
+19191919191919191818191919181818181919191919191919
+191A1919191A1A1A1B1B1B1B1B1C1C1D1D1D1D1D1D1E1E1D1F.
+15141718171515161616151515161616161616161616161616
+16161616161616161616161616161616161616161616161616
+1616181A1C1D1F22252D3B474941362B2523211F1D1B1B1A1A
+1A1B1B1B1B1B1B1B1B1B1C1C1C1B1B1A1A1A1B1C1D1D1E1F1F
+1E1E1E1E1F1F1F20201F202121212121202020201F1F202120
+201F2020202020202020201F1F1F1F1E1D1D1D1D1D1D1D1D1C
+1C1B1B1A1B1A1A1A1A1A1A1919181919191919191919191919
+191A1A1A1A1A1B1B1B1B1B1A1A1A1A1A1B1B1A1A1A1919191A
+19191919191919191919191919191818181919191919191919
+19191919191A1A1B1B1B1B1B1B1B1C1C1C1D1D1D1D1E1E1F21.
+13151717171616141516161616161616161616161616161717
+17161617181615161716161616161616161616161616161616
+161617191B1D1D1E222B39423F3428212122211E1B1A1A1A1A
+1A1B1C1C1C1B1B1A1A1A1B1B1B1B1A1A191A1B1B1B1C1D1E1E
+1E1E1E1E1E1F20201F202121202021202020201F1F1F20201F
+2021202021201F20211F1E201F1E1D1E1E1D1D1D1C1C1C1C1C
+1B1B1A1A1A1A1A1B1B1A19191919191919191919191A19191A
+1A1A1A1A1A1A1A1B1B1B1B1B1A1A1A1A1B1A1A1A1A19191919
+19191919191818181819191919191818181819191919191919
+1A1A191A1A1B1B1C1B1B1B1B1B1B1C1C1C1D1D1D1D1E1E2022.
+1A171616171817141417161615161616161717171717171717
+17171716161616161616161616161616161616161515151516
+1616161718191A1A1B1E242E36362E241F1F201F1C1B1A191A
+1B1B1A1A1B1B1B1B1A1A191A1B1A1A1A1919191A1A1B1B1C1D
+1D1E1F1F1E1F20201E1E2021201F20211F2021201F20211E1F
+21211F1F20201F1F2020201F1E1E1F1F1F1E1D1C1C1C1C1C1C
+1C1C1B1B1B1A1A1A1A1A1A1A1919191919191919191A1A1919
+1A1A1A19191A1A1A1A1A1A1B1B1B1A1A1A1A1A1A1A1A1A1919
+191A1A19191919191919191919191918181919191919181919
+1919191A1A1A1A1B1B1B1B1B1A1A1B1C1D1D1D1D1D1D1E1E1F.
+15151719181817171717161616161617171717171716171717
+17171717171717171717171616161617171616161516161616
+161616161717191A191C242E322D2621201E1D1D1C1A1A191A
+1B1B1B1B1B1B1B1B1B1B1A1A1A1A1A1A1A1A1A1A1B1D1D1D1E
+1E1E1F20201E1F21211F1F2021211F1F2121202020201F2021
+1F20211F1F2021201E1F20201F1E1E1E1E1E1D1D1D1D1D1C1C
+1D1C1C1B1B191A1B1B1B1B1B1A1A19191919191A1A19191A1A
+191A1A1A1A1A1A1A1A1B1B1B1B1B1A1A1A1B1B1A1A1919191A
+1A1A191A191919191A1A191919191A19181818191919191919
+19191A1A1A1A1B1B1C1B1B1B1A1B1C1C1D1D1D1D1E1E1F1F20.
+1415181B1B1816151516161616161617171717171717171616
+16161617171717171717161616161616161616161616161616
+16161717171818181B212A2E2C28221D1C1D1C1B1A1919191A
+1B19191A1A1A1A1A1A1A1A1A1A1A191919191A1B1C1C1E1E1F
+1F1F20201F2022201F20201F1F2021211F2021201F20201F1F
+21211E1E1F201F1E1E1F1F201F1E1D1E1E1D1C1C1D1D1C1C1C
+1C1C1C1A1A191A1B1B1B1B1A19191919191919191919191919
+1A1A1A191919191A1A191A1B1B1B1B1B1B1B1A1A1A1A1A1A1A
+1A1A1A19191A1A1A1A1A1B1A1A1A1919191919191919191A1A
+191919191A1B1B1C1C1B1B1B1B1B1C1D1E1E1D1D1D1E1F2022.
+16151718181615161616151516161616161717171717171616
+16161717171717161616161616161616161616161615151616
+16161717181816171A1D232A2C2A25211E1B1C1C1B1B1A191A
+1B1B1B1B1A1A1A1919191A1A1919191919191A1A1B1B1C1D1E
+1F1F2021202222212020202020212021212121212120202020
+202021202020202020201E1F1F201F1E1E1D1E1D1D1D1D1D1D
+1D1C1C1B1B1A1A1A1B1B1A1A1A191919191A1A1A19191A1A1A
+1A1A1A1A1A191A1A1A1B1B1A1A1B1B1B1B1B1B1A1A1A1A1A1B
+1B1A1A19191A1A1A19191A1A19181919191919191919191919
+1A1A1A1A1A1A1A1B1B1B1B1B1B1B1B1C1C1C1C1D1D1D1E1F20.
+17151618181615151616161616161617171616161616171717
+17161617171616161616161616161616161616161616161616
+1617171718171718191B22282C2A26211D1C1C1C1B1A19191A
+1A1A1A1A1A1A191919191A191919191919191A1B1B1B1C1D1E
+1F1F20202021211F202120202020212121212121202020201F
+1F2021201F2021201F1F20201F1F1F1E1E1D1D1D1D1D1D1D1D
+1C1C1C1C1C1B1B1A1B1A1A1A1919191A1A1A1A1A1A1A1A1A1A
+1A1A1A1A1919191919191A1A1B1B1B1B1B1B1A1A1A1A1A1A1A
+1A1A1A1A191A1A1A191A1A1A1A191919191919191919191919
+1A1A1A1A1B1B1B1B1B1B1B1B1B1B1B1B1C1C1C1D1D1D1D1F20.
+13141718161415151516161615161616161616161616171717
+17161717171616161616161616161616161616161616161616
+16161717171819181A1F25292926211E1C1B1B1A1A1A1A1A1A
+1A1A1A1A1A1A19191A1A1A1A1A1A1A1A1A1A1B1B1C1D1E1F20
+1F1E1F20201F1F202020202020202021201F2021202020201F
+21212020202020202020202020201F1E1E1D1D1D1D1D1D1D1C
+1C1C1C1C1C1B1B1A1A191919191919191919191919191A1A1A
+1A1A1A1A1A1919191A1A1A1A1B1B1B1B1B1A1A1A1A1A1A1A1A
+1A1A1A1A1A1A1A1A1A1A1A1A1A19191919191919191A1A1A1A
+1A1B1B1B1B1B1B1B1B1B1A1A1B1C1C1C1C1C1D1D1D1D1E2023.
+13151717161515141516161516161617171716161617171717
+17171717171717171616161616161616161616161616161716
+16171717181817191C1F222525221F1D1A1B1B1B1B1A1A1919
+1A1A1A1A191919191A1B1A1A1A1A1A1A1A1A1A1B1B1D1F2020
+1E1D1F20201E2021202020201F2021202021202021211F2021
+202020212121212020201F1F20201F1D1D1E1F1E1D1D1C1D1D
+1D1D1C1C1B1B1A1A1A1A1A1A1A1A1A1919191919191919191A
+1A1A1A1A1A19191B1B1A1A1A1A1B1B1B1B1A1A1A1A1A1A1A1A
+1A1A1A1A1A1A1A1A1A1A1A1A1A19191919191919191A1A1A1A
+1B1B1A1B1B1B1C1C1C1B1B1B1A1B1B1C1C1D1E1E1D1D1E1F21.
+1D161415161615141414151515161616161616161616161616
+16171717181615161718161517171616161616161615151616
+161616161617181817191C1D1F2324201D1B19191A1B1B1A1A
+1A1A1A1A1A1919191A1B1B1A1A19191A1A1A1A1B1B1C1D1D1E
+1F1F1F1F1F20201E1F2122211F1F21211F2021212020201F20
+212020212121222220202020212020201E1D1E1E1C1C1C1D1D
+1D1C1C1B1B1B1B1B1B1A191919191A1919191919191919191A
+1A1919191919191A1A1A1A1A1A1A1A1A1A1A1A1A1919191A1A
+191A1A1A1A1B1B1B1A1A1A1A1A1A1A19191919191A1A191A1B
+1C1C1C1C1C1B1B1B1B1C1C1C1B1B1A1B1B1B1C1D1D1D1E1E1E.
+13131517171615151415151616161616161616161616161717
+17171717171717171717161616161616151515151516161616
+16161617181818181A191B1D1F20201D1C1A1A1A1A1A1A1A1A
+1A1A1A1A1A1A1A1A1A1B1B1A1A1A1A1A1A1B1B1C1D1D1E1E1E
+1F1F1F1F20211F212221202121212021212121212121202020
+202121212121202020202120201F1F1F1F1E1D1C1C1D1D1D1D
+1C1C1B1B191A1B1B1A1A1919191919191919191919191A1A1A
+1A1A1A1A19191A1A1A1A1A1A1A1A1A1A1919191919191A1A1A
+1A1A1B1B1B1A1A1A1A1A1A1A1A1A1A1A1A1A191A1A1A1A1B1A
+1A1B1B1B1B1B1B1C1D1D1D1C1B1B1A1B1C1C1D1D1D1E1E1F21.
+12131517161515151516161616161616161616161616161718
+17161618181616171717161616161515151515151516171515
+161617191918191A1A1A1B1C1D1E1E1D1B191818191A1B1A1A
+1A19191A1A1A1A1A1A1B1B1B1C1B1B1B1B1B1C1D1E1E1E1E1F
+1F1F1F20201F20212120202121202121202121212121212020
+2020202020202020201E1F20201E1D1E1F1E1D1D1D1D1D1D1C
+1B1B1B1A1A1B1B1B1A1A1919191A1A1A1A1A1A1919191A1A1A
+1A1A1A1A1A1A1A1A1B1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A
+1A1A1A1B1B1B1A1A1A1A1A1A1A1B1B1B1A1A1A1A1B1B1B1B1B
+1B1B1B1B1C1C1D1D1D1D1C1C1C1C1C1C1C1D1D1D1D1D1E1F21.
+14121416161514141415151616161616161616161616161717
+18171616171716151617161615151515151515151517171615
+16161617171717181919191A1B1C1D1D1C1A1918191A1B1B1A
+1A1A1A1A1B1C1C1B1A1A1A1A1B1B1B1A1A1A1B1C1D1D1E1E1E
+1E1E1F20201E1F212120202121202121202021212020202020
+201F2020201F2020201F1F20201E1D1E1F1E1D1D1D1D1E1E1D
+1B1B1A1A1B1B1B1B1A1A1A1A1A1A1A19191A1A1A19191A1A1A
+1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A
+1A1A1A1A1A1B1B1A1A1A1A1B1B1B1B1B1B1A1A1B1B1B1B1B1B
+1B1B1B1B1C1C1C1D1D1D1D1C1C1C1C1C1C1C1C1D1D1D1E1E1F.
+* End of file "mona.dat"
diff --git a/support/graphbase/multiply.w b/support/graphbase/multiply.w
new file mode 100644
index 0000000000..15ea0a1567
--- /dev/null
+++ b/support/graphbase/multiply.w
@@ -0,0 +1,314 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{MULTIPLY}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GATES}
+@* Introduction. This demonstration program uses graphs
+constructed by the |prod| procedure in the |gb_gates| module to produce
+an interactive program called \.{multiply}, which multiplies and divides
+small numbers the slow way (i.e., by simulating the behavior of
+a logical circuit, one gate at a time).
+
+The program assumes that \UNIX\ conventions are being used. Some code in
+sections listed under `\UNIX\ dependencies' in the index may need to change
+if this program is ported to other operating systems.
+
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+To run the program under \UNIX, say `\.{multiply} $m$ $n$ [|seed|]', where
+$m$ and $n$ are the sizes of the numbers to be multiplied, in bits,
+and where |seed| is given if and only if you want the multiplier
+to be a special-purpose circuit for multiplying a given $m$-bit
+number by a randomly chosen $n$-bit constant.
+
+The program will prompt you for two numbers (or for just one, if the
+random constant option has been selected), and it will use the gate
+network to compute their product. Then it will ask for more input, and so on.
+
+@ We use the data types \&{Vertex}, \&{Arc}, and \&{Graph} defined
+in |gb_graph|.
+
+@f Vertex int
+@f Arc int
+@f Graph int
+
+@ Here is the general layout of this program, as seen by the \Cee\ compiler:
+@^UNIX dependencies@>
+
+@p
+#include "gb_graph.h" /* the standard GraphBase data structures */
+#include "gb_gates.h" /* routines for gate graphs */
+@#
+@<Global variables@>@;
+@<Handy subroutines@>@;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{
+ @<Declare variables that ought to be in registers@>;
+ @<Obtain |m|, |n|, and optional |seed| from the command line@>;
+ @<Make sure |m| and |n| are valid; generate the |prod| graph |g|@>;
+ if (seed<0) /* no seed given */
+ printf("Here I am, ready to multiply %d-bit numbers by %d-bit numbers.\n",
+ m,n);
+ else {
+ g=partial_gates(g,m,0,seed,buffer);
+ if (g) {
+ @<Set |y| to the decimal value of the second input@>;
+ printf("OK, I'm ready to multiply any %d-bit number by %s.\n",m,y);
+ } else { /* there was enough memory to make the original |g|, but
+ not enough to reduce it; this probably can't happen,
+ but who knows? */
+ printf("Sorry, I couldn't process the graph (trouble code %d)!\n",
+ panic_code);
+ return -9;
+ }
+ }
+ printf("(I'm simulating a logic circuit with %d gates, depth %d.)\n",
+ g->n,depth(g));
+ while(1) {
+ @<Prompt for one or two numbers; |break| if unsuccessful@>;
+ @<Use the network to compute the product@>;
+ printf("%sx%s=%s.\n",x,y,z);
+ }
+}
+
+@ @<Make sure |m| and |n| are valid; generate the |prod| graph |g|@>=
+if (m<2) m=2;
+if (n<2) n=2;
+if (m>999 || n>999) {
+ printf("Sorry, I'm set up only for precision less than 1000 bits.\n");
+ return -1;
+}
+if ((g=prod(m,n))==NULL) {
+ printf("Sorry, I couldn't generate the graph (not enough memory for %s)!\n",
+ panic_code==no_room? "the gates": panic_code==alloc_fault? "the wires":
+ "local optimization");
+ return -3;
+}
+
+@ To figure the maximum length of strings |x| and |y|, we note that
+$2^{999}\approx5.4\times10^{300}$.
+
+@<Glob...@>=
+Graph *g; /* graph that defines a logical network for multiplication */
+int m,n; /* length of binary numbers to be multiplied */
+long seed; /* optional seed value, or $-1$ */
+char x[302], y[302], z[603]; /* input and output numbers, as decimal strings */
+char buffer[2000]; /* workspace for communication between routines */
+
+@ @<Declare variables...@>=
+register char *p,*q,*r; /* pointers for string manipulation */
+register int a,b; /* amounts being carried over while doing radix conversion */
+
+@ @<Obtain |m|, |n|, and...@>=
+@^UNIX dependencies@>
+if (argc<3 || sscanf(argv[1],"%d",&m)!=1 ||
+ sscanf(argv[2],"%d",&n)!=1) {
+ fprintf(stderr,"Usage: %s m n [seed]\n",argv[0]);
+ return -2;
+}
+if (m<0) m=-m; /* maybe the user attached |'-'| to the argument */
+if (n<0) n=-n;
+seed=-1;
+if (argc>3 && sscanf(argv[3],"%d",&seed)==1 && seed<0)
+ seed=-seed;
+
+@ This program may not be user-friendly, but at least it is polite.
+
+@d prompt(s)
+ {@+printf(s);@+fflush(stdout); /* make sure the user sees the prompt */
+ if (fgets(buffer,999,stdin)==NULL) break;@+}
+@d retry(s,t)
+ {@+printf(s);@+goto t;@+}
+
+@<Prompt...@>=
+step1: prompt("\nNumber, please? ");
+for (p=buffer;*p=='0';p++) ; /* bypass leading zeroes */
+if (*p=='\n') {
+ if (p>buffer) p--; /* zero is acceptable */
+ else break; /* empty input terminates the run */
+}
+for (q=p;*q>='0' && *q<='9';q++) ; /* check for digits */
+if (*q!='\n') retry(
+ "Excuse me... I'm looking for a nonnegative sequence of decimal digits.",
+ step1);
+*q=0;
+if (strlen(p)>301)
+ retry("Sorry, that's too big.",step1);
+strcpy(x,p);
+if (seed<0) {
+ @<Do the same thing for |y| instead of |x|@>;
+}
+
+@ @<Do the same...@>=
+step2: prompt("\nAnother? ");
+for (p=buffer;*p=='0';p++) ; /* bypass leading zeroes */
+if (*p=='\n') {
+ if (p>buffer) p--; /* zero is acceptable */
+ else break; /* empty input terminates the run */
+}
+for (q=p;*q>='0' && *q<='9';q++) ; /* check for digits */
+if (*q!='\n') retry(
+ "Excuse me... I'm looking for a nonnegative sequence of decimal digits.",
+ step2);
+*q=0;
+if (strlen(p)>301)
+ retry("Sorry, that's too big.",step2);
+strcpy(y,p);
+
+@ The binary value chosen at random by |partial_gates| appears as a
+string of 0s and 1s in |buffer|, in little-endian order. We compute
+the corresponding decimal value by repeated doubling.
+
+If the value turns out to be zero, the whole network will have collapsed.
+Otherwise, however, the |m| inputs from the first operand
+will all remain present, because they all affect the output.
+
+@<Set |y| to the decimal value of the second input@>=
+*y='0';@+*(y+1)=0; /* now |y| is |"0"| */
+for (r=buffer+strlen(buffer)-1;r>=buffer;r--) {
+ /* we will set |y=2y+t| where |t| is the next bit, |*r| */
+ if (*y>='5') a=0,p=y;
+ else a=*y-'0',p=y+1;
+ for (q=y;*p;a=b,p++,q++) {
+ if (*p>='5') {
+ b=*p-'5';
+ *q=2*a+'1';
+ } else {
+ b=*p-'0';
+ *q=2*a+'0';
+ }
+ }
+ if (*r=='1') *q=2*a+'1';
+ else *q=2*a+'0';
+ *++q=0; /* terminate the string */
+}
+if (strcmp(y,"0")==0) {
+ printf("Please try another seed value; %d makes the answer zero!\n",seed);
+ return(-5);
+}
+
+@* Using the network. The reader of the code in the previous section
+will have noticed that we are representing high-precision decimal
+numbers as strings. We might as well do that, since the only
+operations we need to perform on them are input, output, doubling, and
+halving. In fact, arithmetic on strings is kind of fun, if you like
+that sort of thing.
+
+Here is a subroutine that converts a decimal string to a binary string.
+The decimal string is big-endian as usual, but the binary string is
+little-endian. The decimal string is decimated in the process; it
+should end up empty, unless the original value was too big.
+
+@<Handy subroutines@>=
+decimal_to_binary(x,s,n)
+ char *x; /* decimal string */
+ char *s; /* binary string */
+ int n; /* length of |s| */
+{@+register int k;
+ register char *p,*q; /* pointers for string manipulation */
+ register int r; /* remainder */
+ for (k=0;k<n;k++,s++) {
+ if (*x==0) *s='0';
+ else { /* we will divide |x| by 2 */
+ if (*x>'1') p=x,r=0;
+ else p=x+1,r=*x-'0';
+ for (q=x;*p;p++,q++) {
+ r=10*r+*p-'0';
+ *q=(r>>1)+'0';
+ r=r&1;
+ }
+ *q=0; /* terminate string |x| */
+ *s='0'+r;
+ }
+ }
+ *s=0; /* terminate the output string */
+}
+
+@ @<Use the network to compute the product@>=
+strcpy(z,x);
+decimal_to_binary(z,buffer,m);
+if (*z) {
+ printf("(Sorry, %s has more than %d bits.)\n",x,m);
+ continue;
+}
+if (seed<0) {
+ strcpy(z,y);
+ decimal_to_binary(z,buffer+m,n);
+ if (*z) {
+ printf("(Sorry, %s has more than %d bits.)\n",y,n);
+ continue;
+ }
+}
+if (gate_eval(g,buffer,buffer)<0) {
+ printf("??? An internal error occurred!");
+ return 666; /* this can't happen */
+}
+@<Convert the binary number in |buffer| to the decimal string |z|@>;
+
+@ The remaining task is almost identical to what we needed to do
+when computing the value of |y| after a random seed was specified.
+But this time the binary number in |buffer| is big-endian.
+
+@<Convert the binary number in |buffer| to the decimal string |z|@>=
+*z='0';@+*(z+1)=0;
+for (r=buffer;*r;r++) { /* we'll set |z=2z+t| where |t| is the next bit, |*r| */
+ if (*z>='5') a=0,p=z;
+ else a=*z-'0',p=z+1;
+ for (q=z;*p;a=b,p++,q++) {
+ if (*p>='5') {
+ b=*p-'5';
+ *q=2*a+'1';
+ } else {
+ b=*p-'0';
+ *q=2*a+'0';
+ }
+ }
+ if (*r=='1') *q=2*a+'1';
+ else *q=2*a+'0';
+ *++q=0; /* terminate the string */
+}
+
+@* Calculating the depth. The depth of a gate network produced by |gb_gates|
+is easily obtained in one pass. An input gate or a constant has depth~0;
+every other gate has depth one greater than the maximum of its inputs.
+
+This routine is more general than it needs to be for the circuits output
+by |prod|. The result of a latch is considered to have depth~0.
+
+Utility field |u.i| is set to the depth of each individual gate.
+
+@d dp u.i
+
+@<Handy...@>=
+int depth(g)
+ Graph *g; /* graph with gates as vertices */
+{@+register Vertex *v; /* the current vertex of interest */
+ Vertex *u, *uu; /* additional vertices being examined */
+ register Arc *a; /* the current arc of interest */
+ int d; /* depth of current vertex */
+ if (!g) return -1; /* no graph supplied! */
+ for (v=g->vertices; v<g->vertices+g->n; v++) {
+ switch (v->typ) { /* branch on type of gate */
+ case 'I': case 'L': case 'C': v->dp=0;@+break;
+ default: @<Set |d| to the maximum depth of an operand of |v|@>;
+ v->dp=1+d;
+ }
+ }
+ @<Set |d| to the maximum depth of an output of |g|@>;
+ return d;
+}
+
+@ @<Set |d| to the maximum depth of an operand of |v|@>=
+d=0;
+for (a=v->arcs; a; a=a->next)
+ if (a->tip->dp>d) d=a->tip->dp;
+
+@ @<Set |d| to the maximum depth of an output of |g|@>=
+d=0;
+for (a=g->outs; a; a=a->next)
+ if (!is_boolean(a->tip) && a->tip->dp>d) d=a->tip->dp;
+
+@* Index. Finally, here's a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/queen.w b/support/graphbase/queen.w
new file mode 100644
index 0000000000..43687e4dfa
--- /dev/null
+++ b/support/graphbase/queen.w
@@ -0,0 +1,51 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{QUEEN}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+@* Introduction. This is a short demonstration of how to generate and
+traverse graphs with the Stanford GraphBase. It creates a graph
+with 12 vertices, representing the positions on a $3\times4$ rectangular
+board; two positions are considered adjacent if you can get
+from one to another by a queen move. Then it prints a description
+of the vertices and their neighbors, on the standard output file.
+
+An ASCII file called \.{queen.gb} is also produced. Other programs
+can make a copy of the queen graph by calling |restore_graph("queen.gb")|.
+You may find it interesting to compare the output of |queen| with
+the contents of \.{queen.gb}; the former is intended to be readable
+by human beings, the latter by computers.
+
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Arc int
+
+@p
+#include "gb_graph.h" /* we use the |gb_graph| data structures */
+#include "gb_basic.h" /* we test the basic graph operations */
+#include "gb_save.h" /* and we save our results in ASCII format */
+@#
+main()
+{@+Graph *g,*gg,*ggg;
+ g=board(3,4,0,0,-1,0,0); /* a graph with rook moves */
+ gg=board(3,4,0,0,-2,0,0); /* a graph with bishop moves */
+ ggg=gunion(g,gg,0,0); /* a graph with queen moves */
+ save_graph(ggg,"queen.gb"); /* generate an ASCII file for |ggg| */
+ @<Print the vertices and edges of |ggg|@>;
+}
+
+@ @<Print the vertices and edges of |ggg|@>=
+if (ggg==NULL) printf("Something went wrong (panic code %d)!\n",panic_code);
+else {
+ register Vertex *v; /* current vertex being visited */
+ printf("Queen Moves on a 3x4 Board\n\n");
+ printf(" The graph whose official name is\n%s\n", ggg->id);
+ printf(" has %d vertices and %d arcs:\n\n", ggg->n, ggg->m);
+ for (v=ggg->vertices; v<ggg->vertices+ggg->n; v++) {
+ register Arc *a; /* current arc from |v| */
+ printf("%s\n", v->name);
+ for (a=v->arcs; a; a=a->next)
+ printf(" -> %s, length %d\n", a->tip->name, a->len);
+ }
+}
+
+@* Index.
diff --git a/support/graphbase/queen_wrap.ch b/support/graphbase/queen_wrap.ch
new file mode 100644
index 0000000000..a91680cc43
--- /dev/null
+++ b/support/graphbase/queen_wrap.ch
@@ -0,0 +1,91 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+It's a demonstration "change file", which converts the demonstration program
+called "queen" into a similar demonstration program called "queen_wrap".
+
+Change files make it easy to modify CWEB source programs without
+touching the master files, thereby remaining totally compatible with
+all other users. Anybody can make whatever modifications they like in
+change files, but everybody is supposed to leave the master files
+intact. Please also leave the present file intact, so that it remains
+as a useful demonstration of the change-file idea.
+
+The format of change files is simple: First comes a line that begins with @x,
+then comes a line that is a verbatim copy of some line from the master file,
+then comes zero or more additional lines that should match the subsequent
+lines of the master file. Then you say @y, and then you give replacement
+lines for everything between @x and @y in the master file. Then you say @z.
+All changes must occur in the order of replaced text in the master file,
+and must be uniquely identifiable by the first line that follows @x.
+
+Optional comments may follow @x, @y, or @z, and may occur outside
+of @x-@y-@z groups. In fact, you are now reading such an optional comment.
+
+@x change the program title and delete the copyright notice
+\def\title{QUEEN}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+@y
+\def\title{QUEEN\_WRAP}
+\let\maybe=\iffalse % print only sections that change
+\def\botofcontents{\vskip 0pt plus 1filll \parskip=0pt
+ This program was obtained by modifying {\sc QUEEN} in the
+ Stanford GraphBase.\par
+ Only sections that have changed are listed here.\par}
+@z
+
+@x here we modify the introductory remarks of section 1
+An ASCII file called \.{queen.gb} is also produced. Other programs
+can make a copy of the queen graph by calling |restore_graph("queen.gb")|.
+You may find it interesting to compare the output of |queen| with
+the contents of \.{queen.gb}; the former is intended to be readable
+by human beings, the latter by computers.
+@y
+Unlike an ordinary chessboard, the board considered here ``wraps around''
+at the left and right edges, so that it is essentially a cylinder.
+It does not, however, wrap around at the top and bottom; double wrapping
+would, in fact, allow a lowly bishop to move from any position to any other,
+in two different ways.
+
+An ASCII file called \.{queen\_wrap.gb} is also produced. Other programs
+can make a copy of the graph by calling |restore_graph("queen_wrap.gb")|.
+You may find it interesting to compare the output of |queen_wrap| with
+the contents of \.{queen\_wrap.gb}; the former is intended to be readable
+by human beings, the latter by computers.
+@z
+
+@x changes to the code of section 1
+ g=board(3,4,0,0,-1,0,0); /* a graph with rook moves */
+ gg=board(3,4,0,0,-2,0,0); /* a graph with bishop moves */
+ ggg=gunion(g,gg,0,0); /* a graph with queen moves */
+ save_graph(ggg,"queen.gb"); /* generate an ASCII file for |ggg| */
+@y we add wraparound
+ g=board(3,4,0,0,-1,2,0); /* a graph with rook moves and wrapping */
+ /* we set |wrap=2| because only the second coordinate wraps */
+ gg=board(3,4,0,0,-2,2,0); /* a graph with bishop moves and wrapping */
+ ggg=gunion(g,gg,0,0); /* a graph with queen moves and wrapping */
+ save_graph(ggg,"queen_wrap.gb"); /* generate an ASCII file for |ggg| */
+@z
+
+@x change to the code of section 2
+ printf("Queen Moves on a 3x4 Board\n\n");
+@y
+ printf("Queen Moves on a Cylindrical 3x4 Board\n\n");
+@z
+
+A change file is usually much shorter than the master file, but the
+present one is an exception because the master file itself is short.
+You can use many different change files with the same master file.
+
+To run the queen_wrap program on a UNIX system, you can say
+ ctangle queen.w queen_wrap.ch queen_wrap.c
+and then compile and go. (The .w is optional in the first argument to ctangle;
+the .ch is optional in the second; the .c is optional in the third.)
+
+The C compiler and debugger will refer to appropriate lines of the original
+source file queen.w and/or the change file queen_wrap.ch when you are
+troubleshooting. You need never look at the file queen_wrap.c that was
+output by ctangle, although the compiler and debugger will want to see it.
+
+To obtain a TeXed documentation, you can say
+ cweave queen queen_wrap
+ tex queen
+ rm queen.tex
diff --git a/support/graphbase/roget.dat b/support/graphbase/roget.dat
new file mode 100644
index 0000000000..2bd92a03e3
--- /dev/null
+++ b/support/graphbase/roget.dat
@@ -0,0 +1,1038 @@
+* File "roget.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* Cross-references in Roget's Thesaurus, 1879
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 1033,184851240)
+1existence:2 69 125 149 156 166 193 455 506 527
+2inexistence:1 4 167 192 194 368 458 526 527 771
+3substantiality:4 323 325
+4unsubstantiality:3 34 194 360 432 452 458 527
+5intrinsicality:6 82 162 182 228 562 657
+6extrinsicality:5 60 227
+7state:8 247 336 457
+8circumstance:6 7 156
+9relation:10 11 12 18 25 46 78 204 474
+10irrelation:9 26 47 86 90
+11consanguinity:171
+12correlation:153
+13identity:14 18 23 29 108 506
+14contrariety:13 32 225 723
+15difference:19 26 30 84 145 475
+16uniformity:17 25 85
+17non-uniformity:16 84 86 161 263
+18similarity:11 13 16 19 20 25 108 506 533 566
+19dissimilarity:15 17 18 78 86 145
+20imitation:21 23 556 566 611
+21non-imitation:20
+22variation:17 145 286 298
+23copy:18 20 24 108 557 566
+24prototype:23
+25agreement:9 16 18 26 29 85 184 500 661 724 729
+26disagreement:10 25 86 723 728
+27quantity:28 199
+28degree:27 33 74 240
+29equality:13 18 25 30 534
+30inequality:15 29 35 36
+31mean:71 643 658 790
+32compensation:29 31 185 733 790 972
+33greatness:34 35 37 53 55 75 86 106 109 178 199 201 506 651 654 657 887
+34smallness:33 38 54 107 165 200 202 655 658
+35superiority:33 36 37 42 201 217 310 656 657 663 892
+36inferiority:34 35 38 202 658 666 893
+37increase:38 39 76 201 312
+38decrease:37 40 179 202 208 313 674
+39addition:37 40 46 91 235 307
+40subduction:38 39 208 806
+41adjunct:39 42 68 91
+42remainder:41 656 660 668 799
+43decrement:
+44mixture:45 46 51 62 64 226 235 449
+45simpleness:44 47 667
+46junction:39 47 48 49 51 75 766 921
+47disjunction:46 52 73 76 233 260 337 765 803
+48vinculum:46 212 221 222 767
+49coherence:46 50 328 359
+50incoherence:47 49 51 328
+51combination:44 46 52
+52decomposition:47 51 76 320 668
+53whole:54 55 75 90 657
+54part:34 47 53 59 78 188 211 803
+55completeness:53 56 654 656 665 744
+56incompleteness:55 73 205 311 470 655 666 689 744 745
+57composition:51 58 59 79
+58omission:47 57 470 910
+59component:54 60 795
+60extraneousness:6 58 59 227
+61order:62 63 64 72 74 143
+62disorder:26 44 61 63 64 86 178 225 226 248 255 322 356
+63arrangement:64 563 608 641 688
+64derangement:44 62 63 225 265
+65precedence:35 66 67 121 180 241 287 657
+66sequence:36 65 72 122 242 288
+67precursor:68 121 523 524 688
+68sequel:67
+69beginning:67 70 129 130 158 238 241 300 688 691
+70end:69 147 238 242 368 744
+71middle:31 229 235 643
+72continuity:73
+73discontinuity:47 72 143 144 205 235
+74term:28
+75assemblage:33 76 106 297 651 711 727 741 909
+76dispersion:47 75 81 298 803
+77focus:229 297 651
+78class:18
+79inclusion:57 78 80 236
+80exclusion:58 79
+81generality:31 76 82 627
+82speciality:81 86 182
+83rule:24 84 85 506 627 712
+84multiformity:83
+85conformity:16 24 25 83 86 627
+86unconformity:85 480 887
+87number:
+88numeration:89 477
+89list:563
+90unity:46 47 51 91 910
+91accompaniment:39 41 90 125
+92duality:93
+93duplication:94 108 675
+94bisection:93
+95triality:
+96triplication:97
+97trisection:96
+98quaternity:
+99quadruplication:100
+100quadrisection:99
+101five:102
+102quinquesection:101
+103plurality:90 104 105 106
+104fraction:54 103
+105zero:4 103 194
+106multitude:75 107 109 654
+107fewness:34 106 142
+108repetition:20 141 143 415 416 627 675
+109infinity:117
+110time:55 111 112 114 115 118 139 698
+111neverness:110
+112period:114 143
+113contingent duration:114
+114course:110 112 113 127
+115diuturnity:116 117 127 133 138 155 282
+116transientness:115 118 137 154 281 699
+117perpetuity:118 141
+118instantaneity:117 137 699
+119chronometry:120
+120anachronism:119 140
+121priority:67 122 127 137 287 523
+122posteriority:68 121 126 288
+123present time:118 124
+124different time:123
+125synchronism:110 118
+126futurity:127 137 157 519 522
+127preterition:121 126 128 129 171 517
+128newness:129 132 675
+129oldness:69 127 128 133 674
+130morning:131
+131evening:130
+132youth:133
+133age:129 132 135
+134infant:135
+135veteran:134 171
+136adolescence:381 382
+137earliness:118 130 138 281 520 697 699
+138lateness:137 140 282 519 651 698
+139occasion:25 137 140 661 692 700 801 806
+140intempestivity:26 120 137 138 139 470 662 698
+141frequency:108 142 627
+142infrequency:107 141
+143periodicity:144 321
+144irregularity:73 143
+145change:64 146 149 151 154 192 225 277 620
+146permanence:145 155 272 619
+147cessation:70 127 148 299 368 639
+148continuance:108 117 147 617
+149conversion:247 277 282
+150reversion:143 226 284 290 675 676
+151revolution:167 557
+152substitution:153 533 774
+153interchange:152 733 811
+154changeableness:116 145 155 321 322 618 621
+155stability:46 115 146 154 191 619
+156eventuality:8 127 157 161 838
+157destiny:126 156 161 166 485 519 613
+158cause:159 160 166 169 171 182 222 635
+159effect:70 158
+160attribution:158 159 161 171 534
+161chance:160 481 613 636
+162power:163 164 173 176 180 752 759
+163impotence:162 165 655 660 719 747
+164strength:162 165 176 675 704 759
+165weakness:132 134 163 164 670 698
+166production:158 167 173 688 744 791
+167destruction:151 166 308 369 660 674 771
+168reproduction:166 675
+169producer:170 705
+170destroyer:167 169 369 678 996
+171paternity:11 172
+172posterity:171
+173productiveness:166 174 659
+174unproductiveness:163 173 660
+175agency:158 180 642 646 647 695
+176energy:162 164 177 178 400 401 616 697 701 841
+177inertness:146 176 272 618 619 698 843
+178violence:62 179 322 356 515 754 842 880 904
+179moderation:38 165 178 698 755 764 766 843
+180influence:162 181 222 657 752
+181absence of influence:10 163 177 180
+182tendency:183 285 646 659 722
+183liability:680
+184concurrence:25 185 500 722 724 727
+185counteraction:14 32 184 284 721 723 734 766
+186space:109 187 188 189 193 194 205
+187inextension:34 186
+188region:186 196 240
+189place:186 190 196 198 251
+190situation:189 285 566
+191location:192 193 196 307 675
+192displacement:64 191 277 300 304 910
+193presence:76 186 191 194 453
+194absence:2 173 193 300
+195inhabitant:60 191 193 196 380
+196abode:166 188 191 193 195 198 230 239 1022
+197contents:198 228
+198receptacle:196 222 239 259 279 651
+199size:33 53 75 109 186 200 201
+200littleness:34 38 54 199 202 208 210 337 658
+201expansion:35 37 199 202 257
+202contraction:36 38 200 201 208 236 608 674 766
+203distance:76 186 204
+204nearness:75 203 206 293 297
+205interval:47 56 73 194 206 235 266 267
+206contiguity:49 204 205 240
+207length:72 208 477 589
+208shortness:200 202 207 584 608
+209thickness:186 199 201 210
+210thinness:200 201 202 205 209 212
+211layer:212 230
+212filament:211 263
+213height:35 55 199 210 214 217 230 251 257 312 314
+214lowness:213 220 259 315
+215depth:205 216 259 317
+216shallowness:215
+217summit:35 70 213 218 230
+218base:217 222
+219verticality:220
+220horizontality:211 219 258
+221pendency:48 222
+222support:46 48 218 221 722
+223parallelism:224 243
+224obliquity:219 223 250 252
+225inversion:14 244
+226crossing:62 255
+227exteriority:6 228 230 234
+228interiority:5 197 227 229 235 236 259 307
+229centrality:71 77 297
+230covering:196 211 231 232 363 364 433 540 542 732
+231lining:230
+232investment:230 233 254 864 899 1021
+233divestment:230 232
+234circumjacence:235 236 237 238
+235interjacence:234 307
+236circumscription:232 234 239 766
+237outline:239 254
+238edge:267
+239inclosure:198 236 237 732 767
+240limit:
+241front:67 242
+242rear:241 288
+243laterality:204 244
+244contraposition:225 243
+245dextrality:246
+246sinistrality:245
+247form:166 237 248 336 457
+248amorphism:62 64 247 250
+249symmetry:29 229 250 862
+250distortion:201 208 210 224 249 863
+251angularity:219 224 264 265
+252curvature:224 250 253 254 255 286
+253straightness:226 252 255 285 330
+254circularity:234 252 255 256 318
+255convolution:62 226 254
+256rotundity:254
+257convexity:201 213 258 259 260 314 670
+258flatness:220 257 262
+259concavity:198 205 252 257 266 267 350
+260sharpness:47 261 263 269 742
+261bluntness:260
+262smoothness:220 258 263 339
+263roughness:249 260 262
+264notch:
+265fold:
+266furrow:205
+267opening:205 259 268 357 358 642
+268closure:202 267 270 721
+269perforator:270 742
+270stopper:230 269
+271motion:154 272 273 274 277 283 286 291
+272quiescence:147 155 191 193 196 222 271 299 411 681 698 702
+273journey:274 275 277 279 281 289
+274navigation:273 276 280 300
+275traveller:276
+276mariner:275
+277transference:76 153 192 291 292 800
+278carrier:279 280
+279vehicle:280
+280ship:279 741
+281velocity:118 178 271 282 310 697 699
+282slowness:138 281 698
+283impulse:178 260 284 291 731 742 993
+284recoil:283 332 416
+285direction:182 286
+286deviation:252 285 298 321 644
+287precession:65 67 121 241 288 310
+288following:66 122 242 287 637
+289progression:273 277 281 290 673
+290regression:150 284 289 294 674
+291propulsion:283 292 304 319 741 742
+292traction:291
+293approach:126 157 294 637
+294recession:284 290 293 300 638
+295attraction:296
+296repulsion:283 295
+297convergence:75 77 298
+298divergence:47 76 286 297
+299arrival:191 300 301 455 681 744
+300departure:299 302 304 458 638
+301ingress:235 267 302 303 307 357 642
+302egress:267 300 301 306 355 357 358 642 686
+303reception:235 304 305 307
+304ejection:283 291 302 303 356 771 993
+305food:196 303 306 401 652 857 978 980
+306excretion:302 304 305 668
+307insertion:235 267 301 308 317 344 371
+308extraction:302 304 307
+309passage:267 273 274 277 301 302 357 642
+310transcursion:311 312 656
+311shortcoming:56 310 470 655 666 745 747
+312ascent:224 313 316
+313descent:312 315
+314elevation:257 315 648
+315depression:220 259 314
+316leap:317 322 857
+317plunge:316 344
+318circuition:255 644
+319rotation:320
+320evolution:225 319
+321oscillation:618
+322agitation:62 154 356
+323materiality:324 650
+324immateriality:323 459
+325world:477
+326gravity:327
+327levity:326
+328density:49 329 330
+329rarity:259 327 328 341
+330hardness:331
+331softness:330
+332elasticity:284 333
+333inelasticity:331 332
+334tenacity:49 335 619
+335brittleness:334
+336texture:263
+337pulverulence:34 202
+338friction:337 339
+339lubrication:262 338 362 363
+340fluidity:341 342 355
+341gaseity:340 343 360
+342liquefaction:340 343 392
+343vaporization:341 342
+344water:345 346 355
+345air:341 344 356 360
+346moisture:302 344 347 352
+347dryness:346
+348ocean:349 355
+349land:213 257 325 348 797
+350gulf:351 651
+351plain:220 350
+352marsh:353
+353island:352
+354stream:256 355 356
+355river:268 302 304 344 356 721
+356wind:178 355
+357conduit:267 358 642
+358air-pipe:267 356 357
+359semiliquidity:49 346 352 360
+360bubble:359 431 435
+361pulpiness:362
+362unctuousness:339 361 363
+363oil:
+364resin:230
+365organization:336 366 376 377
+366inorganization:365
+367life:1 157 166 168 305 368 675 697
+368death:70 147 367 369 613 670 856
+369killing:672 742 993 996
+370corpse:371
+371interment:856
+372animality:164 373
+373vegetability:372
+374animal:200 278 375
+375vegetable:374 379
+376zoology:377
+377botany:376 379
+378cicuration:239 369 379 766 767
+379agriculture:196 378 857
+380mankind:195 893
+381man:134 136 382 921
+382woman:134 136 381 921
+383physical sensibility:384 502 839
+384physical insensibility:383 698 840
+385physical pleasure:222 386 402 404 408 422 844 846 862 974
+386physical pain:322 385 419 845 993
+387touch:
+388sensations of touch:389
+389numbness:384 388
+390heat:391 392 397 432
+391cold:390 393
+392calefaction:231 232 342 390 393 394 396
+393refrigeration:328 391 392
+394furnace:395
+395refrigeratory:394
+396fuel:363 392 432
+397thermometer:
+398taste:399 402
+399insipidity:398
+400pungency:400 401 403 405
+401condiment:400
+402savouriness:403
+403unsavouriness:402 405 847
+404sweetness:405
+405sourness:404
+406odour:407
+407inodorousness:406
+408fragrance:409
+409fetor:408 668
+410sound:411 416 592
+411silence:272 410 413 593 597
+412loudness:413 416 419 420 421
+413faintness:412 422 595
+414snap:415
+415roll:108 414 416
+416resonance:413 417 419
+417non-resonance:416
+418sibilation:419
+419stridor:418 420 421 423
+420cry:412 421 592
+421ululation:420
+422melody:416 419 423 424 609 846
+423discord:419 422
+424music:422 425 609 856 857
+425musician:422 424 426 609
+426musical instruments:
+427hearing:416 428
+428deafness:427
+429light:390 392 430 431 432 454
+430darkness:429 431 432 435 440
+431dimness:360 429 430 435 438 456
+432luminary:363 390 429 433 562
+433shade:230 430 432
+434transparency:435 436
+435opacity:360 431 434
+436semitransparency:360 434
+437colour:438 568
+438achromatism:437 439
+439whiteness:440
+440blackness:429 430 439 441
+441gray:440 442
+442brown:441
+443redness:444
+444greenness:443
+445yellowness:446
+446purple:445
+447blueness:448
+448orange:447
+449variegation:
+450vision:193 451 452 453 455 465 467 469 510 519
+451blindness:450 452 540
+452dimsightedness:432 451 454 457 542
+453spectator:193 450 683
+454optical instruments:457
+455visibility:450 456 457 467 537
+456invisibility:431 435 450 451 455 538 540
+457appearance:227 247 452 455 458 537 562 899
+458disappearance:300 304 457 564
+459intellect:324 460 461 510 527 713
+460absence of intellect:459 511
+461thought:462 463 467 468 471 517 527 710
+462incogitancy:461 468 493 511
+463idea:457 464 496 526 527
+464topic:9 461 463 471
+465curiosity:466 471 519 544
+466incuriosity:465 840
+467attention:459 461 464 468 469 470 519 537 562
+468inattention:467 470 518 520 698 883
+469care:61 461 467 470 506 510 519 522 667 679 688 697 881 959
+470neglect:62 467 468 469 507 518 520 668 689 698 745 840 880 950
+471inquiry:461 465 472 473 486 487 545 637 677 710 719 728 780
+472answer:158 471 492 525 534 562 563
+473experiment:471 690
+474comparison:9 204 533
+475discrimination:476 477 510 867
+476indiscrimination:470 475 486
+477measurement:31 88 200 240 251 326 345 390 562
+478evidence:473 479 480 489 500 537 547 562 563 787
+479counter-evidence:167 478 490 548 632 957
+480qualification:86 478 481 486 526 830
+481possibility:25 161 482 486
+482impossibility:26 481 484 488 497 876 887
+483probability:161 457 478 484 496 519 523
+484improbability:142 483 497
+485certainty:155 486 489 496 506 613
+486uncertainty:154 430 456 471 473 485 497 503 531 532 618 636 877
+487reasoning:25 471 488 489 491 548 735
+488intuition:10 487 493 507 509 511 550 556
+489demonstration:473 478 485 487 490 491
+490confutation:167 489
+491judgment:467 471 492 493 496 500 510 536 622
+492discovery:491 506 541 791
+493misjudgment:485 491 494 495 498 507 511 619 714
+494overestimation:495 561 839 897
+495underestimation:470 494 873 898 950 954
+496belief:463 483 485 491 497 498 500 526 547 549 875 1005
+497unbelief:486 496 499 501 507 548 620 1011
+498credulity:493 496 499 557 559 619 1006
+499incredulity:497 498 969 1006 1011
+500assent:25 184 478 501 547 563 614 724 775 777
+501dissent:26 497 500 548 615 620 639 728 779 849 1006
+502knowledge:69 463 491 492 496 503 539 541 549 572 713
+503ignorance:486 502 531 540
+504scholar:502 505 512 553
+505ignoramus:503 504 513 553 559 716
+506truth:1 5 18 83 478 485 492 507 555 959 1005
+507error:4 452 486 488 493 498 506 509 515 527 535 550 556 557 558 559 714\
+ 747 1006
+508maxim:463 491 496 509 712
+509absurdity:62 488 508 511 529 561
+510wisdom:450 459 469 475 502 511 522 530 661 688 697 713 717 867 881
+511folly:459 468 486 488 493 498 509 510 515 619 658 660 662 714 860 880
+512sage:504 513 715 1016
+513fool:505 512 516 559 716
+514sanity:515
+515insanity:486 511 514 854
+516madman:513 527 854
+517memory:518 539 563 657 900 938
+518oblivion:468 517 564 840 937
+519expectation:137 157 465 469 483 496 520 522 523 688 875 887
+520inexpectation:86 118 468 493 519 521 887
+521disappointment:493 887
+522foresight:137 469 493 510 519 523 641 683 688 881
+523prediction:67 524 641 683 1014
+524omen:67 523 562 683
+525oracle:536 1016
+526supposition:461 481 496 517 641
+527imagination:4 360 432 452 461 507 515 516 561 606 875
+528meaning:5 29 506 529 530 533 534 537 538 539 547 555
+529unmeaningness:509 528 531 538
+530intelligibility:506 528 531 534 537
+531unintelligibility:62 64 430 435 456 486 503 529 530 532 534 535 538 540\
+ 545 887
+532equivocalness:528 540 545 556 859
+533metaphor:578
+534interpretation:29 158 491 492 528 530 535 562 572 574
+535misinterpretation:507 534 556 561
+536interpreter:525
+537manifestation:455 467 492 530 538 541 543 555 718
+538latency:450 456 492 531 537 539 540 541 545 597 682
+539information:273 467 502 528 530 534 537 538 540 541 543 544 546 547 549\
+ 551 562 563 606 718
+540concealment:456 470 486 531 538 539 541 542 545 556 557 597 717 910
+541disclosure:455 492 537 539 542 543 544
+542ambush:540 541 557 681 682
+543publication:537 539 544
+544news:539 541 543 545 606
+545secret:471 503 531 538 540 544 719
+546messenger:539 773
+547affirmation:478 485 496 500 526 537 539 548 563 783 904
+548negation:470 480 490 497 501 547 620 624 771 776 779
+549teaching:69 467 496 534 539 550 551 627 673
+550misteaching:488 507 531 540 549 556 557
+551learning:471 502 539 549 553 614 697 713
+552teacher:24 536 549 553 554 710 1018
+553learner:551 552
+554school:
+555veracity:506 541 547 556 557 718 959
+556falsehood:20 507 527 535 540 555 557 558 560 561 717 872 960
+557deception:20 23 432 452 507 542 550 556 558 560 629 717 808 960 1014
+558untruth:527 540 542 556 557 561 577 632
+559dupe:498 507 513 557 560 874
+560deceiver:556 557 559 611 716 809
+561exaggeration:201 494 509 527 556 589 852 901
+562indication:24 82 467 473 477 478 523 524 534 539 543 563 566 657 683 684\
+ 748 762
+563record:89 127 478 517 539 562 564 565 606 651 787 900
+564obliteration:562 563
+565recorder:127 606
+566representation:18 20 23 567 568 569 570 606 611
+567misrepresentation:566
+568painting:364 429 437 566 864
+569sculpture:23 566
+570engraving:603
+571artist:
+572language:502 504 562 575 578 581 594
+573letter:602 603
+574word:504 506 572 575 576 578 579
+575neology:129 532 533 574 577 859
+576nomenclature:534 562 575 577
+577misnomer:575 576
+578phrase:508 533 534 581
+579grammar:554 572 580
+580solecism:579
+581style:578 594
+582perspicuity:506 530 537 583
+583obscurity:486 507 531 532 575 582
+584conciseness:202 208 585 608
+585diffuseness:108 584 589 596
+586vigor:587
+587feebleness:585 586
+588plainness:587 589
+589ornament:533 588 590 591 864
+590elegance:589 591
+591inelegance:575 580 589 590 872
+592voice:410 412 420 422 593
+593aphony:413 419 423 592 597
+594speech:539 585 589 595 596 598 600 601
+595stammering:413 575 593 594
+596loquacity:108 509 585 594 597 600 909
+597taciturnity:411 540 593 594 596
+598allocution:554 594 599 600
+599response:472 598
+600interlocution:594 596 601 711 909
+601soliloquy:600
+602writing:23 478 562 563 573 603 605
+603printing:543 570 573 602 605
+604correspondence:546 605
+605book:502 543 604
+606description:89 539 541 547 563 565 566 608
+607dissertation:461 471 487 534
+608compendium:75 202 208
+609poetry:424 592 610
+610prose:609
+611drama:20 562 566
+612will:158 613 614 616 622 625 635 756 763
+613necessity:152 612 626 636 645 759 764 1014 1015
+614willingness:331 500 612 615 713 763 777 780 837 882
+615unwillingness:282 501 548 613 614 618 619 638 723 759 779 883 884 885
+616resolution:155 330 491 617 618 619 622 635 691 697 701 878
+617perseverance:108 146 148 155 164 697 701
+618irresolution:145 154 321 331 486 616 620 621 698 877 879
+619obstinacy:155 177 330 493 612 616 617 620
+620tergiversation:154 548 618 619 639 771 970
+621caprice:86 618
+622choice:491 562 612 616 623 624 629 663 665 882
+623absence of choice:29 613 618 622
+624rejection:304 548 622 693 779
+625predetermination:626 635 641
+626spontaneity:612 613 625
+627habit:5 16 85 108 549 551 628 713 869
+628desuetude:86 627 693 714
+629motive:160 283 291 292 557 614 630 631 635 710 777 780 841 846 1015
+630absence of motive:615 621 629 636
+631dissuasion:286 615 619 629 721 766 767 781 884
+632plea:488 537 556 557 558 953 957
+633good:634 659 663 673 677 749 801 844 846 951
+634evil:167 633 664 674 678 750 808 845 847 931 1001
+635intention:182 528 614 616 625 629 636 637 641 691 882
+636non-design:161 481 486 613 626 633 635
+637pursuit:69 178 281 288 374 471 473 635 638 640 691 695 699 780
+638avoidance:284 294 300 615 624 637 639 686 696 723 910
+639relinquishment:147 620 628 771 772 799
+640business:637 691 695 697 764 811 945
+641plan:61 63 152 158 305 527 557 613 625 688 707 717
+642method:196 267 277 357 643 646 707
+643mid-course:31 71 285 644
+644circuit:286 318 643
+645requirement:613 655 756 780 882
+646instrumentality:175 641 647 648 659 722
+647means:175 641 642 646 648 651 652 681 722 817
+648instrument:48 221 222 260 269 274 279 283 314 319 646 742 797 798
+649substitute:152 774
+650materials:305 392 647 689 742 797
+651store:75 198 652 685 819
+652provision:305 647 651 653 722 814 834
+653waste:76 302 652 660 694 792 835
+654sufficiency:31 33 55 166 173 355 651 655 656 820 886 973
+655insufficiency:34 56 163 311 470 647 653 654 666 821 823 825 836
+656redundance:39 42 75 201 310 355 561 585 651 653 654 835 974
+657importance:5 33 35 142 180 367 562 641 658 659 663 890
+658unimportance:31 34 36 163 165 494 495 511 529 627 657 660 668 883 950
+659utility:166 173 182 635 640 646 660 661 663 673 692 695 722 928
+660inutility:108 129 140 163 174 482 653 655 656 658 659 668 674 689 698\
+ 714 747
+661expedience:25 85 139 659 662
+662inexpedience:26 140 656 660 661 719 721
+663goodness:35 506 633 659 664 665 666 671 673 831 846 875 924 951 964 968
+664badness:167 369 634 658 660 662 663 666 670 672 674 678 694 714 847 876\
+ 925 931 952 965 967 993
+665perfection:35 55 217 659 663 666 674 688 744 951
+666imperfection:31 34 56 73 165 205 250 311 655 664 665 674 689 865
+667cleanness:668
+668uncleanness:306 409 660 667 674 974 982
+669health:670 671 673 675 677
+670disease:165 257 368 511 515 556 660 669 672 674 876
+671salubrity:25 659 672 675 677
+672insalubrity:26 369 671 678
+673improvement:37 38 63 164 289 312 314 640 667 674 675 677 722
+674deterioration:38 165 167 202 290 294 313 368 660 664 666 668 673 680 703\
+ 808 876 965
+675restoration:63 108 115 168 676 677 687 704 807 851
+676relapse:290 674 675
+677remedy:222 671 673 675 678 721 851
+678bane:634 664 672 677 847 931 996 1001
+679safety:236 469 665 680 681 683 685 686 688 732 766 875 881 959
+680danger:154 167 183 520 557 679 682 683 684 689 876 877 878 880 927
+681refuge:222 239 542 679 682 686 721 732 767 910
+682pitfall:538 542 557 681
+683warning:469 523 539 562 684 881 927
+684alarm:683
+685preservation:469 651 679 687 732 734 1015
+686escape:267 300 638 642 679 681 687 765
+687deliverance:675 765
+688preparation:29 63 65 69 222 247 469 519 522 549 551 627 641 652 689 713\
+ 720 722
+689non-preparation:56 158 233 470 520 626 641 650 660 688 778
+690essay:473 701
+691undertaking:69 158 616 640 697 783 785
+692use:175 646 659 693 694
+693disuse:167 304 628 660 692 799
+694misuse:653 692 835
+695action:175 640 641 691 696 697 701 705 707 744 899
+696inaction:147 167 272 470 638 639 695 698 702
+697activity:137 139 176 281 289 467 469 510 616 617 695 698 699 701
+698inactivity:50 138 147 177 179 272 282 618 619 638 696 697 700 840
+699haste:118 137 178 281 697 700
+700leisure:282 696 699 702
+701exertion:176 616 617 697 702
+702repose:147 696 698 701 704
+703fatigue:698 704 858
+704refreshment:164 675 703 851
+705agent:646 648 761 773 774
+706workshop:
+707conduct:640 641 642 695 708
+708management:709 711 752
+709director:539 708 710 711 760 773 774 988
+710advice:539 552 629 631 683 708 780 988
+711council:987
+712precept:508 756
+713skill:139 502 510 527 557 633 641 692 697 701 707 714 715 717 746 881
+714unskilfulness:140 282 468 470 498 503 507 511 513 549 621 660 698 713\
+ 716 745 747 880
+715proficient:504 560 716 809 1016
+716bungler:560 715
+717cunning:520 540 556 557 558 641 713 718
+718artlessness:547 717 959 966
+719difficulty:62 255 481 482 486 545 619 720 721 876
+720facility:262 331 339 481 713 719 722 763 775 851
+721hindrance:147 268 270 482 631 639 660 674 677 697 719 722 723 725 732\
+ 746 766 767 776
+722aid:182 222 305 469 646 647 659 663 721 724 726 924
+723opposition:14 26 32 185 721 722 724 734 735 737 766
+724cooperation:46 51 184 500 722 723 727 729
+725opponent:726 908
+726auxiliary:725 761 907
+727party:46 75 171 724
+728dissension:26 62 322 471 501 548 725 729 735 737 906 915
+729concord:25 184 500 724 727 728 736 738 905 914
+730defiance:757 878 927
+731attack:167 283 732 993
+732defence:222 236 239 469 542 679 681 685 721 731 734 742
+733retaliation:12 32 153 284 734 938 958
+734resistance:62 164 617 619 723 731 733 737 740 757 878 952
+735contention:487 723 728 736 737 857 918
+736peace:272 729 735 738 905
+737warfare:735 738 743
+738pacification:179 729 737
+739mediation:738 773 790
+740submission:331 500 758 843 896
+741combatant:276 760
+742arms:283 291 651 732
+743arena:77 611
+744completion:55 70 299 617 688 745
+745non-completion:56 311 470 744
+746success:35 289 692 713 721 744 747 749 764 791 901
+747failure:163 167 290 311 313 482 507 520 521 655 660 714 740 745 746 750 825
+748trophy:562 890 894 899 900
+749prosperity:746 750 820 846
+750adversity:167 634 747 749 821 847
+751mediocrity:179 643
+752authority:708 711 753 754 756 759 760 762 770 774 775 943 986
+753laxity:470 752 755 757 763 944 985
+754severity:755 759 902 925 933
+755lenity:179 754 932
+756command:622 752 759 780 786 984
+757disobedience:62 730 734 758 779 789 985
+758obedience:331 740 757 761 764 788 903
+759compulsion:613 615 754 766
+760master:709 761 796 892 986
+761servant:705 758 760 767 773 903
+762sceptre:562 767 894
+763freedom:612 720 721 764 765 775 832
+764subjection:183 740 746 752 754 758 761 763 766 767
+765liberation:46 47 686 687 763 766 991
+766restraint:46 236 721 759 764 765 767 769 776
+767prison:48 239 721
+768keeper:552 769
+769prisoner:766 768
+770commission:760 771 773 774 775
+771abrogation:167 304 548 620 770
+772resignation:548 639 771 799
+773consignee:546 709 761 774 818
+774deputy:709 760 773
+775permission:500 612 614 755 763 770 776 777 984 991
+776prohibition:548 721 766 775 781 985
+777consent:500 614 775 779 783 951
+778offer:779 780 801 813
+779refusal:501 548 619 624 771 777 778
+780request:756 778 781 1012 1015
+781deprecation:776 780
+782petitioner:
+783promise:478 547 784 785 787
+784release:763 765 783
+785compact:478 739 773 783 790 811
+786conditions:480 785
+787security:478 563 783 785 804
+788observance:506 758 789 959
+789non-observance:564 757 788 960
+790compromise:32 785
+791acquisition:75 166 633 651 792 801 802 806 808 820 827 994
+792loss:653 791 794 799 806 876
+793possession:791 797 798
+794exemption:194 793
+795participation:724
+796possessor:793
+797property:349 648 752 763 793 796 801 817 820 822 823 827
+798retention:48 651 769 793 799
+799non-retention:42 304 639 693 772 798
+800transfer:152 153 277 791 801 811
+801giving:778 800 802 824 826 832 994
+802receiving:303 791 801 806 827
+803apportionment:795
+804lending:787 805
+805borrowing:804 808 823
+806taking:40 208 303 304 305 791 792 798 807 808
+807restitution:675 791 806
+808stealing:557 806
+809thief:
+810booty:
+811barter:152 153 785
+812purchase:805 813 824 826
+813sale:778 787 811 812 814
+814merchant:727 773 812 813
+815merchandise:197 651
+816mart:651
+817money:787 797 820 822 823 824 827 828 830
+818treasurer:814
+819treasury:198 651
+820wealth:654 791 797 817 819 821 827
+821poverty:817 820 823 825
+822credit:823
+823debt:805 822 825
+824payment:32 817 818 825 826 994
+825non-payment:655 808 821 823 824 832
+826expenditure:801 812 824 827 829 994
+827receipt:791 797 802 806 826 994
+828accounts:88 817 818
+829price:823 828 830 994
+830discount:829
+831dearness:832
+832cheapness:831
+833liberality:826 834 924
+834economy:651 833 836
+835prodigality:831 833 836
+836parsimony:835 963
+837affections:838 914
+838feeling:156 322 837 841 842 843 844 846 914
+839sensibility:383 840 842 885
+840insensibility:384 468 470 495 658 698 839 843 880 883 902
+841excitation:400 629 838 842 843 846 847 917
+842excitability:178 322 838 841 843 882 917 918
+843inexcitability:177 179 740 766 840 842
+844pleasure:222 385 614 633 845 846 848 853 857 914 1002
+845pain:386 634 750 844 847 849 854 856 858 876 919 1003
+846pleasurableness:385 402 404 629 663 841 844 847 853 857 862 882 1002
+847painfulness:386 664 678 742 750 845 846 863 917 925 931 949 993 996
+848content:500 843 844 846 849 853
+849discontent:501 848 850 854 856
+850regret:664 848 849 856 970
+851relief:222 675 677 704 720 852
+852aggravation:494 561 674 841 851
+853cheerfulness:844 846 854 855 857 859 875
+854dejection:845 847 849 850 853 856 858 876
+855rejoicing:856 857 870 900 901 913 1012
+856lamentation:371 420 421 845 849 850 855 934 952
+857amusement:274 305 316 379 457 566 611 636 637 658 735 844 846 855 858\
+ 859 870 873 900 909
+858weariness:698 703 854 857 886
+859wit:532 545 611 857 860 870 873
+860dulness:511 854 859
+861humorist:
+862beauty:25 249 437 629 665 846 863 864
+863ugliness:208 210 248 250 437 438 668 674 847 862 865 866
+864ornamentation:25 257 336 589 865 866 868 869
+865blemish:257 666 668 674 864
+866simplicity:864
+867good taste:475 590 868
+868vulgarity:86 129 575 668 847 863 867 869 870 872 893 912
+869fashion:85 86 232 457 627 864 867 868 890 892 899 911
+870ridiculousness:86 509 529 658 857 863 873 874
+871fop:
+872affectation:556 560 589 871 899 901 902 955
+873ridicule:611 857 949
+874laughing-stock:559 611 859 861
+875hope:222 452 496 519 876 877 882 1002
+876hopelessness:368 482 521 854 875
+877fear:497 618 638 680 847 875 876 879 927 1001
+878courage:155 616 617 730 735 737 879 880
+879cowardice:618 638 877 878
+880rashness:468 470 520 680 714 881
+881caution:137 469 522 651 683 688 713 880
+882desire:614 622 645 837 842 846 875 883 884 885 886 978
+883indifference:399 468 495 658 698 840 880 882 950
+884dislike:403 615 638 847 882 886 915 917
+885fastidiousness:882 950 952
+886satiety:703 858 882
+887wonder:86 520 521 531 888 1014
+888expectance:519 627 858 887
+889prodigy:86 524
+890repute:35 213 312 429 657 665 715 748 760 869 891 892 895 897 901 951 959
+891disrepute:890 896 898 952 960 993
+892nobility:760 869 893
+893commonality:658 892 894
+894title:892 893 994
+895pride:872 896 897 901 902
+896humility:740 843 891 895 898 903 911
+897vanity:493 871 895 898 899 901 902 904 963
+898modesty:896 897
+899ostentation:556 589 864 871 900 951
+900celebration:748 855 899 1012
+901boasting:561 871 897 900 904
+902insolence:547 754 903 904
+903servility:761 764 896 902 953 955 1012
+904blusterer:178 871 901
+905friendship:722 729 736 906 907 909 914 924
+906enmity:728 884 905 915 917 925
+907friend:726 908
+908enemy:725 907
+909sociality:75 600 727 857 905 910 911
+910seclusion:90 174 639 909 1022
+911courtesy:300 867 869 896 903 909 912 920 934 948 1012
+912discourtesy:868 904 911 917 918 919 949
+913congratulation:855 911 934
+914love:882 905 915 916 920 924
+915hate:847 884 906 908 912 914 917 925 938
+916favourite:914
+917resentment:178 841 912 915 918 919 938 949
+918irascibility:178 735 839 842 904 912 917 919 938
+919sullenness:619 912 917 918
+920endearment:911 914
+921marriage:46 783 922 923
+922celibacy:921
+923divorce:921
+924benevolence:663 722 905 911 914 925 928 932 962
+925malevolence:369 386 847 906 912 915 917 919 924 933 938 949
+926malediction:927 952
+927threat:523 683 730 877 926
+928philanthropy:924 929 962
+929misanthropy:919 928 963
+930benefactor:726 931 968
+931evil doer:369 678 809 930 969 1001
+932pity:755 780 928 933 934
+933pitilessness:754 925 932 938
+934condolence:856
+935gratitude:936 1012
+936ingratitude:935
+937forgiveness:470 738 938 991
+938revenge:733 925 933 937
+939jealousy:
+940envy:
+941right:775 942 943 945 959 964 984 994
+942wrong:941 944 965 985
+943dueness:775 787 797 941 944 958 984
+944undueness:753 943 965 985
+945duty:640 754 783 943 946 947 959 964
+946dereliction:945 952 965 967
+947non-ownership:937 945 991
+948respect:903 911 949 951 1009 1012
+949disrespect:873 912 948 950 952 954
+950contempt:470 495 624 658 949
+951approbation:633 663 890 914 948 952 953
+952disapprobation:237 664 856 884 885 926 949 950 951 954 958 965 992
+953flattery:494 561 954
+954detraction:949 952 953 956
+955flatterer:903 956
+956detractor:918 955
+957vindication:632 958 991
+958accusation:733 952 954 957 965 990 992
+959probity:555 718 890 945 960 964 966
+960improbity:556 557 722 789 891 953 959 965
+961knave:620 903 969
+962disinterestedness:616 924 959 963
+963selfishness:836 897 962
+964virtue:616 890 945 959 965 966 973
+965vice:674 925 960 964 967 969
+966innocence:718 957 959 964 967 991
+967guilt:960 965 966
+968good man:665 928 930 966 969 1009
+969bad man:369 809 835 931 961 965 968 1001
+970penitence:541 620 740 850 971 972
+971impenitence:970
+972atonement:32
+973temperance:616 654 974 979
+974intemperance:973
+975sensualist:983
+976asceticism:910 972 977
+977fasting:882 978
+978gluttony:305 882 977
+979sobriety:980
+980drunkenness:305 979
+981purity:982
+982impurity:668 981
+983libertine:975 982
+984legality:622 712 756 775 941 985
+985illegality:86 757 776 984
+986jurisdiction:752 987 988
+987tribunal:986
+988judge:491 958 986 987
+989lawyer:988
+990lawsuit:491 728 766 958
+991acquittal:765 937 992
+992condemnation:747 952 958 991
+993punishment:283 766 994 995 996
+994reward:801 824 894 995 996
+995penalty:972 993 994
+996scourge:767 994
+997deity:
+998angel:999
+999satan:998 1001
+1000jupiter:1001
+1001demon:1000
+1002heaven:675 1003
+1003hell:1002
+1004theology:496 1006
+1005orthodoxy:496 506 1006
+1006heterodoxy:493 498 501 507 527 619 1005 1011 1013 1019
+1007revelation:525 1008
+1008pseudo-revelation:1007 1013
+1009piety:948 1010 1011 1012
+1010impiety:493 556 560 619 926 965 969 1009 1011
+1011irreligion:497 1009
+1012worship:780 838 948 1020
+1013idolatry:1008
+1014sorcery:523 557 629
+1015spell:
+1016sorcerer:525 1001
+1017churchdom:711 1006
+1018clergy:1017 1019
+1019laity:1018
+1020rite:371 921 972 1012 1015 1017
+1021canonicals:232
+1022temple:
+* End of file "roget.dat"
diff --git a/support/graphbase/roget_components.w b/support/graphbase/roget_components.w
new file mode 100644
index 0000000000..596fae3a25
--- /dev/null
+++ b/support/graphbase/roget_components.w
@@ -0,0 +1,391 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{ROGET\_\thinspace COMPONENTS}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+
+\prerequisite{GB\_\thinspace ROGET}
+@* Strong components. This demonstration program computes the
+strong components of GraphBase graphs derived from Roget's Thesaurus,
+using a variant of Tarjan's algorithm [R. E. Tarjan, ``Depth-first
+search and linear graph algorithms,'' {\sl SIAM Journal on Computing\/
+\bf1} (1972), 146--160]. We also determine the relationships
+between strong components.
+
+Two vertices belong to the same strong component if and only if they
+are reachable from each other via directed paths.
+
+We will print the strong components in ``reverse topological order'';
+that is, if |v| is reachable from~|u| but |u| is not reachable
+from~|v|, the strong component containing~|v| will be listed before
+the strong component containing~|u|.
+
+Symbolic references to vertices from the |roget| graph are given
+by both name and category number.
+
+@d specs(v) v->cat_no, v->name /* category number and category name */
+
+
+@ We permit command-line options in \UNIX\ style so that a variety of
+graphs can be studied:
+The user can say `\.{-n}\<number>', `\.{-d}\<number>', `\.{-p}\<number>',
+and/or `\.{-s}\<number>' to change the default values of the parameters
+in the graph |roget(n,d,p,s)|.
+@^UNIX dependencies@>
+
+@p
+#include "gb_graph.h" /* the GraphBase data structures */
+#include "gb_roget.h" /* the |roget| routine */
+@#
+@<Global variables@>;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{@+Graph *g; /* the graph we will work on */
+ register Vertex *v; /* the current vertex of interest */
+ unsigned n=0; /* the desired number of vertices (0 means infinity) */
+ unsigned d=0; /* the minimum distance between categories in arcs */
+ unsigned p=0; /* 65536 times the probability of rejecting an arc */
+ long s=0; /* the random number seed */
+ @<Scan the command line options@>;
+ g=roget(n,d,p,s);
+ if (g==NULL) {
+ fprintf(stderr,"Sorry, can't create the graph! (error code %d)\n",
+ panic_code);
+ return -1;
+ }
+ printf("Reachability analysis of %s\n\n",g->id);
+ @<Perform Tarjan's algorithm on |g|@>;
+}
+
+@ @<Scan the command line options@>=
+while (--argc) {
+@^UNIX dependencies@>
+ if (sscanf(argv[argc],"-n%u",&n)==1) ;
+ else if (sscanf(argv[argc],"-d%u",&d)==1) ;
+ else if (sscanf(argv[argc],"-p%u",&p)==1) ;
+ else if (sscanf(argv[argc],"-s%ld",&s)==1) ;
+ else {
+ fprintf(stderr,"Usage: %s [-nN][-dN][-pN][-sN]\n",argv[0]);
+ return -2;
+ }
+}
+
+@ Tarjan's algorithm is inherently recursive. We will implement
+the recursion explicitly via linked lists, instead of using \Cee's runtime
+stack, because some computer systems
+bog down in the presence of deeply nested recursion.
+
+Each vertex goes through three stages during the algorithm: First it is
+`unseen'; then it is `active'; finally it becomes `settled', when it
+has been assigned to a strong component.
+
+The data structures that represent the current state of the algorithm
+are implemented by using five of the utility fields in each vertex:
+|rank|, |parent|, |untagged|, |link|, and |min|. We will describe each of
+these in turn.
+
+@ First is the integer |rank| field, which is zero when a vertex is unseen.
+As soon as the vertex is first examined, it becomes active and its |rank|
+becomes and remains nonzero. Indeed, the |k|th vertex to become active
+will receive rank~|k|. When a vertex finally becomes settled its rank
+is reset to infinity.
+
+It's convenient to think of Tarjan's algorithm as a simple adventure
+game, in which we want to explore all rooms of a cave. Passageways between
+the rooms allow one-way travel only. When we come
+into a room for the first time, we assign a new number to that room;
+this is its rank. Later on we may happen to come into the same room
+again, and we will notice that it has nonzero rank; then we'll be able
+to make a quick exit, saying ``we've already been here.'' (The extra
+complexities of computer games, like dragons that might need to be
+vanquished, do not arise.)
+
+@d rank z.i /* the |rank| of a vertex is stored in utility field |z| */
+
+@<Glob...@>=
+int nn; /* the number of vertices that have been seen */
+
+@ The active vertices will always form an oriented tree, whose arcs are
+a subset of the arcs in the original graph. A tree arc from |u| to~|v|
+will be represented by |v->parent==u|. Every active vertex has a
+parent, which is usually another active vertex; the only exception is
+the root of the tree, whose |parent| is |NULL|.
+
+In the cave analogy, the `parent' of room |v| is the room we were in
+immediately before entering |v| the first time. By following parent
+pointers, we will be able to leave the cave whenever we want.
+
+As soon as a vertex becomes settled, its |parent| field changes
+significance. Then |v->parent| is set equal to the unique
+representative of the strong component containing vertex~|v|. Thus,
+two settled vertices will belong to the same strong component if and only
+if they have the same |parent|.
+
+@d parent y.v /* the |parent| of a vertex is stored in utility field |y| */
+
+@ All arcs in the original directed graph are explored systematically during
+a depth-first search. Whenever we look at an arc, we `tag' it so that
+we won't need to explore it again. In a cave, for example, we might
+mark each passageway between rooms once we've tried to go through it.
+
+The algorithm doesn't actually place a tag on its |Arc| records; instead,
+each vertex |v| has a pointer |v->untagged| that leads to all
+hitherto-unexplored arcs from~|v|. The arcs of the list that appear
+between |v->arcs| and |v->untagged| are the ones already examined.
+
+@d untagged x.a /* the |untagged| field points to an |Arc| record, or |NULL| */
+
+@ The algorithm maintains two special stacks: |active_stack| contains
+all the currently active vertices, and |settled_stack| contains all the
+currently settled vertices. Each vertex has a |link| field that points
+to the vertex next lower on its stack, or to |NULL| if the vertex is
+at the bottom. The vertices on |active_stack| always appear in increasing
+order of rank from bottom to top.
+
+@d link w.v /* the |link| field of a vertex occupies utility field |w| */
+
+@<Glob...@>=
+Vertex * active_stack; /* the top of the stack of active vertices */
+Vertex * settled_stack; /* the top of the stack of settled vertices */
+
+@ Finally there's a |min| field, which is the tricky part that makes
+everything work. If vertex~|v| is unseen or settled, its |min| field is
+irrelevant. Otherwise |v->min| points to the active vertex~|u|
+of smallest rank having the property that
+either |u==v| or there is a directed path from |v| to |u| consisting of
+zero or more `mature' tree arcs followed by a single non-tree arc.
+
+What is a tree arc, you ask. And what is a mature arc? Good questions. At the
+moment when arcs of the graph are tagged, we classify them either as tree
+arcs (if they correspond to a new |parent| link in the tree of active
+nodes) or non-tree arcs (otherwise). A tree arc becomes mature when it
+is no longer on the path from the root to the current vertex being
+explored. We also say that a vertex becomes mature when it is
+no longer on that path. All arcs from a mature vertex have been tagged.
+
+We said before that every vertex is initially unseen, then active, and
+finally settled. With our new definitions, we see further that every arc starts
+out untagged, then it becomes either a non-tree arc or a tree arc. In the
+latter case it begins as an immature tree arc and eventually matures.
+
+Just believe these definitions, for now. All will become clear soon.
+
+@d min v.v /* the |min| field of a vertex occupies utility field |v| */
+
+@ Depth-first search explores a graph by systematically visiting all
+vertices and seeing what they can lead to. In Tarjan's algorithm, as
+we have said, the active vertices form an oriented tree. One of these
+vertices is called the current vertex.
+
+If the current vertex still has an arc that hasn't been tagged, we
+tag one such arc and there are two cases: Either the arc leads to
+an unseen vertex, or it doesn't. If it does, the arc becomes a tree
+arc; the previously unseen vertex becomes active, and it becomes the
+new current vertex. On the other hand if the arc leads to a vertex
+that has already been seen, the arc becomes a non-tree arc and the
+current vertex doesn't change.
+
+Finally there will come a time when the current vertex~|v| has no
+untagged arcs. At this point, the
+algorithm might decide that |v| and all its descendants form a strong
+component. Indeed, this condition turns out to be true if and only if
+|v->min==v|; a proof appears below. If so, |v| and all its descendants
+become settled, and they leave the tree. If not, the tree arc from
+|v|'s parent~|u| to~|v| becomes mature, so the value of |v->min| is
+used to update the value of |u->min|. In both cases |v| becomes mature,
+and the new current vertex will be the parent of~|v|. Notice that only the
+value of |u->min| needs to be updated, when the arc from |u| to~|v|
+matures; all other values |w->min| stay the same, because a newly
+mature arc has no mature predecessors.
+
+In the cave analogy, a room |v| and its descendants will become a
+strong component when there's no outlet from the subcave starting at~|v|
+without coming back through |v| itself. Once such a strong component
+is identified, we close it off and don't explore that subcave any further.
+
+If |v| is the root of the tree, it always has |v->min==v|,
+so it will always define a new strong component at the moment it matures.
+Then the depth-first search will terminate, since |v|~has no parent.
+But Tarjan's algorithm will press on, trying to find a vertex~|u| that is still
+unseen. If such a vertex exists,
+a new depth-first search will begin with |u| as the root. This
+process keeps on going until at last all vertices are happily settled.
+
+The beauty of this algorithm is that it all works very efficiently
+when we organize it as follows:
+
+@<Perform Tarjan's algorithm on |g|@>=
+@<Make all vertices unseen and all arcs untagged@>;
+for (vv=g->vertices; vv<g->vertices+g->n; vv++)
+ if (vv->rank==0) /* |vv| is still unseen */
+ @<Perform a depth-first search with |vv| as the root, finding the
+ strong components of all unseen vertices reachable from~|vv|@>;
+@<Print out one representative of each arc that runs
+ between strong components@>;
+
+@ @<Glob...@>=
+Vertex *vv; /* sweeps over all vertices, making sure none is left unseen */
+
+@ It's easy to get the data structures started, according to the
+conventions stipulated above.
+
+@<Make all vertices unseen...@>=
+for (v=g->vertices+g->n-1; v>=g->vertices; v--) {
+ v->rank=0;
+ v->untagged=v->arcs;
+}
+nn=0;
+active_stack=settled_stack=NULL;
+
+@ The task of starting a depth-first search isn't too bad either. Throughout
+this part of the algorithm, variable~|v| will point to the current vertex.
+
+@<Perform a depth-first search with |vv| as the root...@>=
+{
+ v=vv;
+ v->parent=NULL;
+ @<Make vertex |v| active@>;
+ do @<Explore one step from the current vertex~|v|, possibly moving
+ to another current vertex and calling~it~|v|@>@;
+ while (v!=NULL);
+}
+
+@ @<Make vertex |v| active@>=
+v->rank=++nn;
+v->link=active_stack;
+active_stack=v;
+v->min=v;
+
+@ Now things get interesting. But we're just doing what any well-organized
+spelunker would do when calmly exploring a cave.
+There are three main cases,
+depending on whether the current vertex stays where it is, moves
+to a new child, or backtracks to a parent.
+
+@<Explore one step from the current vertex~|v|, possibly moving
+ to another current vertex and calling~it~|v|@>=
+{@+register Vertex *u; /* a vertex adjacent to |v| */
+ register Arc *a=v->untagged; /* |v|'s first remaining untagged arc, if any */
+ if (a) {
+ u=a->tip;
+ v->untagged = a->next; /* tag the arc from |v| to |u| */
+ if (u->rank) { /* we've seen |u| already */
+ if (u->rank < v->min->rank)
+ v->min=u; /* non-tree arc, just update |v->min| */
+ } else { /* |u| is presently unseen */
+ u->parent = v; /* the arc from |v| to |u| is a new tree arc */
+ v = u; /* |u| will now be the current vertex */
+ @<Make vertex |v| active@>;
+ }
+ } else { /* all arcs from |v| are tagged, so |v| matures */
+ u=v->parent; /* prepare to backtrack in the tree */
+ if (v->min==v) @<Remove |v| and all its successors on the active stack
+ from the tree, and mark them as a strong component of the graph@>@;
+ else /* the arc from |u| to |v| has just matured,
+ making |v->min| visible from |u| */@,
+ if (v->min->rank < u->min->rank)
+ u->min=v->min;
+ v=u; /* the former parent of |v| is the new current vertex |v| */
+ }
+}
+
+@ The elements of the active stack are always in order
+by rank, and all children of a vertex~|v| in the tree have rank higher
+than~|v|. Tarjan's algorithm relies on a converse property: {\sl All
+active nodes whose rank exceeds that of the current vertex~|v|
+are descendants of~|v|.} (This holds because the algorithm has constructed
+the tree by assigning ranks in preorder, ``the order of succession to the
+throne''. First come |v|'s firstborn and descendants, then the nextborn,
+and so on.) Therefore the descendants of the current vertex always appear
+consecutively at the top of the stack.
+
+Another fundamental property of Tarjan's algorithm is more subtle:
+{\sl There is always a way to get from any active vertex to the
+current vertex.} This follows from the fact that all mature active vertices~|u|
+have |u->min->rank<u->rank|. If some active vertex does not lead to the
+current vertex~|v|,
+let |u| be the counterexample with smallest rank. Then |u| isn't an
+ancestor of~|v|, hence |u| must be mature; hence it leads to the
+active vertex |u->min|, from which there {\it is\/} a path to~|v|,
+contradicting our assumption.
+
+Therefore |v| and its active descendants are all reachable from each
+other, and they must belong to the same strong component. Moreover, if
+|v->min=v|, this component can't be made any larger. For there is no
+arc from any of these vertices to an unseen vertex; all arcs from |v|
+and its descendants have already been tagged. And there is no arc from
+any of these vertices to an active vertex that is below |v| on the
+stack; otherwise |v->min| would have smaller rank than~|v|. Hence all
+arcs, if any, that lead from these vertices to some other vertex must
+lead to settled vertices. And we know from previous steps of the
+computation that the settled vertices all belong to other strong
+components.
+
+Therefore we are justified in settling |v| and its active descendants now.
+Removing them from the tree of active vertices does not remove any
+vertex from which there is a path to a vertex of rank less than
+|v->rank|; hence it does not affect the validity of the |u->min| value
+for any vertex~|u| that remains active.
+
+We print out enough information for a reader to verify the
+strength of the claimed component easily.
+
+@d infinity g->n /* infinite rank (or close enough) */
+
+@<Remove |v| and all its successors on the active stack
+ from the tree, and mark them as a strong component of the graph@>=
+{@+register Vertex *t; /* runs through the vertices of the
+ new strong component */
+ t=active_stack;
+ active_stack=v->link;
+ v->link=settled_stack;
+ settled_stack=t; /* we've moved the top of one stack to the other */
+ printf("Strong component `%d %s'", specs(v));
+ if (t==v) putchar('\n'); /* single vertex */
+ else {
+ printf(" also includes:\n");
+ while (t!=v) {
+ printf(" %d %s (from %d %s; ..to %d %s)\n", specs(t), specs(t->parent),
+ specs(t->min));
+ t->rank=infinity; /* now |t| is settled */
+ t->parent=v; /* and |v| represents the new strong component */
+ t=t->link;
+ }
+ }
+ v->rank=infinity; /* |v| too is settled */
+ v->parent=v; /* and represents its own strong component */
+}
+
+@ After all the strong components have been found, we can also compute the
+relations between them, without mentioning any cross-connection more than
+once. In fact, we built the |settled_stack| precisely so that this task
+could be done easily without sorting or searching; if only the components
+themselves were of interest, this part of the algorithm wouldn't be
+necessary.
+
+For this step we use the name |arc_from| for the field we previously
+called |untagged|. The trick here relies on the fact that all vertices of the
+same strong component appear together in |settled_stack|.
+
+@d arc_from x.v /* utility field |x| will now point to a vertex */
+
+@<Print out one representative of each arc that runs between...@>=
+printf("\nLinks between components:\n");
+for (v=settled_stack; v; v=v->link) {@+register Vertex *u=v->parent;
+ register Arc *a;
+ u->arc_from=u;
+ for (a=v->arcs; a; a=a->next) {@+register Vertex *w=a->tip->parent;
+ if (w->arc_from!=u) {
+ w->arc_from=u;
+ printf("%d %s -> %d %s (e.g., %d %s -> %d %s)\n",
+ specs(u),specs(w),specs(v),specs(a->tip));
+ }
+ }
+}
+
+@* Index. We close with a list that shows where the identifiers of this
+program are defined and used.
+
+@f Vertex int
+@f Arc int
+@f Graph int
diff --git a/support/graphbase/sample.correct b/support/graphbase/sample.correct
new file mode 100644
index 0000000000..da66e894af
--- /dev/null
+++ b/support/graphbase/sample.correct
@@ -0,0 +1,109 @@
+GraphBase samples generated by test_sample:
+
+"raman(31,3,3,4)"
+12 vertices, 96 arcs, format ZZZIIIIZZZZZZZ
+V4: "(1,0;1,1)"[1][0][1]
+ ->"(1,2;1,0)"[1][2][0], 1[16]
+ ->"(1,1;1,2)"[1][1][2], 1[17]
+ ->"(0,2;1,0)"[0][2][0], 1[18]
+ ->"(1,1;0,1)"[1][1][3], 1[19]
+ ->"(2,0;1,2)"[2][0][2], 1[20]
+ ->"(1,0;0,1)"[1][0][3], 1[21]
+ ->"(0,2;1,1)"[0][2][1], 1[22]
+ ->"(2,1;1,1)"[2][1][1], 1[23]
+
+"board(1,1,2,-33,1,-2147483648,1)"
+2048 vertices, 14336 arcs, format ZZZIIIZZZZZZZZ
+V2000: "0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.1.0.0.0.0.0.0.0.0.0.0.0.0"[0][0][1]
+ ->"0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.0.0.0.0.0.0.0"[0][0][1], 1
+ ->"0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.1.0.0.1.0.0.0.0.0.0.0.0.0"[0][0][1], 1
+ ->"0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.1.0.0.0.0.0.1.0.0.0.0.0.0"[0][0][1], 1
+ ->"0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.1.0.0.0.0.0.0.0.0.1.0.0.0"[0][0][1], 1
+ ->"0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.1.0.0.0.0.0.0.0.0.0.0.0.0"[0][0][1], 1
+ ->"0.0.1.0.0.1.0.0.1.0.0.1.0.0.1.0.0.0.0.0.1.0.0.0.0.0.0.0.0.0.0.0.1"[0][0][1], 1
+
+"subsets(32,18,16,0,0,0,0x80000000,1)"
+3 vertices, 2 arcs, format ZZZIIIZZZZZZZZ
+V1: "17.15"[17][15][0]
+ ->"18.14"[18][14][0], 1
+
+"gunion(random_lengths(complement(random_graph(3,10,1,1,0,0,dist,1,2,1),1,1,0),0,10,12,dist,2),random_graph(3,10,1,1,0,0,dist,1,2,1),1,0)"
+3 vertices, 30 arcs, format ZZZZZZZZZZZZZZ
+V2: "2"
+ ->"1", 1
+ ->"1", 1
+ ->"1", 1
+ ->"1", 10
+ ->"0", 1
+ ->"0", 11
+
+"partial_gates(risc(16),1,43210,98765)"
+1702 vertices, 3796 arcs, format ZZZIIVZZZZZZZA[->"Z1508"[0][38]]
+V79: "R10:10"[0][76]["Z898"[0][38]]
+
+"book("homer",500,400,2,12,10000,-123456,789)"
+100 vertices, 4 arcs, format IZZIISIZZZZZZZ
+V81: "Eetion"[90][2][1][" king of Cilicia, father of AH"]
+ ->"Andromache"[377][2][1][" wife of HT"], 1[6]
+
+"econ(40,0,400,-111)"
+40 vertices, 512 arcs, format ZZZZIAIZZZZZZZ
+V11: "Printing and publishing"[69451][->NULL]
+ ->"Food, liquor, and candy"[300724], 1[1863]
+ ->"Cigarettes, cigars, tobacco"[24445], 1[195]
+ ->"Printing and publishing"[69451], 1[6089]
+ ->"Business support services"[463594], 1[8369]
+ ->"Personal services"[827615], 1[9073]
+ ->"Users"[3999362], 1[30676]
+
+"games(60,70,80,-90,-101,60,128,999999999)"
+60 vertices, 114 arcs, format IIIISSIIZZZZZZ
+V14: "Maryland"[42][2][0][0]["Terps"]["Atlantic Coast"]
+ ->"Louisiana Tech"[0][0][0][0]["Bulldogs"]["(null)"], 34[2][111]
+ ->"Virginia"[1005][272][188][65]["Cavaliers"]["Atlantic Coast"], 35[1][83]
+
+"miles(50,-500,100,1,500,5,314159)"
+50 vertices, 164 arcs, format ZZIIIIZZZZZZZZ
+V20: "Saint Louis, MO"[453085][3293][1785][24]
+ ->"Tupelo, MS"[23905][3441][1131][86], 364
+ ->"Springfield, MO"[133116][2983][1575][62], 235
+
+"plane_mona(100,100,50,1,300,1,200,2975050,11900200)"
+3158 vertices, 13888 arcs, format ZZZIIIZZIIZZZZ[100][100]
+V1294: "1294"[7][2676][2776]
+ ->"1416"[6][2876][2876], 1
+ ->"1359"[1][2777][2777], 1
+ ->"1358"[23][2775][2775], 1
+ ->"1295"[2][2677][2677], 1
+ ->"1293"[19][2675][2675], 1
+ ->"1236"[4][2576][2576], 1
+
+"plane_miles(50,500,-100,1,1,40000,271818)"
+51 vertices, 96 arcs, format ZZIIIIZZZZZZZZ
+V14: "Saint Louis, MO"[453085][3293][1785][24]
+ ->"Waterloo, IA"[75985][3078][2367][103], 373
+ ->"South Bend, IN"[109727][3687][2244][58], 358
+ ->"San Diego, CA"[875538][597][898][35], 1875
+
+"random_bigraph(300,3,1000,-1,0,dist,-500,500,666)"
+303 vertices, 1138 arcs, format ZZZZZZZZIZZZZZ[300]
+V3: "3"
+ ->"300", -377
+ ->"302", 39
+
+"roget(1000,3,1009,1009)"
+1000 vertices, 3573 arcs, format IZZZZZZZZZZZZZ
+V40: "thought"[461]
+ ->"imagination"[527], 1
+ ->"memory"[517], 1
+ ->"inquiry"[471], 1
+ ->"inattention"[468], 1
+ ->"attention"[467], 1
+
+Ooops, we just ran into panic code 30!
+
+"words(90,{100,-80588,50000,18935,-18935,18935,18935,18935,18935},70000000,69)"
+90 vertices, 38 arcs, format IZZZZZIZZZZZZZ
+V5: "would"[590131605]
+ ->"world"[150515830], 1[2]
+ ->"could"[438944820], 1[0]
diff --git a/support/graphbase/take_risc.w b/support/graphbase/take_risc.w
new file mode 100644
index 0000000000..2658066c21
--- /dev/null
+++ b/support/graphbase/take_risc.w
@@ -0,0 +1,173 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{TAKE\_\thinspace RISC}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_\thinspace GATES}
+@* Introduction. This demonstration program uses graphs
+constructed by the |risc| procedure in the |gb_gates| module to produce
+an interactive program called \.{take\_risc}, which multiplies and divides
+small numbers the slow way (i.e., by simulating the behavior of
+a logical circuit, one gate at a time).
+
+The program assumes that \UNIX\ conventions are being used. Some code in
+sections listed under `\UNIX\ dependencies' in the index may need to change
+if this program is ported to other operating systems.
+
+\def\<#1>{$\langle${\rm#1}$\rangle$}
+To run the program under \UNIX, say `\.{take\_risc} \<trace>', where \<trace>
+is nonempty if and only if you want the machine computations to
+be printed out.
+
+The program will prompt you for two numbers, and it will use the simulated
+RISC machine to compute their product and quotient. Then it will ask
+for two more numbers, and so on.
+
+@ We use the data type \&{Graph} defined in |gb_graph|.
+
+@f Graph int
+
+@ Here is the general layout of this program, as seen by the \Cee\ compiler:
+@^UNIX dependencies@>
+
+@p
+#include "gb_graph.h" /* the standard GraphBase data structures */
+#include "gb_gates.h" /* routines for gate graphs */
+@#
+@<Global variables@>@;
+main(argc,argv)
+ int argc; /* the number of command-line arguments */
+ char *argv[]; /* an array of strings containing those arguments */
+{
+ trace=(argc>1? 8: 0); /* we'll show registers 0--7 if tracing */
+ if ((g=risc(8))==NULL) {
+ printf("Sorry, I couldn't generate the graph (trouble code %d)!\n",
+ panic_code);
+ return(-1);
+ }
+ printf("Welcome to the world of microRISC.\n");
+ while(1) {
+ @<Prompt for two numbers; |break| if unsuccessful@>;
+ @<Use the RISC machine to compute the product, |p|@>;
+ printf("The product of %d and %d is %d%s.\n",m,n,p,
+ o?" (overflow occurred)":"");
+ @<Use the RISC machine to compute the quotient and remainder, |q| and~|r|@>;
+ printf("The quotient is %d, and the remainder is %d.\n",q,r);
+ }
+}
+
+@ @<Glob...@>=
+Graph *g; /* graph that defines a simple RISC machine */
+int o,p,q,r; /* overflow, product, quotient, remainder */
+int trace; /* number of registers to trace */
+int m,n; /* numbers to be multiplied and divided */
+char buffer[100]; /* input buffer */
+
+@ @d prompt(s)
+ {@+printf(s);@+fflush(stdout); /* make sure the user sees the prompt */
+ if (fgets(buffer,99,stdin)==NULL) break;@+}
+
+@<Prompt...@>=
+prompt("\nGimme a number: ");
+step0:if (sscanf(buffer,"%d",&m)!=1) break;
+step1:if (m<=0) {
+ prompt("Excuse me, I meant a positive number: ");
+ if (sscanf(buffer,"%d",&m)!=1) break;
+ if (m<=0) break;
+}
+while (m>0x7fff) {
+ prompt("That number's too big; please try again: ");
+ if (sscanf(buffer,"%d",&m)!=1) goto step0; /* |step0| will |break| out */
+ if (m<=0) goto step1;
+}
+@<Now do the same thing for |n| instead of |m|@>;
+
+@ @<Now do the same thing for |n| instead of |m|@>=
+prompt("OK, now gimme another: ");
+if (sscanf(buffer,"%d",&n)!=1) break;
+step2:if (n<=0) {
+ prompt("Excuse me, I meant a positive number: ");
+ if (sscanf(buffer,"%d",&n)!=1) break;
+ if (n<=0) break;
+}
+while (n>0x7fff) {
+ prompt("That number's too big; please try again: ");
+ if (sscanf(buffer,"%d",&n)!=1) goto step0; /* |step0| will |break| out */
+ if (n<=0) goto step2;
+}
+
+@* A RISC program. Here is the little program we will run on the
+little computer. It consists mainly of a subroutine called |tri|,
+which computes the value of the ternary operation $x\lfloor
+y/z\rfloor$, assuming that $y\ge0$ and $z>0$; the inputs $x,y,z$
+appear in registers $1,2,3$, respectively, and the exit address is
+assumed to be in register~7. As special cases we can compute the
+product $xy$ (letting $z=1$) or the quotient $\lfloor y/z\rfloor$
+(letting $x=1$). When the subroutine returns, it leaves the result in
+register~4, and it also leaves the value $(y\bmod z)-z$ in register~2;
+overflow will be set if and only if the true result was not between
+$-2^{15}$ and $2^{15}-1$, inclusive.
+
+It would not be difficult to modify the code to make it work with unsigned
+16-bit numbers, or to make it deliver results with 32 or 48 or perhaps
+even 64 bits of precision.
+
+@d div 7 /* location `|div|' in the program below */
+@d mult 10 /* location `|mult|' in the program below */
+@d memry_size 34 /* the number of instructions in the program below */
+
+@<Glob...@>=
+unsigned memry[memry_size]={ /* a ``read-only memory'' used by |run_risc| */
+ 0x2ff0, /* |start:| $\\{r2}=m$ (contents of next word) */
+ 0x1111, /* (we will put the value of |m| here, in |memry[1]|) */
+ 0x1a30, /* \quad$\\{r1}=n$ (contents of next word) */
+ 0x3333, /* (we will put the value of |n| here, in |memry[3]|) */
+ 0x7f70, /* \quad\&{jumpto} (contents of next word),
+ $\\{r7}={}$return address */
+ 0x5555, /* (we will put either |mult| or |div| here, in |memry[5]|) */
+ 0x0f8f, /* halt without changing any status bits */
+ 0x3a21, /* |div:| $\\{r3}=\\{r1}$ */
+ 0x1a01, /* \quad$\\{r1}=1$ */
+ 0x0a12, /* \quad|goto tri| (literally, |@t\\{r0}@>+=2|) */
+ 0x3a01, /* |mult:| $\\{r3}=1$ */
+ 0x4000, /* |tri:| $\\{r4}=0$ */
+ 0x5000, /* \quad$\\{r5}=0$ */
+ 0x6000, /* \quad$\\{r6}=0$ */
+ 0x2a63, /* \quad|@t\\{r2}@>-=@t\\{r3}@>| */
+ 0x0f95, /* \quad|goto l2| */
+ 0x3063, /* |l1:| |@t\\{r3}@><<=1| */
+ 0x1061, /* \quad|@t\\{r1}@><<=1| */
+ 0x6ac1, /* \quad|if| (overflow) $\\{r6}=1$ */
+ 0x5fd1, /* \quad|@t\\{r5}@>++| */
+ 0x2a63, /* |l2:| |@t\\{r2}@>-=@t\\{r3}@>| */
+ 0x039b, /* \quad|if| ($\ge0$) |goto l1| */
+ 0x0843, /* \quad|goto l4| */
+ 0x3463, /* |l3:| |@t\\{r3}@>>>=1| */
+ 0x1561, /* \quad|@t\\{r1}@>>>=1| */
+ 0x2863, /* |l4:| |@t\\{r2}@>+=@t\\{r3}@>| */
+ 0x0c94, /* \quad|if| ($<0$) |goto l5| */
+ 0x4861, /* \quad|@t\\{r4}@>+=@t\\{r1}@>| */
+ 0x6ac1, /* \quad|if| (overflow) $\\{r6}=1$ */
+ 0x2a63, /* \quad|@t\\{r2}@>-=@t\\{r3}@>| */
+ 0x5a41, /* |l5:| |@t\\{r5}@>--| */
+ 0x0398, /* \quad|if| ($\ge0$) |goto l3| */
+ 0x6666, /* \quad|if| (\\{r6}) force overflow (literally |@t\\{r6}@>>>=4|) */
+ 0x0fa7}; /* \quad|return|
+ (literally, $\\{r0}=\\{r7}$, preserving overflow) */
+
+@ @<Use the RISC machine to compute the product, |p|@>=
+memry[1]=m;
+memry[3]=n;
+memry[5]=mult;
+run_risc(g,memry,memry_size,trace);
+p=(int)risc_state[4];
+o=(int)risc_state[16]&1; /* the overflow bit */
+
+@ @<Use the RISC machine to compute the quotient and remainder, |q| and~|r|@>=
+memry[5]=div;
+run_risc(g,memry,memry_size,trace);
+q=(int)risc_state[4];
+r=((long)(risc_state[2]+n))&0x7fff;
+
+@* Index. Finally, here's a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/test.correct b/support/graphbase/test.correct
new file mode 100644
index 0000000000..1d621ccc12
--- /dev/null
+++ b/support/graphbase/test.correct
@@ -0,0 +1,115 @@
+* GraphBase graph (format ZZZZZZZZZZVZZZ,8V,102A)
+"complement(random_graph(3,10,1,1,0,0,dist,1,2,1),1,1,0)",3,10,V7
+* Vertices
+"0",A4
+"1",A8
+"2",A9
+"",0
+"",0
+"",0
+"",0
+"Testing",0
+* Arcs
+V0,A1,1
+V0,0,1
+V1,A0,1
+V0,0,1
+V2,A2,1
+V0,0,1
+V1,A7,1
+V1,A3,1
+V2,A6,1
+V1,A5,1
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+* Checksum 761246749
diff --git a/support/graphbase/test.dat b/support/graphbase/test.dat
new file mode 100644
index 0000000000..a1799d6be5
--- /dev/null
+++ b/support/graphbase/test.dat
@@ -0,0 +1,8 @@
+* File "test.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* A test program used to validate the gb_io module (at least in part)
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 3,1008816584)
+0000000000000000000000000000000000000000000000000000000000000000123456789ABCDEF
+
+Oops:(intentional mistake)
+* End of file "test.dat"
diff --git a/support/graphbase/test_sample.w b/support/graphbase/test_sample.w
new file mode 100644
index 0000000000..c5ddb6cccc
--- /dev/null
+++ b/support/graphbase/test_sample.w
@@ -0,0 +1,268 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{TEST\_\thinspace SAMPLE}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+@* Introduction. This GraphBase program is intended to be used only
+when the Stanford GraphBase is being installed. It invokes the
+most critical subroutines and creates a file that can be checked
+against the correct output.
+The testing is not by any means exhaustive, but it is designed to detect
+errors of portability, i.e., cases where different results might occur
+on different systems. Thus, if nothing goes wrong, one can assume that
+the GraphBase routines are probably installed satisfactorily.
+
+The basic idea of |test_sample| is quite simple: We generate a graph,
+then print out a few of its salient characteristics. Then we recycle
+the graph and generate another, etc. The test is passed if the output
+file matches a ``correct'' output file generated at Stanford by the author.
+
+Actually there are two output files. The main one, containing samples of
+graph characteristics, is the standard output. The other, called \.{test.gb},
+is a graph that has been saved in ASCII format with |save_graph|.
+
+@f Graph int /* |gb_graph| defines the |Graph| type and a few others */
+@f Vertex int
+@f Area int
+@f Arc int
+
+@p
+#include "gb_graph.h" /* we use the |gb_graph| data structures */
+#include "gb_io.h" /* and the GraphBase input/output routines */
+@<Include headers for all of the GraphBase generation modules@>@;
+@#
+@<Private variables@>@;
+@<Procedures@>@;
+main()
+{@+Graph *g,*gg;@+int i;@+Vertex *v; /* temporary registers */
+ printf("GraphBase samples generated by test_sample:\n");
+ @<Save a graph to be restored later@>;
+ @<Print samples of generated graphs@>;
+}
+
+@ @<Include headers for all of the GraphBase generation modules@>=
+#include "gb_basic.h" /* we test the basic graph operations */
+#include "gb_books.h" /* and the graphs based on literature */
+#include "gb_econ.h" /* and the graphs based on economic data */
+#include "gb_games.h" /* and the graphs based on football scores */
+#include "gb_gates.h" /* and the graphs based on logic circuits */
+#include "gb_miles.h" /* and the graphs based on mileage data */
+#include "gb_mona.h" /* and the graphs based on Mona Lisa */
+#include "gb_plane.h" /* and the planar graphs */
+#include "gb_raman.h" /* and the Ramanujan graphs */
+#include "gb_rand.h" /* and the random graphs */
+#include "gb_roget.h" /* and the graphs based on Roget's Thesaurus */
+#include "gb_save.h" /* and we save results in ASCII format */
+#include "gb_words.h" /* and we also test five-letter-word graphs */
+
+@ The subroutine |print_sample(g,n)| will be specified later. It prints global
+characteristics of |g| and local characteristics of vertex |g->vertices+n|.
+
+We begin the test cautiously by generating a graph that requires no input data
+and no pseudorandom numbers. If this test fails, the fault must lie either in
+|gb_graph| or |gb_raman|.
+
+@<Print samples of generated graphs@>=
+print_sample(raman(31,3,0,4),4);
+
+@ Next we test part of |gb_basic| that relies on a particular interpretation
+of the operation `|w>>=1|'. If this part of the test fails, please look up
+`system dependencies' in the index to |gb_basic|, and correct the
+problem on your system by making a change file \.{gb\_basic.ch}. (See
+\.{queen\_wrap.ch} for an example of a change file.)
+
+On the other hand, if |test_sample| fails only in this particular test
+while passing all those that follow, chances are excellent that
+you have a pretty good implementation of the GraphBase anyway,
+because the bug detected here will rarely show up in practice. Ask
+yourself: Can I live comfortably with such a bug?
+
+@<Print samples of generated graphs@>=
+print_sample(board(1,1,2,-33,1,-0x40000000-0x40000000,1),2000);
+ /* coordinates 32 and 33 (only) should wrap around */
+
+@ Another system-dependent part of |gb_basic| is tested here.
+
+@<Print samples of generated graphs@>=
+print_sample(subsets(32,18,16,0,999,-999,0x80000000,1),1);
+
+@ If \.{test.gb} fails to match \.{test.correct}, the most likely culprit
+is |vert_offset|, a ``pointer hack'' in |gb_basic|. That macro absolutely
+has to be made to work properly, because it is used heavily.
+
+@<Save a graph to be restored later@>=
+ g=random_graph(3,10,1,1,0,NULL,dst,1,2,1);
+ gg=complement(g,1,1,0); /* a copy of |g| */
+ v=gb_alloc_type(1,@[Vertex@],gg->data); /* create a stray vertex too */
+ v->name=gb_save_string("Testing");
+ gg->format[10]='V';
+ gg->w.v=v; /* the stray vertex is now part of |gg| */
+ save_graph(gg,"test.gb"); /* so it will appear in \.{test.gb} (we hope) */
+ gb_recycle(g);@+gb_recycle(gg);
+
+@ @<Private...@>=
+static long dst[]={0x20000000,0x10000000,0x10000000};
+ /* a probability distribution with frequencies 50\%, 25\%, 25\% */
+
+@ Now we try to reconstruct the graph we saved before, and randomize
+its lengths.
+
+@<Print samples...@>=
+g=restore_graph("test.gb");
+if (i=random_lengths(g,0,10,12,dst,2))
+ printf("\nFailure code %d returned by random_lengths!\n",i);
+else {
+ gg=random_graph(3,10,1,1,0,NULL,dst,1,2,1); /* same as before */
+ print_sample(gunion(g,gg,1,0),2);
+ gb_recycle(g);@+gb_recycle(gg);
+}
+
+@ Partial evaluation of a RISC circuit involves fairly intricate pointer
+manipulation, so this should help test the portability of the author's
+favorite tricks.
+
+@<Print samples...@>=
+print_sample(partial_gates(risc(0),1,43210,98765,NULL),79);
+
+@ Now we're ready to test the mechanics of reading data files,
+sorting with |gb_sort|, and heavy randomization. Lots of computation
+takes place in this section.
+
+@<Print samp...@>=
+print_sample(book("homer",500,400,2,12,10000,-123456,789),81);
+print_sample(econ(40,0,400,-111),11);
+print_sample(games(60,70,80,-90,-101,60,0,999999999),14);
+print_sample(miles(50,-500,100,1,500,5,314159),20);
+print_sample(plane_mona(100,100,50,1,300,1,200,50*299*199,200*299*199),1294);
+print_sample(plane_miles(50,500,-100,1,1,40000,271818),14);
+print_sample(random_bigraph(300,3,1000,-1,0,dst,-500,500,666),3);
+print_sample(roget(1000,3,1009,1009),40);
+
+@ Finally, here's a picky, picky test that is supposed to fail the first time,
+succeed the second. (The weight vector just barely exceeds
+the maximum weight threshold allowed by |gb_words|. That test is
+ultraconservative, but eminently reasonable nevertheless.)
+
+@<Print samples...@>=
+print_sample(words(100,wt_vector,70000000,69),5);
+wt_vector[1]++;
+print_sample(words(100,wt_vector,70000000,69),5);
+
+@ @<Private...@>=
+static int wt_vector[]=
+ {100,-80589,50000,18935,-18935,18935,18935,18935,18935};
+
+@* Printing the sample data. Given a graph |g| in GraphBase format and
+an integer~|n|, the subroutine |print_sample(g,n)| will output
+global characteristics of~|g|, such as its name and size, together with
+detailed information about its |n|th vertex. Then |g| will be recycled.
+
+@<Procedures@>=
+void print_vert(); /* a subroutine for printing a vertex is declared below */
+void print_arc(); /* likewise for arcs */
+void print_util(); /* and for utility fields in general */
+void print_sample(g,n)
+ Graph *g; /* graph to be sampled and destroyed */
+ int n; /* index to the sampled vertex */
+{
+ printf("\n");
+ if (g==NULL) {
+ printf("Ooops, we just ran into panic code %d!\n",panic_code);
+ if (io_errors)
+ printf("(The I/O error code is 0x%x)\n",io_errors);
+ } else {
+ @<Print global characteristics of |g|@>;
+ @<Print information about the |n|th vertex@>;
+ gb_recycle(g);
+ }
+}
+
+@ The graph's |format| field is used to determine how much information
+should be printed. A level parameter also helps control the verbosity of
+printout. In the most verbose mode, each utility field that points to a
+vertex or arc or contains integer or string data will be printed.
+
+@<Procedures@>=
+void print_vert(v,l,s)
+ Vertex *v; /* vertex to be printed */
+ int l; /* |<=0| if the output should be terse */
+ char *s; /* format for graph utility fields */
+{
+ if (v==NULL) printf("NULL");
+ else if (is_boolean(v)) printf("ONE"); /* see |gb_gates| */
+ else {
+ printf("\"%s\"",v->name);
+ print_util(v->u,s[0],l-1,s);
+ print_util(v->v,s[1],l-1,s);
+ print_util(v->w,s[2],l-1,s);
+ print_util(v->x,s[3],l-1,s);
+ print_util(v->y,s[4],l-1,s);
+ print_util(v->z,s[5],l-1,s);
+ if (l>0) {@+register Arc *a;
+ for (a=v->arcs;a;a=a->next) {
+ printf("\n ");
+ print_arc(a,1,s);
+ }
+ }
+ }
+}
+
+@ @<Pro...@>=
+void print_arc(a,l,s)
+ Arc *a; /* non-null arc to be printed */
+ int l; /* |<=0| if the output should be terse */
+ char *s; /* format for graph utility fields */
+{
+ printf("->");
+ print_vert(a->tip,0,s);
+ if (l>0) {
+ printf( ", %d",a->len);
+ print_util(a->a,s[6],l-1,s);
+ print_util(a->b,s[7],l-1,s);
+ }
+}
+
+@ @<Procedures@>=
+void print_util(u,c,l,s)
+ util u; /* a utility field to be printed */
+ char c; /* its format code */
+ int l; /* 0 if output should be terse, |-1| if pointers omitted */
+ char *s; /* format for overall graph */
+{
+ switch (c) {
+ case 'I': printf("[%d]",u.i);@+break;
+ case 'S': printf("[\"%s\"]",u.s);@+break;
+ case 'A': if (l<0) break;
+ printf("[");
+ if (u.a==NULL) printf("NULL");
+ else print_arc(u.a,l,s);
+ printf("]");
+ break;
+ case 'V': if (l<0) break; /* avoid infinite recursion */
+ printf("[");
+ print_vert(u.v,l,s);
+ printf("]");
+ default: break; /* case |'Z'| does nothing, other cases won't occur */
+ }
+}
+
+@ @<Print information about the |n|th vertex@>=
+printf("V%d: ",n);
+if (n>g->n || n<0) printf("index is out of range!\n");
+else {
+ print_vert(g->vertices+n,1,g->format);
+ printf("\n");
+}
+
+@ @<Print global characteristics of |g|@>=
+printf("\"%s\"\n%d vertices, %d arcs, format %s",
+ g->id,g->n,g->m,g->format);
+print_util(g->u,g->format[8],0,g->format);
+print_util(g->v,g->format[9],0,g->format);
+print_util(g->w,g->format[10],0,g->format);
+print_util(g->x,g->format[11],0,g->format);
+print_util(g->y,g->format[12],0,g->format);
+print_util(g->z,g->format[13],0,g->format);
+printf("\n");
+
+@* Index.
+
diff --git a/support/graphbase/word_components.w b/support/graphbase/word_components.w
new file mode 100644
index 0000000000..248524ff52
--- /dev/null
+++ b/support/graphbase/word_components.w
@@ -0,0 +1,126 @@
+% This file is part of the Stanford GraphBase (c) Stanford University 1992
+\def\title{WORD\_\thinspace COMPONENTS}
+@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
+
+\prerequisite{GB\_WORDS}
+@* Components. \kern-.7pt
+This simple demonstration program computes the connected
+components of the GraphBase graph of five-letter words. It prints the
+words in order of decreasing weight, showing the number of edges,
+components, and isolated vertices present in the graph defined by the
+first $n$ words for all~$n$.
+
+@f Vertex int
+@f Arc int
+@f Graph int
+
+@p
+#include "gb_graph.h" /* the GraphBase data structures */
+#include "gb_words.h" /* the |words| routine */
+@#
+main()
+{@+Graph *g=words(0,0,0,0); /* the graph we love */
+ Vertex *v; /* the current vertex being added to the component structure */
+ Arc *a; /* the current arc of interest */
+ int n=0; /* the number of vertices in the component structure */
+ int isol=0; /* the number of isolated vertices in the component structure */
+ int comp=0; /* the current number of components */
+ int m=0; /* the current number of edges */
+ printf("Component analysis of %s\n",g->id);
+ for (v=g->vertices; v<g->vertices+g->n; v++) {
+ n++, printf("%4d: %5d %s",n,v->weight,v->name);
+ @<Add vertex |v| to the component structure, printing out any
+ components it joins@>;
+ printf("; c=%d,i=%d,m=%d\n", comp, isol, m);
+ }
+ @<Display all unusual components@>;
+}
+
+@ The arcs from |v| to previous vertices all appear on the list |v->arcs|
+after the arcs from |v| to future vertices. In this program, we aren't
+interested in the future, only the past; so we skip the initial arcs.
+
+@<Add vertex |v| to the component structure, printing out...@>=
+@<Make |v| a component all by itself@>;
+a=v->arcs;
+while (a && a->tip>v) a=a->next;
+if (!a) printf("[1]"); /* indicate that this word is isolated */
+else {@+int c=0; /* the number of merge steps performed because of |v| */
+ for (; a; a=a->next) {@+register Vertex *u=a->tip;
+ m++;
+ @<Merge the components of |u| and |v|, if they differ@>;
+ }
+ printf(" in %s[%d]", v->master->name, v->master->size);
+ /* show final component */
+}
+
+@ We keep track of connected components by using circular lists, a
+procedure that is known to take average time $O(n)$ on truly
+random graphs [Knuth and Sch\"onhage, {\sl Theoretical Computer Science\/
+\bf 6} (1978), 281--315].
+
+Namely, if |v| is a vertex, all the vertices in its component will be
+in the list
+$$\hbox{|v|, \ |v->link|, \ |v->link->link|, \ \dots,}$$
+eventually returning to |v| again. There is also a master vertex in
+each component, |v->master|; if |v| is the master vertex, |v->size| will
+be the number of vertices in its component.
+
+@d link z.v /* link to next vertex in component (occupies utility field |z|) */
+@d master y.v /* pointer to master vertex in component */
+@d size x.i /* size of component, kept up to date for master vertices only */
+
+@<Make |v| a component all by itself@>=
+v->link=v;
+v->master=v;
+v->size=1;
+isol++;
+comp++;
+
+@ When two components merge together, we change the identity of the master
+vertex in the smaller component. The master vertex representing |v| itself
+will change if |v| is adjacent to any prior vertex.
+
+@<Merge the components of |u| and |v|, if they differ@>=
+u=u->master;
+if (u!=v->master) {@+register Vertex *w=v->master, *t;
+ if (u->size<w->size) {
+ if (c++>0) printf("%s %s[%d]", (c==2? " with": ","), u->name, u->size);
+ w->size += u->size;
+ if (u->size==1) isol--;
+ for (t=u->link; t!=u; t=t->link) t->master=w;
+ u->master=w;
+ } else {
+ if (c++>0) printf("%s %s[%d]", (c==2? " with": ","), w->name, w->size);
+ if (u->size==1) isol--;
+ u->size += w->size;
+ if (w->size==1) isol--;
+ for (t=w->link; t!=w; t=t->link) t->master=u;
+ w->master=u;
+ }
+ t=u->link;
+ u->link=w->link;
+ w->link=t;
+ comp--;
+}
+
+@ The |words| graph has one giant component and lots of isolated vertices.
+We consider all other components unusual, so we print them out when the
+other computation is done.
+
+@<Display all unusual components@>=
+printf("\nThe following non-isolated words didn't join the giant component:\n");
+for (v=g->vertices; v<g->vertices+g->n; v++)
+ if (v->master==v && v->size>1 && v->size <4000) {@+register Vertex *u;
+ int c=1; /* count of number printed on current line */
+ printf("%s", v->name);
+ for (u=v->link; u!=v; u=u->link) {
+ if (c++==12) putchar('\n'),c=1;
+ printf(" %s",u->name);
+ }
+ putchar('\n');
+ }
+
+@* Index. We close with a list that shows where the identifiers of this
+program are defined and used.
+
diff --git a/support/graphbase/words.dat b/support/graphbase/words.dat
new file mode 100644
index 0000000000..267943eda6
--- /dev/null
+++ b/support/graphbase/words.dat
@@ -0,0 +1,5683 @@
+* File "words.dat" from the Stanford GraphBase (C) 1992 Stanford University
+* A database of English five-letter words
+* This file may be freely copied but please do not change it in any way!
+* (Checksum parameters 5678,99373046)
+aargh
+abaca 2
+abaci+1
+aback*2,2,3
+abaft
+abase+,,,,3
+abash*
+abate*,,2,,2
+abbey*3,1,3
+abbot*3,1
+abeam
+abend
+abets+1
+abhor*,,,,19
+abide*10,6,3,,34,1
+abled
+abler*,2
+abode+5,4,3,,11
+abort*,,,,,7
+about*12496,1813,1898,186,846,325,181
+above*2298,295,296,24,174,181,31
+absit ,,2
+abuse*9,16,10,12,13,1,3
+abuts+,,1,,,1
+abyss*5,4,4,,7
+ached*27,3,7
+aches*10,1
+achoo+1
+acids*59,7,1
+acing*
+acked
+acmes+
+acnes*
+acorn*10,,1
+acres*159,42,31,,1
+acrid*1,1,3,1
+acted*83,18,21,2,38,3
+actin
+actor*44,24,18,2
+acute*38,13,21,2,,5
+adage*1,3,4
+adapt*25,5,5,,,7
+added*972,172,221,5,29,67,18
+adder*2,,,,4
+addle+
+adept*4,4,1,2
+adieu+14,1,1
+adios*,1,2
+adlib+
+adman+
+admen 2
+admit*74,37,46,2,4,,2
+admix+
+adobe*40,2
+adopt*16,13,23,9,2,4,3
+adore*4,2,4
+adorn*6,1,4,1,8
+adult*152,25,36,6,,,1
+adzes*,,1
+aegis+,1
+aerie+1
+affix*5,1,22
+afire*13,1
+afoot*14,1,2
+afore*7,,1
+afoul+2
+after*5915,1067,1120,86,704,571,109
+again*3892,576,663,36,486,113,78
+agape 1,,2,,1
+agars
+agate*2,,,,5
+agave+2
+agent*79,44,29,,1
+agile*11,2,2,,1
+aging*13,4,,,1
+agley
+aglow+3,,2,,1
+agone
+agony*23,9,23,,5
+agora+
+agree*262,51,107,23,15,14,1
+agues+
+ahead*639,109,92,17,23,35,2
+ahhhh+,,1
+ahoys
+aided*25,11,8,,3
+aider
+aides*6,4,1
+ailed*1
+aimed*45,24,21,8,1
+aioli
+aired*,2,3
+airer
+aisle*15,6,5
+aitch
+ajuga
+alack+6
+alarm*105,16,28,1,17,1
+album*11,6,1
+alder*8
+aleck+2,2
+aleph+4
+alert*63,32,16,3,3,2,1
+algae*64,7,4
+algal 1
+algin
+alias*,1,1
+alibi*3,8,3
+alien*17,16,26,2,21
+align+4,2,,,,1
+alike*463,20,24,8,29
+alive*376,57,52,3,132,4
+alkyd
+alkyl
+allay*2,1,2,1
+alley*43,8,4,1
+allot*3,1,,,5
+allow*229,72,75,24,15,33,16
+alloy*34,3,14,,1
+aloes+1,2,,,5
+aloft*25,3,4,,3
+aloha+8
+alone*825,194,218,10,167,2,5
+along*2835,355,250,15,114,10,11
+aloof*8,5,6,1,6
+aloud*230,13,13,1,51,,1
+alpha+9,,1,,,6
+altar*24,4,13,,432
+alter*32,15,14,2,3,1
+altho ,4,2
+altos*3,,1,,,1
+alums*
+alway 2
+amahs ,,2
+amass*2,2
+amaze*2,3
+amber*14,3,6
+ambit ,,2
+amble*1,,2
+ameba+23
+amend*2,2,4,1,5
+amens+
+amide ,1
+amigo*5,2
+amine
+amino+38,1
+amiss*2,2,2,2,4,2
+amity+1,1,1
+ammos
+among*1308,369,313,40,1021,9,22
+amour+
+amped
+ample*18,16,15,1,4
+amply+2,4,4,1,1,,1
+amuck+2
+amuse*23,3,3
+amyls
+anded+
+anent
+angel*45,9,13,,242
+anger*108,48,39,,316
+angle*462,51,40,,,67,2
+angry*402,44,42,4,117
+angst+
+anile
+anima ,,1
+anion+,1,4
+anise+1,2
+ankhs+
+ankle*40,8,8
+annas 4
+annex*14,1,2
+annoy*13,2,,,3
+annul+1,,1,,4
+annum+5,3,17
+anode*4,77,5
+anole 3
+anted+
+antes+
+antic*2,1
+antis
+antsy+
+anvil*33,1,,,2
+aorta*5,3
+apace+2,,1,,2
+apart*414,57,134,10,57,23,8
+apers
+aphid*4
+aphis 1,,1
+apian
+aping*,,1
+apish
+apnea
+aport
+apple*294,9,7,,8,,3
+apply*192,56,67,9,5,42,56
+apron*96,7,12
+apses+,1
+apsos
+aptly*5,4,2,2
+aquae
+aquas+
+arbor*7,,1
+arced*
+ardor*3,3
+areal 1
+areas*689,236,117,27,,3,4
+arena*26,7,5,,2
+argon*15,6,1
+argot+,1
+argue*49,29,27,10,6,,3
+arias+,,2
+arise*52,28,33,3,76,18,23
+arity
+armed*103,35,22,8,49,1,1
+armor*60,4,,,32
+aroma*9,3,5,,2
+arose*77,18,20,2,153,2
+array*57,11,3,,20,12,16
+arrow*193,13,1,,25,13
+arses
+arson*2,2,1
+artsy+
+arums
+asana
+ascot+
+ashen*2,2,1
+ashes*87,6,5,1,64
+aside*182,66,38,11,118,,1
+asked*2924,398,448,30,178,12,6
+asker
+askew*2,1,2
+aspen*9,2
+aspic*1
+assay*,1,3,,1
+assed
+asses*6,2,,,64
+asset*13,5,11,1
+aster*3
+astir*7,,1
+astro 1
+atilt
+atlas*39,,4,,,1
+atoll*6
+atoms*332,41,9,,,24
+atone*,1,1,,3
+atria
+attar
+attic*45,14,15
+audio+9,2
+audit+,4
+auger*13,,4
+aught 4
+augur+,,1,,1
+aunts*26,4,1
+aurae
+aural 1,1,3
+auras+
+auric
+autos*8,4
+avail+9,4,4,,11
+avant+4,1,1
+avast 3
+avers*
+avert*6,1,3,,7
+avian+
+avoid*246,58,69,14,13,42,6
+avows+
+await*19,9,8,1,5
+awake*134,19,13,1,29
+award*30,38,25,,1
+aware*172,84,83,7,14,6,2
+awash+3,1,,1
+aways+2
+awful*2,17,19,1,1,4
+awing
+awoke*54,9,6,,19
+axial+2,2
+axing+
+axiom+10,1,5
+axled
+axles*7,1,1,,4
+axman+
+axmen 1
+axons+2
+ayins+
+azine
+azoic
+azure+8
+babel+,,1
+babes*1,3,1,,15
+backs*99,15,3,,12,3
+bacon*99,8,21,,,2
+baddy
+badge*12,5,1
+badly*159,34,44,1,3,3
+bagel*
+baggy*11,4,3
+bahts
+bails*,,1
+bairn
+baits*1
+baize+,,1
+baked*93,8,5,,16,1
+baker*19,10,2,,9
+bakes*10,1,,,1
+balds
+baled*3
+baler+1,,1
+bales*21,3,8
+balks+,1,,,,1
+balky+1
+balls*170,17,3,2,,,2
+bally 1
+balms+
+balmy*3,2
+balsa*6
+banal+1,2
+bands*142,11,28,2,10,1
+bandy+3
+banes*
+bangs*10,4
+banjo*32,1
+banks*219,23,24,5,1
+banns+,,2
+barbs*16,2
+bards+2,2
+bared*14,,1,,2
+barer*
+bares*1,,1
+barfs
+barfy
+barge*35,7,11
+barks*19,,1
+barky
+barms
+barmy+
+barns*44,4,,,4
+baron*13,2,2,,,1
+basal+3,,3
+based*361,119,140,25,5,73,31
+baser*1,1,2
+bases*131,23,26,2,54,5
+basic*517,170,81,14,,45,42
+basil+5
+basin*62,5,11,,17
+basis*189,184,144,10,1,6,15
+basks*
+bassi
+basso+1,1
+baste*5,,1
+batch*9,5,11,1
+bated+2
+bates
+bathe*22,4,6,1,29
+baths*18,5,14,,9
+batik+
+baton*11,5,5
+batty+
+bauds
+baulk ,,1
+bawdy+1,3
+bawls*
+bayed*,3
+bayou*3
+bazar ,,2
+beach*308,33,35,7,5
+beads*143,3,7,,1,,2
+beady+7,1,2,1
+beaks*29,,2
+beaky ,,1
+beams*66,13,2,,14
+beamy
+beano
+beans*199,9,7,,2
+beard*89,25,7,,18
+bears*195,17,20,1,37,,1
+beast*103,7,10,,147
+beats*210,4,7
+beaus*
+beaut+1
+beaux ,,1
+bebop+,1
+bebug
+becks
+bedew
+bedim
+beech*19,2,5
+beefs*
+beefy+,1,1
+beeps*5,3
+beers*1,1,1
+beery
+beets*44,2
+befit*1,,,,1
+befog+
+began*2491,312,270,6,226,17,8
+begat 1
+beget+1,1,2,,3
+begin*976,84,86,15,27,69,18
+begot 2,,,,5
+begun*205,51,53,9,15,14,1
+beige*15,1,3
+being*2092,709,962,86,303,187,28
+belay 2
+belch*1,2,,,1
+belie+,,1
+belle+3,1,2
+belli ,,1
+bells*303,6,10,,5,1
+belly*46,23,6,,22
+below*3276,145,150,16,19,123,14
+belts*86,8,2,,3,,1
+bench*140,28,28,6
+bends*73,2,5,,5,11
+bents
+beret*4,,2,1
+bergs ,1
+berms
+berry*16,4,3,,,1
+berth*14,3
+beryl+6,,,,6
+beset*6,7,4,,8
+besot
+bests*
+betas+
+betel+1
+beths
+bevel*27,2,1
+bhang
+bhoys ,,1
+bibbs+
+bible*1,1,6
+biddy+
+bided*
+bider
+bides*
+bidet+,,3
+biers*
+biffs
+biffy
+biggy
+bight
+bigly
+bigot*
+biked*
+biker+
+bikes*19,,,1
+biles
+bilge+1,2
+bilgy
+bilks+
+bills*96,45,17,1,,2
+billy+15,,,1
+bimbo+
+binds*4,2,1,2,14
+binge+1,1
+bingo*1,,1
+biome
+biped+
+bipod 1
+birch*33,1,1
+birds*1203,47,70,1,109
+birth*147,63,63,6,79
+bison*18,1
+bitch*4,6,1
+biter+,1
+bites*41,8,3,,5
+bitsy 2
+bitty 3
+blabs+
+black*1556,162,164,4,16,52
+blade*137,13,17,,4,1
+blahs+
+blame*79,34,27,12,8
+bland*6,3,6,4
+blank*255,14,10,,,113,1
+blare*5
+blash ,,,,,2
+blast*74,15,15,,11
+blats+
+blaze*34,7,7,,2
+bleak*19,9,22,3
+blear
+bleat*8,1,,,1
+blebs ,1
+bleed*13,2,1
+blend*175,9,10,,,3
+bless*36,9,11,,13
+blest+6,3
+blimp*
+blind*181,47,25,2,82
+blini
+blink*16,4,2
+blips+,1
+bliss*60,4,5
+blitz*,2,1,1
+bloat*2,8
+blobs*2,,2,,,1
+block*328,66,45,8,16,8,1
+blocs+2,,1
+bloke+,1,4
+blond*22,11,11
+blood*705,119,168,2,466
+bloom*63,11,4,,4
+blots*,4,1,,2,1
+blown*88,9,12,,9
+blows*124,8,12,,16
+blowy 1
+blued+1
+bluer*1
+blues*35,13,5
+bluff*27,8,6,2
+blunt*25,9,9,,1,4
+blurb*,,1
+blurs*1
+blurt*
+blush*13,1,5,,4
+board*536,174,179,26,6,1,5
+boars*2,,,,1
+boast*18,8,5,,53
+boats*391,50,19,5,1
+bobby+7,13
+bocce
+bocci
+bocks
+boded+,,1
+bodes+1,1
+bodge
+boffo+
+boffs
+bogey*,5
+boggy 2
+bogie*
+bogus+1,3,4
+boils*23,2,1,1,6,1,2
+bolas 2
+bolls+9
+bolts*37,1,4,2,7
+bombe+
+bombs*38,35,16
+bonds*50,47,7,,23
+boned*1
+boner*
+bones*491,20,17,1,101
+bongo+4,1
+bongs*1
+bonks
+bonne ,,2
+bonny+8,,2
+bonus*21,2,18,,,3,11
+boobs+
+booby*7,4
+booed*4
+books*902,95,156,3,17,24,1
+booky
+booms*9,,,1
+boomy
+boons+
+boors+,1
+boost*12,15,5,3
+booth*32,5,2,,5
+boots*176,19,26,,,,5
+booty*5,2,3,,23
+booze*,4,1
+boozy+
+borax+14,1,4
+bored*48,14,15,,1,1
+borer+2,1
+bores*2,2,4
+boric+4
+borne+25,8,13,,44
+boron+6
+bosky
+bosom*16,8,6,,42
+bossa+
+bossy*8,,1
+bosun+
+botch+
+bough*20,2,1,,3
+boule
+bound*170,42,74,5,103,8,35
+bouts*6,3,7
+bowed*66,7,10,,72
+bowel*1,,1
+bower+4,1
+bowie+1
+bowls*53,3,5,,32,1
+boxed*11,2,1,,,1
+boxer*23,1,5,1
+boxes*331,14,24,2,1,245,3
+bozos+
+brace*20,11,4,,,47
+brack ,,1
+bract
+brads+2
+braes
+brags*4
+braid*20,,4
+brain*330,44,4
+brake*73,2,7
+brand*52,17,22,1,2,3,1
+brans*
+brant
+brash+2,1,3
+brass*191,18,33,1,11
+brats*,,4
+brave*282,20,20,1,13,2
+bravo*7
+brawl*3,1,1
+brawn*2
+brays*1
+braze+1
+bread*515,41,41,2,347
+break*516,88,75,6,141,183,1
+bream ,,23
+breed*47,16,21,1,4
+brent ,,1,,,,1
+breve+2,,,,,3
+brews*3,,1
+briar*2,,3
+bribe*6,1,1,,22,,1
+brick*132,18,12,,4,,3
+bride*53,32,17,,24
+brief*160,73,60,2,8,5
+brier+6,,1,,3
+bries+
+brigs+
+brims*1
+brine*14
+bring*1016,158,191,16,702,5,4
+brink*13,3,4,4,5
+briny+3
+brisk*26,7,3
+broad*292,83,37,10,38,1
+broil*9,2
+broke*396,71,70,3,101,1,2
+bromo
+bronc+1,3
+bronx 1
+brood*20,9,4,,11
+brook*76,1,1,,37
+broom*78,2,1,1,5
+broth*16,3,8,,4
+brown*557,68,68,3,,1
+brows*12,5,6
+bruin+
+brung 4
+brunt*2,1,1
+brush*251,42,14,2,1,1
+brusk
+brute*11,6,4,,,1,1
+bubba
+bucks*10,5
+buddy*9,12
+budge*21,3,2
+buena
+bueno 1,1
+buffa 1,,1
+buffo
+buffs*2,1
+buggy*51,6,,,,1
+bugle*48,1,,,1
+build*857,86,43,12,164,9,2
+built*1249,102,150,14,249,26,2
+bulbs*40,3,2,,,1
+bulge*14,4,9
+bulgy+1,,1
+bulks*2,1
+bulky*25,9,6
+bulls*20,2,6,,63
+bully*16,4,6
+bumph
+bumps*24,1,1,,,2
+bumpy+17,,1
+bunch*105,17,12,,1,8,5
+bunco+
+bunds
+bungs
+bunko
+bunks*11,17,2
+bunny*5
+bunts*
+buoys*7,1
+burgs+
+burls+
+burly*10,3,5
+burns*91,16,2,1,20,1
+burnt+43,5,11,,334
+burps+
+burro*55
+burrs*8,1
+burry
+burst*194,33,28,,2
+busby
+bused*
+buses*61,6,12,9
+bushy*25,,1
+busks
+busts*,3,3
+busty+
+butch+1
+butte*4
+butts*3,5,2
+butyl+
+buxom*,1,1
+buyer+30,2,6,1,5
+buzzy
+bylaw*
+byres ,,1
+bytes+,,,,,12
+byway+
+cabal+
+cabby+
+cabin*404,21,26,1,,,1
+cable*66,5,23
+cacao*26,1
+cache*5,1,1
+cacti+16
+caddy+,,2
+cadet*6,2,3
+cadge+
+cadre+,3,2
+cafes*9,5,4
+caged*7,1,2
+cager+
+cages*42,2,5
+cagey+,2
+cairn+
+caked*11,2
+cakes*133,3,12,,28
+calix
+calks
+calla
+calls*216,70,55,3,41,19,5
+calms*7,,1
+calve+,,1
+calyx+5
+camel*72,1,5,,1
+cameo+3
+campo
+camps*49,18,8,1,1
+campy+
+canal*153,,20,1,2
+candy*256,16,2
+caned*
+caner
+canes*7,,2
+canna
+canny*2,2
+canoe*164,6,,1
+canon*21,3,3
+canst+6,,,,4
+canto+,3,,,,1
+cants
+caped+2
+caper*3,2,1
+capes*6,4
+capon+
+capos+
+carat*5
+cards*186,33,19,5,,,26
+cared*68,15,9,,4
+carer
+cares*35,8,3,2,14
+caret+1,,,,,4
+cargo*106,6,7,,5
+carne 3,3
+carny+
+carob+,1
+carol*22,1,3
+carom+
+caron+,,,,,1
+carps*
+carpy
+carry*940,88,86,12,121,9,16
+carte ,1,2
+carts*40,5,,,2
+carve*30,3,1,1,1
+casas
+cased*,1
+cases*307,148,209,17,11,135,124
+casks*4,1,1
+caste*16,3,5
+casts*23,6,,,16
+casus ,,1
+catch*679,43,43,1,11,5,1
+cater*1,3,5,1
+catty+
+caulk+
+cauls
+cause*502,130,119,13,151,47,4
+caved+4,1
+caves*75,5,3,,9
+cavil+
+cawed+3
+cease*27,15,22,1,51
+cedar*31,,2,,55
+ceded*1,,,1
+ceder
+cedes*
+ceils
+celeb
+cello*28
+cells*747,81,56,,1,7,6
+cento
+cents*479,25,4,3,,1,5
+chafe*,1,1
+chaff*2,,,,16
+chain*204,48,38,1,11,,4
+chair*421,66,87,1,1,1
+chalk*109,3,7
+champ*11,,2,,,,1
+chant*61,2,1,,2
+chaos*16,17,13,5,6,4,1
+chaps*12,1,5
+chard+
+charm*54,26,19,,5
+chars ,,,,,1
+chart*393,17,4,,,5
+chary+,,1
+chase*88,10,18,,5,1,1
+chasm*2,2,1,,1
+chats*1
+chaws+
+cheap*60,24,38,8,1,1,1
+cheat*12,2,8,1,2,,1
+check*1024,88,58,3,,32,37
+cheek*87,20,22,,9
+cheep*6,,1
+cheer*88,7,11,,10,1
+chefs*1
+chert ,,1
+chess*21,3,2
+chest*231,53,42,,6
+chews*8,,,,5
+chewy*2
+chick*21,2,1
+chide*2,2,1,,1
+chief*428,89,95,21,187,5
+chiff+
+child*730,210,245,7,212,3
+chile 1
+chili*12,6,1
+chill*57,14,9
+chime*3,,3
+chimp*5
+china*34,6,5
+chine ,,7
+chink+1
+chino
+chins*5,2
+chips*42,2,4
+chirp*12,,,,1
+chits+
+chive+1,1
+chock+
+choir*30,4,8
+choke*12,9,5,,2
+chomp+,1
+choos 1
+chops*22,3,3
+chord*303,7,6
+chore*13,7,1,,,1
+chose*171,37,17,3,65,3,3
+chows*
+chuck*21,11,3
+chugs*4
+chump+,1
+chums*3,,1
+chunk*21,2
+churl
+churn*21,,,1
+chute*17,2
+cider*19,2,2,1
+cigar*30,10,5
+cilia+22,1
+cills ,,4
+cinch*6,3
+circa+,1,3
+cirri
+cited*7,24,12,2,,1,1
+cites*4,10,1
+civet*2
+civic*12,19,12,5
+civil*81,45,95,13
+civvy
+clack+,,3
+clads+
+claim*125,97,106,23,8,2,5
+clamp*41,,6
+clams*50,2
+clang*9,1,1
+clank*6
+clans*,,2,,9
+claps*9,2,,,2
+clash*11,5,17,,,2
+clasp*6,,12,,1
+class*1211,166,138,4,1,24,15
+clave 3
+claws*146,3,1,,3
+clays*5,1,3
+clean*521,69,70,4,127,3,1
+clear*811,219,203,31,43,27,17
+cleat*1,1
+clefs*3
+cleft*12,2,1,,8
+clerk*104,34,17,,1
+clews
+click*31,2,7
+cliff*94,9,12,,2
+climb*288,12,18,,4,,3
+clime+,,1
+cling*36,6,2,,2
+clink*7
+clips*30,2,1
+cloak*42,3,10,1,9
+clock*330,20,35,2,,2,1
+clods*3,4,3,,3
+clogs*7,,1
+clomp+3
+clone+
+clops+
+close*1288,233,204,18,45,33,17
+cloth*427,42,18,,17
+clots*4
+cloud*314,26,25,5,111
+clout*3,1,1,4
+clove*3,1
+clown*62,3
+cloys+
+clubs*73,19,31,2,5
+cluck*7,2
+clued*
+clues*125,10,6,1,,6
+clump*36,4,1
+clung*54,14,9,1,6
+clunk+3
+coach*147,19,4
+coals*42,8,6,,23
+coast*594,33,41,5,6
+coati+1
+coats*120,10,9,,11
+cobra*15,3
+cocas
+cocci*2,,1
+cocks*11,,1
+cocky*2,3,1
+cocoa*57,3,7
+cocos*1
+codas+
+coded*5,1,2,,,4
+coder+
+codes*10,17,4,,,121
+codex+,,12
+codon+
+coeds*,1
+cohos+3
+coifs+
+coils*32,2,1
+coins*161,9,7,,4,,16
+coked+
+cokes*,,1
+colas+
+colds*15,2,1
+colic*,,,,1
+colon*19,2,2,,,22
+color*1109,139,,3,9,4,9
+colts*30,6,2,,1
+comas*,1
+combo+9,4
+combs*14
+comer+2,1
+comes*1289,134,133,10,319,103,45
+comet*21,1,7
+comfy+1
+comic*39,8,16
+comma*90,2,2,,,27
+comps+
+conch*3
+condo+
+coned+
+cones*62,2,,,,,1
+coney ,1
+conga+2,1
+conic*3,2,,,,,1
+conks+
+cooch ,2
+cooed*4
+cooks*36,8,6,,1
+cooky*13,2
+cools*77,2
+coons+5
+coops*1,1
+coots+1
+coped*2,,1
+coper
+copes*,1,,,,1
+copra*5,2
+copse*1
+coqui 1
+coral*85,1,4,,3
+cords*51,2,15,,34
+cordy
+cored*
+corer+
+cores*14,3,1
+corgi
+corks*2,1
+corky 1
+corms ,,1
+corns*1,2
+cornu 1
+corny*4,1,2
+corps*11,25,9,1
+coset+
+costa ,,1
+costs*159,176,82,25,,4,2
+cotes
+cotta+1
+couch*37,12,9,,13
+cough*30,7,5,,,2
+could*8585,1597,1741,164,258,158,76
+count*435,44,36,2,33,16,1
+coupe+25,2
+coups+,2,2
+court*236,122,166,35,137,1
+couth
+cover*604,87,92,9,77,12,11
+coves*3,1
+covet*4,1,2,,11
+covey*1,,1
+cowed*,,1
+cower*,,,,4
+cowls*
+cowry+
+coxed+
+coxes+
+coyer
+coyly*3,1,1
+coypu ,,8
+cozen
+crabs*40,2
+crack*144,21,10,,1,,1
+craft*87,22,46,,5,2
+crags*7,2,,,2
+cramp*4,2,13,,,1
+crams*
+crane*36,1,10,,2
+crank*36,1,3,,,1
+craps+
+crash*106,20,10,,7
+crass+,2
+crate*21,2,3
+crave*1,2,1,,2
+crawl*67,11,3,,,,3
+craws+
+craze*2,2,2
+crazy*86,32,22,,,1,1
+creak*12,1,3
+cream*300,20,23
+credo+1,7
+creed*8,6,4
+creek*102,8,5,1
+creel+
+creep*36,10,7,,2
+creme
+crepe+7,1,1
+crept*89,11,5,,,2
+cress*
+crest*41,12,4
+crews*39,2,7
+cribs*2,3
+crick+1
+cried*1043,30,40,,165,8,1
+crier+6
+cries*89,6,20,2,23,,2
+crime*52,33,44,8,14
+crimp+1
+crink
+crisp*62,8,3,,,1
+crits
+croak*9,1,,,1
+crock*3
+crocs 2
+croft+,,2
+crone*,2,1
+crony*
+crook*17,3,3
+croon*3
+crops*536,18,17,,11
+cross*498,44,71,1,45,15,6
+croup*1
+crowd*396,52,62,,84
+crown*87,17,51,1,88
+crows*43,1,,,6
+crude*67,15,13,5,,,1
+cruds
+cruel*95,15,16,,24
+cruet*
+cruft
+crumb*7,,1
+cruse+,,,,3
+crush*23,3,1,,3
+crust*160,1,4
+crypt+,1
+cubby+,,1
+cubed*2,1,1,,,,1
+cuber
+cubes*73,4,1,,,1,6
+cubic*94,15,9,,,,1
+cubit+6,,,,41
+cuffs*28,2,5
+cuing
+cukes
+culls*,,1,,,1
+culpa 2
+cults+3,4,2
+cumin+2,1
+cunts
+cupid*
+cuppa
+cuppy
+curbs*5,3
+curds*18,1,,,8
+curdy
+cured*24,7,9,,9,3
+curer
+cures*10,3,2,,1
+curia ,,1
+curie+
+curio+,2,1
+curls*42,1,5,,,2
+curly*44,5,3,,,13,1
+curry*13,1,6
+curse*13,11,4,,104
+curve*174,45,47,,,79,9
+curvy+2
+cushy+
+cusps+1,,,,,2
+cuspy+
+cuter*
+cutie+1
+cutup+
+cycad ,,1
+cycle*125,24,26,,1,66,4
+cynic*1,,1
+cysts*,3
+czars*1
+dacha+1
+daddy*14,3,2
+dados+
+daffy+
+daily*229,99,82,3,34
+dairy*131,19,23
+daisy*9,,1
+dales*1,1
+dally*
+dames*,,1
+damns*,,2
+damps*3
+dance*608,84,61,1,15
+dandy*17,4
+dared*68,14,12,,7
+darer
+dares*8,3,1,,3
+darks*3
+darky
+darns*1
+darts*36,,,,2
+dashy
+dated*14,19,7,2
+dater
+dates*109,30,29,,,1
+datum*1,1,1
+daubs*,,1
+daunt*,1,1
+dawns*2,1,,,4
+dazed*,4,10,,1
+dazes*
+deads*
+deals*37,15,25,3,10,16,3
+dealt*21,22,31,3,61,2
+deans*,1
+dears*3
+deary 5
+death*518,268,229,12,542,1,3
+debar
+debit+
+debts*36,11,10,1,4
+debug+,,,,,1
+debut*5,14,12
+decaf+
+decal*
+decay*67,13,24,,3
+decks*24,6,3,,3
+decor+2,4,3
+decoy*5,,,,1
+decry+,2,1
+deeds*39,8,9,,197
+deems+2,,1,,1
+deeps+4,1,1,,7
+defer*,1,3,3,3,3,2
+defog
+defun
+deice+
+deify+
+deign*,,1,,1
+deism+
+deist+
+deity*4,2,1,,2
+delay*42,21,28,8,31,3
+delft
+delis+
+dells*1
+delta*25,,1,,,1,1
+delve*,,2,,,1
+demon*17,5,9,,28
+demos+
+demur+1,,1
+denim*11
+dense*86,9,6,,1
+dents*4
+depot*19,3,5
+depth*167,53,55,1,8,164,3
+deque
+derby*3,4
+desex
+desks*37,4,3
+deter*5,1,4
+deuce+
+devil*64,20,27,,32
+dewed
+dewey+,2
+dhows
+dials*10,1,2
+diary*57,3,15
+diazo
+diced*1
+dicer
+dices*
+dicey+,,,,,,1
+dicks+,1
+dicky
+dicot 1
+dicta 1,,5
+dictu ,,1
+dicut
+diddy
+didos 1
+didot ,,,,,4
+didst 5,,,,283
+diems
+diest
+dieth ,,2
+diets*17,3,2
+digit*191,1,1,,,25,9
+diked*
+dikes*37
+dildo
+dills*
+dilly+6
+dimer+
+dimes*129,2,,,,,3
+dimly*32,12,2,,2
+dinar+
+dined*11,3,10,,2
+diner*8,,1
+dines*2,1
+dingo+,1
+dings+,,1
+dingy*11,5,1
+dinks
+dinky+2,,1
+dints*
+diode+3
+dippy+
+dipso
+direr
+dirge*,2,,,2
+dirks*
+dirts*
+dirty*143,35,26,1,,4
+disco+
+discs*14,7,8
+dishy
+disks*22,4,,,,,29
+ditch*63,9,3,1
+ditto+,,,,,2
+ditty*2,1,1
+divan*,6,1
+divas+
+dived*62,5,6
+diver+87,1,4
+dives*15,4,1
+divot+1
+divvy+
+dixit
+dizzy*11,4,5
+djinn
+docks*45,1,3
+dodge*11,7,4,1
+dodgy
+dodos*,,1
+doers+7,1,1,,4
+doest ,,,,5
+doeth
+doffs*
+doges
+doggo
+doggy+
+dogie*4
+dogma*3,4,2
+doily*1
+doing*927,163,202,13,140,51,2
+dolce ,,1
+doled*2,1
+doles*,,2
+dolls*73,12,5
+dolly+6,1
+dolor+
+dolts*1
+domed*5,2,1
+domes*6,8
+donee
+donna 1,2
+donor*6,5,3
+donut+
+dooms*,1
+doors*225,36,38,3,84
+doozy+
+doped*1,1,1
+doper+
+dopes*
+dopey+
+dorks+
+dorky+
+dorms+
+dosed*1,2
+doser
+doses*6,13,8
+doted*1,,1,,6
+doter
+dotes*
+dotty+,,3
+doubt*222,114,211,34,10,,4
+dough*55,13,,,6
+douse*1
+doves*23,1,2,,9
+dovey
+dowdy*,,2
+dowel*6,2,1
+dower ,1
+downs+7,3,1
+downy*13
+dowry*3,2,1,,3
+dowse+
+doxie
+doyen+
+dozed*16,5,2
+dozen*253,52,49,4,,7,2
+dozer 1
+dozes*2
+drabs
+draft*57,16,22,5,,3
+drags*19,,,1,2
+drain*43,18,15,2,4
+drake*
+drama*84,43,18,4,,1
+drams+
+drank*106,19,20,,52
+drape*2
+drawl*7,2,1
+drawn*344,70,91,6,31,58,2
+draws*43,14,17,3,13,12
+drays+
+dread*29,9,6,,40,2
+dream*232,60,56,1,85
+drear+1
+dreck
+dregs*1,4,,,2
+dress*396,67,76,,3,1,1
+dribs
+dried*218,28,32,1,28
+drier*23,3,4
+dries+26,1,,,4
+drift*71,18,28,3,1,3
+drill*136,33,53
+drily+
+drink*347,82,112,3,362
+drips*2,1
+drive*543,94,88,6,66,3
+droid+
+droll*
+drone*11,3,3,,,,3
+drool*1
+droop*12,1
+drops*234,18,3,,8,2,3
+dross+1,4,,,7
+drove*361,62,62,,49
+drown*29,3,6,,1
+drubs+
+drugs*96,28,47,12
+druid+
+drums*128,15,8,,1
+drunk*29,36,18,1,52
+dryer*8,4,1
+dryly*8,4,2
+duals+
+ducal+1,,1
+ducat+1
+duchy+
+ducks*149,4,2
+ducky+,,1
+ducts*14,6,4
+duddy
+dudes*2
+duels*1,1
+duets*3,1
+duffs+
+dukes*3
+dulls*1,1
+dully*8,3,4
+dummy*7,3,22,,,2
+dumps*8,1,1
+dumpy*6
+dunce*
+dunes*51,8,1
+dungs
+dungy
+dunks*
+dunno+5,,,,,,1
+duped*1,1
+duper+
+dupes*
+duple+6
+durst+
+dusks*
+dusky*10,2
+dusts*2,1
+dusty*79,16,17,1
+dutch+
+duvet+
+dwarf*19,3,3,,1
+dweeb
+dwell*27,8,6,1,308,,2
+dwelt*22,1,5,1,184,1
+dyads 2
+dyers+,,2
+dying*108,33,21,,15,1
+dykes+2,,1
+dynes+
+eager*159,27,21,2,14
+eagle*95,4,8,,31
+eared 2,1
+earls*2
+early*1439,352,283,26,82,4,9
+earns*20,2,7,,4
+earth*2690,116,112,8,1064,1,1
+eased*25,8,15,,1
+easel*10,5,3
+eases*3,,1,,1
+easts
+eaten*251,12,24,,91
+eater+24,,,,3
+eaves*11,,1
+ebbed+1,,3,1
+ebony*4,3,3,,1
+echos+2
+eclat 1,1
+edema ,2
+edged*22,7,6,1,,1
+edger+3
+edges*269,37,20,1,9,66,14
+edict*3,,,1,9
+edify+,,,,1
+edits*1,,1
+educe+
+eerie*21,2,7
+egads+
+egged+1,1,2
+egger
+egret*1
+eider*3
+eight*651,101,92,9,68,23,7
+eject*1,1,,,,3
+eking*
+eland
+elans
+elate*
+elbow*52,7,11
+elder*30,9,20,,18
+elect*43,8,11,5,2
+elegy*2,1,1
+elfin*1,1
+elide+
+elite+8,12,2,2
+elope*
+elude*1,,3
+elves*14,,1
+email
+embed*,,1,,,3
+ember*5,,1
+emcee+,1
+emend+,,1
+emery*15
+emirs+1
+emits*3,,,,,1
+emote+
+empty*384,64,70,4,48,121,3
+enact*4,7,2
+ended*240,59,51,4,33,19,3
+ender
+endow*4,2
+endue
+enema*3,,1
+enemy*301,88,36,,171
+enjoy*422,44,58,7,35,11
+ennui+,,1,1
+enrol*,,2,,2
+ensue*,2,,,,3
+enter*249,78,49,1,190,17,2
+entry*162,25,64,1,3,91,8
+envoi+
+envoy*3,,,,2
+epact+
+epees+
+ephah ,,,,5
+ephod ,,,,51
+epics*3,2,1
+epoch*10,6,14
+epoxy+,2
+epsom ,1
+equal*565,90,80,7,28,126,85
+equip*2,1,4,1,3
+erase*14,1,1,1,,24,1
+erect*36,13,12,,1
+erode*4,,,1
+erred*2,3,1,,3
+error*86,36,30,1,24,203,75
+eruct
+erupt*11,2
+essay*44,19,22
+esses+
+ester+27
+estop+
+etext
+ether*,1,1
+ethic+3,4,1
+ethos+,4,3,2
+ethyl+17,4
+etude*1
+evade*4,1,3,1
+evens*
+event*179,81,80,7,,1,9
+every*3398,488,499,49,1089,145,97
+evict*1
+evils*8,9,10,2,29
+evoke*4,6,2
+exact*236,27,39,1,8,16,21
+exalt*,1,1,,69
+exams*6,,4,,,1,1
+excel*2,1,1,,3
+excon
+exeat ,,3
+execs+
+exert*18,11,6,2,2
+exile*17,4,9,1,69
+exist*135,59,30,1,20,13,24
+exits*14,1,,,4
+expat
+expel*3,2,1
+extol*4,,1,,12
+extra*284,50,71,12,,118,13
+exude+
+exult*1,,,,24
+exurb
+eyers
+eying*5,2
+eyrie+2
+fable*37,2
+faced*130,54,55,10,16,5,6
+facer
+faces*351,71,43,12,86,4,9
+facet*3,2,3
+facie ,,5,1
+facto 2,7,2,2
+facts*519,87,86,5,3,11,18
+faddy+
+faded*63,18,20,,2
+fades*9,,,1,5
+fagot+2
+fails*24,14,19,3,13,13,12
+faint*117,25,28,,44
+faire 3
+fairs*14,1,1
+fairy*71,2,17,,,1
+faith*124,106,53,12,281,,1
+faked*3,2
+faker+,1
+fakes*2,,1,,,,1
+fakir+1
+falls*329,23,30,4,50,3,3
+false*225,29,42,5,107,72,12
+famed+23,5,2,,1
+fames ,1
+fancy*103,16,23,,1,3,1
+fangs*23,2,1,,3
+fanin
+fanny+,1
+farad+4,,1
+farce*4,3,8
+fared*3,,5,2,7
+fares*3,3,21,5,2
+farms*481,16,36
+farts
+fasts*1,,3,,2
+fatal*37,19,24,1,1,6
+fated+2,,2
+fates*,3,3
+fatly
+fatso+
+fatty+13,7,1
+fatwa
+fault*120,22,39,3,16,1
+fauna*19,1,1
+fauns
+favor*107,78,1,13,156,1,1
+fawns*6,,,,3
+faxed+
+faxer
+faxes+
+fazed+
+fazes+
+fears*37,47,30,15,32,,1
+feast*103,3,16,,166
+feats*16,3,2
+fecal
+feces
+feeds*46,12,3,,5,1
+feels*182,45,46,6,4,2
+feign*1,,,,1
+feint+1,2
+feist 2
+fella+5,6,1
+fells*
+felon+,1,1
+felts*3,,1
+femme ,1,5
+femur+1,,1
+fence*346,30,21,2,3
+fends+
+fenny
+feral
+fermi
+ferns*38,1
+ferny+6
+ferry*41,2,2,1
+fetal 2
+fetch*65,6,12,,12
+feted*,2
+fetes*,1
+fetid+,2
+fetor
+fetus*4
+feuar ,,1
+feuds*3,2,1
+feued ,,1
+fever*150,19,6,,1
+fewer*155,33,21,10,3,9,7
+fiats+
+fiber*57,27
+fibre 3,,3
+fiche+,1
+fichu+,,1
+fiefs*
+field*919,249,256,3,275,44,2
+fiend*10,3,1
+fiery*49,7,1,,26
+fifes*4
+fifth*185,24,32,1,65,9,4
+fifty*306,68,98,,129,1
+fight*529,98,87,18,133
+filar
+filch*
+filed*23,33,3,2,,2
+filer
+files*17,13,9,1,,101
+filet*1,,1
+fills*49,5,7,,15,9
+filly*9,9,3
+films*31,31,74,,5
+filmy*3,1,1
+filth*8,2,1,,6
+final*460,153,152,18,6,110,64
+finch*6
+finds*137,59,50,5,42,25,3
+fined*3,4,12,,3
+finer*35,2,6,,,2
+fines*3,2,11
+finif
+finis
+finks+
+fiord*7
+fired*131,44,23,,2
+firer
+fires*154,16,9,1,9
+firma ,1
+firms*28,55,54,6
+first*7655,1312,1286,92,484,583,353
+firth*4,,4
+fishy*4,,1
+fists*35,14,5,,1
+fisty
+fitly*1,,,,2
+fiver+
+fives*31,2
+fixed*196,86,68,6,20,33,35
+fixer+
+fixes*9,,1
+fixit+
+fizzy+
+fjord*2
+flabs
+flack+
+flags*66,5,5
+flail*5,1,3,,1
+flair*3,8,2
+flake*8,1
+flaks
+flaky*7,2,1,,,2,2
+flame*151,17,19,1,43,1
+flams 1
+flank*16,2,5,,1
+flaps*31,,2
+flare*14,3,2
+flash*114,21,10,,11,3,2
+flask*59,5,4,,9
+flats*37,3,26,3,,1
+flaws*6,1,4,1
+flays*
+fleas*13,2,1
+fleck*2,1
+flees*,1,1,,9
+fleet*95,13,6,6,1
+flesh*95,52,34,,359
+flick*14,2,5
+flics
+flied*1
+flier*8,1,1
+flies*220,12,11,,16
+fling*17,2,3,,1
+flint*32,1,2,,8
+flips*9,1,,,,,13
+flirt*3,1,1
+flits*
+float*125,3,2,1,1,1
+flock*69,7,15,1,13
+floes*5,1
+flogs*
+flood*127,17,21,2,45
+floor*935,157,136,6,47,15,4
+flops*3,1
+flora*6,1,1
+floss*
+flour*224,8,12,,59
+flout*
+flown*55,4,8
+flows*218,5,11,2,8,1
+flubs+
+flues*
+fluff*11,1
+fluid*55,21,16
+fluke+8,1,1,1
+fluky
+flume+
+flung*70,14,19,,3
+flunk*1
+flush*13,11,4,,,46
+flute*80,1,3,,1
+flyby+1
+flyer*5,3
+foals*4,1
+foams*,22,,,2
+foamy+5,3
+focal+11,8,1,,,2
+focus*56,40,20,3,,4,2
+fogey*
+foggy*37,3
+foils*1,,3
+foist+
+folds*51,3,5,,7
+folio+,,1,1,,2
+folks*153,19,6,,,1
+folky ,,2
+folly*7,7,14,2,57
+fondu ,,1
+fonts+,,,,,243,1
+foods*518,44,27,,14
+fools*17,5,3,1,44
+foots ,,1
+foray*4,1,1
+force*651,200,168,30,54,34,3
+fords*,2,,,9
+fores ,,1
+forge*21,4,1
+forgo*1,1,1,1
+forks*20,2,4,,5
+forky
+forma ,2,,,,2
+forms*992,128,124,7,8,30,33
+forte+2,4,1
+forth*412,71,22,2,578,7
+forts*32,4,3,,2
+forty*153,35,45,,114
+forum*4,7,1,1
+fossa ,,1
+fosse ,,1
+fouls*3
+found*3362,536,625,27,456,78,59
+fount+2
+fours*47,2,1,,4
+fowls*10,,1,,1
+foxed*,,2
+foxes*57,,3,,5
+foyer*3,3,6,1
+frail*30,8,5,,1
+frame*249,74,45,1,29
+franc*5,1
+frank*10,24,11,2,,1
+frats+
+fraud*7,7,3,1,4
+frays*2
+freak*3,4,2,,,1
+freed*57,12,6,2,14
+freer*4,5,,1,1
+frees*3,2,,,,1
+fresh*573,79,84,7,28,4,1
+frets*3
+friar*3
+fried*61,6,3
+frier
+fries*2
+frigs
+frill*2,,1
+frisk*1,,1
+frizz+1
+frock*2,2,4
+frogs*140,1,5,,15
+frond*1
+front*1438,219,167,13,77,10,6
+frosh+
+frost*83,3,7,,8
+froth*4,1,1
+frown*41,1,4,,,1
+froze*23,5,6
+fruit*456,33,45,1,233
+frump+
+fryer+1
+ftped
+fucks ,1
+fudge*22,,,1,,,3
+fudgy+1
+fuels*41,1,1,1
+fugal
+fugit 1
+fugue+18,,1
+fulls
+fully*141,80,111,6,34,10,8
+fumed*4,1,1
+fumer
+fumes*26,5,6,1
+funds*52,95,29,23,6
+fungi*91,,1
+fungo+
+funks
+funky+1
+funny*312,41,21,1,,13,1
+furls*
+furor+1,3
+furry*31
+furze+
+fused*9,3,2
+fusee
+fuses*10,3,2
+fussy*10,3,4,,,4,1
+fusty 1,1
+futon+
+fuzed
+fuzes
+fuzzy*17,7,2,1
+gabby+
+gable*5,2,2
+gaffe+,,1
+gaffs
+gages 2,2
+gaily*33,5,6,1,1
+gains*41,19,16,12,8,,1
+gaits*
+galas*,,1
+gales*7,,2
+galls*10,1,1
+gamba+3
+gamed+
+gamer
+games*349,53,20,4,1,1,4
+gamey+
+gamic
+gamin+
+gamma+13,4,2
+gamut+3,4,1
+ganef
+gangs*6,6,3,1
+gaols
+gaped*8,3,4,,1
+gaper
+gapes*
+gappy
+garbs*
+garde+3,1,1
+gases*276,7,9,1
+gasps*8,5,4
+gassy+,1
+gated+
+gates*67,13,24,,148
+gaudy*8,7,3
+gauge*53,12,15,1
+gaunt*20,6,6,1,7
+gauss*,2,,,,,2
+gauze*12,1,4,,1
+gauzy*1,,1
+gavel*5
+gawks*
+gawky*2,1,3
+gayer*4
+gayly*5
+gazed*68,7,10,,3
+gazer+,1
+gazes*7,1
+gears*20,2,3
+gecko+3,,,,1
+geeks
+geese*74,3,36
+gelds+
+genes*37,1,1
+genet
+genie*16,1
+genii 3,1
+genre+7,2,7
+gents+3
+genus*31,2
+geode*
+geoid
+germs*152,1,1
+gesso+
+getup+1
+ghost*138,10,19,1,3,2
+ghoti
+ghoul+2,1
+giant*316,23,21,3,2,,1
+gibed+
+giber
+gibes+,1
+giddy*7,2
+gifts*115,11,16,,93
+gigas 3,,1
+gigue 1
+gilds*
+gills*58,,1
+gilts*
+gimel+
+gimme+1,1,,,,5
+gimps
+gimpy
+ginny
+gipsy ,,2
+girds*,,,,3
+girls*1107,141,122,3,2
+girly+
+giros
+girth*8,1
+girts+
+gismo+
+gists*
+given*1661,377,539,55,589,228,133
+giver+5,1,1,,2
+gives*650,112,127,15,177,81,196
+gizmo+
+glade*6,,1
+glads
+gland*29,9,1
+glans
+glare*36,7,7
+glary
+glass*913,96,99,,6,,1
+glaze*3,11,4,,1
+gleam*28,4,8,,2
+glean+1,1,1,,9
+glebe
+glees ,1
+glens*3,,2
+glide*28,2,1,,,1
+glint*4,2,9
+glitz+
+gloat*2,,3,,2
+globe*278,12,4
+globs+,,,,,4
+gloms
+gloom*28,14,9,,24
+glory*93,18,23,,462,,1
+gloss*8,1,4,2
+glove*42,9,2,1
+glows*12,1
+glued*17,19,12
+glues*4,,,,1,1
+gluey 2
+gluon
+gluts*
+glyph+8
+gnarl+
+gnash*,,,,9
+gnats*9,,,,8
+gnaws*3,,,,1
+gnome*1,1,1
+goads*,,,,3
+goals*54,39,21,3,,1,1
+goats*99,,1,,55
+godly*8,,1,,33
+goers
+goest 2,,,,1
+goeth 4
+gofer+
+going*2832,398,517,16,197,35,32
+golds*1
+golem
+golfs*
+golly+14,2,1
+gonad
+goner*
+gongs+4
+gonna+57,16,2
+gonzo+
+goods*420,57,66,14,56
+goody*7,1
+gooey*3,1
+goofs+
+goofy*8,,1
+gooks
+gooky
+goons*
+goony
+goopy 1
+goose*184,2,8,3,,2
+goosy
+gored+3
+gores+,,,,3
+gorge+10,1,,,2
+gorse 2,,1
+goths
+gotta+15,5,2
+gouda+
+gouge*13,1,1,,2
+gourd+17,2
+gouts
+gouty+
+gowns*9,2,5
+goyim+
+grabs*13,3
+grace*55,32,43,1,108
+grade*175,35,19
+grads+,2
+graft*5,1,,1,1
+grail+
+grain*340,27,10,1,127
+grams*29,18,1
+grand*109,31,41,4,,1,1
+grant*31,37,37,4,63,1
+grape*18,3,,,1
+graph*379,17,5,,,14,24
+grapy
+grasp*69,17,25,1,4,1,1
+grass*761,52,64,1,69
+grata ,1,1
+grate*5,3,5
+grave*78,33,28,3,38,3
+gravy*19,4,3
+grays*4
+graze*46,1,,,2
+great*3855,617,654,29,1120,16,15
+grebe 1
+greed*12,3,1,4,7,,2
+greek 3,4,,2,,2
+green*1216,97,109,11,35,1
+greet*42,7,8,1,2
+greps
+greys*3,,3
+grids*5,,7
+grief*48,10,15,,44,,1
+grift+
+grill*8,11,19,,,5
+grime*5
+grimy*3,,1
+grind*38,2,,1,4,1,1
+grins*24,2
+gripe*1
+grips*5,8,5,1
+grist*1,2
+grits*5,1,1
+groan*26,1,4,,21
+groat ,,2
+grody
+grogs
+groin*1,4,5
+groks
+gronk
+grook
+groom*20,4,2
+grope*5,1,,,6
+gross*32,35,28,6,1,2,1
+group*1570,382,313,25,3,122,2
+grout+
+grove*37,7
+growl*25,4,4,,7
+grown*501,43,60,6,43,1
+grows*331,22,16,3,20,1,9
+grubs*15,1
+gruel*5
+gruff*8,4,1
+grump*
+grunt*9,2
+guano
+guard*158,35,43,4,122,2
+guava+,,1
+guess*637,55,35,,1,29,2
+guest*94,35,29,1,7,,1
+guide*347,36,40,3,23,7
+guild*6,3,1
+guile*5,1,,,12
+guilt*12,33,16,,11
+guise*2,6,1,1,,,1
+gulag+
+gulch*
+gules
+gulfs*5,,3
+gulls*66,,1
+gully*12,5,1
+gulps*6,1,2
+gumbo*1
+gummy*3,2
+gunks
+gunny+2,2
+guppy*11
+gurus+,,,,,1
+gushy*
+gusto+2,2,2,1
+gusts*16,3,1
+gusty*4,2,1
+gutsy+
+gutta
+gutty
+guyed
+gwine 1
+gyppy
+gypsy*46,4,4
+gyros+,5
+gyved
+gyves ,,1
+habit*130,23,39,4,2,4,1
+hacks*,,3,1,,4
+hadda
+hades
+hadst 4,,,,8
+hafta 1,3
+hafts
+haiku*37
+hails*2,1
+hairs*70,12,4,,15
+hairy*29,5,4,,5,1,2
+haled+
+haler
+hales+
+hallo 3,,3
+halls*47,3,11,1,,2,1
+halos*3,1
+halts*9,1,,,,1
+halve*3,,1
+hames
+hammy+
+hamza+,,,,,1
+hands*1357,286,236,15,566,2,2
+handy*47,13,8,,,19,13
+hangs*60,4,3,1,3
+hanks
+hanky+1
+hapax+
+haply
+happy*774,92,121,2,26,8,1
+hardy*24,9,4
+harem+1,2,3,,5
+hares*11,,4
+harks
+harms*,,,,1
+harps*3,,,,2
+harpy 2,1
+harry*5,5,1
+harsh*61,12,12,2,9
+harts+,,,,2
+harum 1
+hasps+1,1
+haste*36,9,11,,77
+hasty*10,5,4,2,1
+hatch*114,5,9,,4
+hated*96,28,21,1,56
+hater+,,,,1
+hates*16,4,5,,39
+hauls*5,2,4
+haunt*5,4,4,,7
+haute ,2,1
+haven*7,5,3,,5
+haves*,,,2
+havoc*6,3,4,,1
+hawed+
+hawks*54,1,,2
+hayed+
+hayer
+hayey
+hazed+
+hazel*12,2,1
+hazer
+hazes*,1
+heads*358,43,69,5,207,4,45
+heady+3,2,1,1
+heals*3,,1,,7
+heaps*20,1,6,,22
+heard*1988,240,240,6,721,2
+hears*67,7,8,,61
+heart*1032,171,196,8,830,8
+heath*3,,7
+heats*35,,1
+heave*20,2,3
+heavy*984,109,144,7,63,9,2
+hedge*27,2,17,,6
+heeds*,,,,6
+heels*109,22,22,,5
+heerd 3
+hefts*
+hefty*5,1,2
+heirs*13,2,7,,11
+heist+
+helix+1
+hello*162,9,14
+hells*,1
+helms*
+helps*554,30,19,,10,11,13
+hemps*
+hempy
+hence*61,58,54,8,10,100,344
+henge
+henna+,,,,2
+henry ,10,2,1
+herbs*27,3,12,,4
+herby
+herds*126,6,11,,4
+herem ,,1
+heres*1
+heron*9,,,,2
+heros*
+hertz+3
+hewed*4,1,,,1
+hewer+,,,,1
+hexad
+hexed*
+hexer
+hexes*,,,,,1
+hicks+
+hider+
+hides*91,5,4,1,13,1
+highs*7,2
+hiked*11,1
+hiker+1,,1
+hikes*4,4
+hilar ,4
+hills*410,37,21,5,77
+hilly+55,,3
+hilts*
+hilum ,5
+himbo
+hinds*,,,,6
+hinge*19,1,6
+hints*27,9,2,,,4,1
+hippo+2
+hippy*1
+hired*69,25,3,,37,,1
+hirer+
+hires*3,1,1,,2
+hitch*14,4,4,1
+hived
+hiver
+hives*1
+hoagy+1
+hoard*4,,,,1
+hoars
+hoary*5,,,,3
+hobby*74,4,13,,,3
+hobos*
+hocks+3
+hocus+
+hodad
+hoers
+hogan*8,3
+hoist*9,1,2
+hokey+
+hokum+
+holds*228,41,29,6,24,13,91
+holed+1,1
+holer
+holes*278,38,15,,9,1,2
+holey
+holly*24,,1
+holon
+homed+
+homer*3,9,,,9
+homes*581,62,55,4,2
+homey*2
+homme ,,1
+homos 3
+honed+1,,1
+honer
+hones+
+honey*113,23,11,,63
+honks*1
+honky
+honor*204,64,2,3,192,,2
+hooch+,1
+hoods*11,2,1
+hooey+,,1
+hoofs*66,7,1,,9
+hooks*49,2,9,,29,2
+hooky*4
+hoops*8,3,6
+hoots*2,1,1
+hoped*201,48,76,7,9,1,2
+hoper
+hopes*112,48,59,7,10,4,2
+hoppy
+horde*11,2,2,,2
+horns*158,9,6,,69
+horny*2
+horse*1263,112,60,,39,,2
+horsy+
+hosed*
+hoses*10,2
+hosts*10,5,2,,304
+hotel*106,85,112,5
+hotly*10,2,6,,4
+hound*44,4,5
+houri+
+hours*990,175,194,18,5,8
+house*2705,403,415,24,1891,1,4
+hovel*2,2
+hover*9,4
+howdy+15
+howls*10,3,1
+hubba+,1
+hubby+,1
+huffs*1
+huffy+1,,1
+huger*
+hulas+1
+hulks*,2
+hulky+
+hullo 4,,4
+hulls*7,,1
+human*710,297,210,28,57,1
+humid*38,1,2
+humor*72,47
+humpf 1
+humph 11
+humps*13,,1,,1
+humpy+1
+humus*20,,13
+hunch*6,7,2
+hunks*1
+hunky
+hunts*25,2,2,,2
+hurls*,,,,1
+hurly
+hurry*314,36,25,1,1
+hurts*23,4,4,,3
+husks*13,,1
+husky*26,3
+hussy+
+hutch*4,,1
+huzza
+hydra*4
+hydro ,,,3
+hyena*8,1,1,,1
+hying
+hymen ,13
+hymns*24,6,6,,15
+hyped+
+hyper+
+hypes+
+hypos
+iambs
+icers
+ichor
+icier*
+icily*1,,2
+icing*10,1,18
+icons*,,1
+ideal*59,60,36,6,,5,1
+ideas*978,142,128,6,,26,11
+idiom*11,7,2
+idiot*10,2,7,,,1
+idled*,1,1
+idler*1,1,,,1
+idles*1
+idols*7,2,2,,137
+idyll+,2,1
+idyls
+igloo*7,,1
+ikats+
+ikons
+ileum ,1
+ileus
+iliac ,1,3
+ilium
+image*148,119,43,6,90,21,2
+imago ,,1
+imams+2
+imbed
+imbue+,,1
+immix
+impel*2,,3
+imply*11,12,16,2,2,12,8
+impro
+inane*,1,1
+inapt ,1
+incur+1,5,,,7
+index*91,77,27,4,,64,95
+indie
+inept*4,2,1
+inert*16,5,8
+infer*12,1,3
+infix+
+infra ,1
+ingot*1
+injun 1
+inked*9,,,,,1
+inker
+inlay+1
+inlet*12,4,7
+inner*128,53,48,10,75,29,11
+inode
+input+35,20,1,2,,241,1
+inset+4,1
+inter+3,2,4
+intra ,,1
+intro+
+inure+,1
+ionic+,4,6
+iotas+
+irate*1,1,2
+irked*1
+irons*15,7,1,,2
+irony*9,12,7,4
+isles*6,,,,5
+islet+1
+issue*97,151,95,29,10,5,3
+itchy+4
+items*196,71,40,,,69,7
+ivied+
+ivies*
+ivory*29,16,8,,13
+ixnay
+jacks*4
+jaded*1,2,1
+jades+
+jaggy+
+jails*4,3,,4
+jakes ,1
+jambs*,,,,18
+jammy
+janes
+japan
+jaunt*1,,1
+jawed*
+jazzy+,1
+jeans*24,1,1
+jeeps*8,,3
+jeers*3,1,2
+jello+2
+jells*
+jelly*87,3,15
+jenny
+jerks*8,1,2
+jerky*13,4,4
+jerry
+jests*2
+jetty*4,,3
+jewel*20,1,8,,5
+jibed*1
+jiber
+jibes*2,1
+jiffs
+jiffy*6,2,1
+jihad+1,,1
+jilts+
+jimmy+
+jingo+3,,3
+jings 2
+jinks+
+jinns
+jived+
+jives+
+jocks+
+joeys
+johns
+joins*50,2,7,,1,5,1
+joint*142,32,53,2,5,1,3
+joist*
+joked*8,1
+joker*2,,1
+jokes*77,9,13,1,,8
+jolly*41,3,6
+jolts*2
+joule+,,1
+joust+,1,1
+jowls+2,4
+jowly+
+joyed
+judge*173,43,65,17,161,1,1
+judos*
+juice*170,11,32,,3
+juicy*40,6
+jujus
+jukes
+julep+,2
+jumbo*3,,,,,1
+jumps*82,2,7,,,5,1
+jumpy*6,2,1
+junco
+junks*5,1,1
+junky*1
+junta+8,3,,7
+juror*2,4
+juste ,,1
+jutes*
+kabob+
+kaiak
+kales*
+kapok
+kappa+
+kaput+1
+karat*2
+karma+
+kayak*2
+kayos+
+kazoo+,1
+kebab+
+kebob ,1
+keels*1
+keens
+keeps*288,21,16,3,55,24,3
+kefir+
+kelps*2
+kelpy
+kenaf
+kepis
+kerbs
+kerfs 1
+kerns+,,,,,32
+ketch*7
+keyed*4,3,1
+keyer
+khaki*6,1,2,1
+khans+,,1
+kicks*23,3,2
+kicky
+kiddo+1
+kikes
+kills*37,8,3,,26
+kilns*,,3
+kilos+
+kilts*1,1
+kilty
+kinda+8,5
+kinds*1545,36,44,3,54,49,1
+kings*131,3,7,,343
+kinks*5,,1
+kinky*2
+kiosk+1,1,3
+kirks
+kited 1
+kites*19,,,,1
+kiths
+kitty*22,2,2
+kivas 2
+kiwis+1
+klieg+
+kluge
+klugy
+klunk 1
+klutz+
+knack*8,4,4
+knave*2,,1,,2
+knead*3,1,1,,2
+kneed+1
+kneel*9,5,4,,2
+knees*213,38,28,,29
+knell*1,,1
+knelt*59,8,9,,13
+knife*318,74,38,1,4,2,1
+knits*6
+knobs*24,1
+knock*85,15,18,1,4
+knoll+11,1
+knops ,,1
+knots*60,1,8,,1
+knout
+known*1401,245,358,18,255,90,58
+knows*505,99,102,9,118,21,8
+knurl+1
+koala*3,,1
+koine
+kooks+1
+kooky+2
+kopek+
+kraal ,,,1
+kraut+,1
+krill+7
+krona
+krone
+kudos*,,1
+kudzu
+kyrie ,,1
+label*184,19,17,1,,26,1
+labia
+labor*164,125,,185,81
+laced*15,2,2
+lacer
+laces*11,1,5
+lacey+,2
+lacks*24,6,5,5,18
+laded
+laden*20,6,3,1,5
+lades
+ladle*9,1
+lager+,,2
+laird ,,1
+lairs*1,1,,,1
+laity+,3
+laker
+lakes*261,6,5
+lamas+
+lambs*46,7,11,,95
+lamed*3
+lamer*
+lames*
+lamps*60,6,14,1,39
+lanai+
+lance*18,3,1,1
+lands*602,24,32,,152
+lanes*27,4,3,1,2
+lanky*21,2,2
+lapel*,1,2
+lapin
+lapis+1
+lapse*4,6,6,,1
+larch*1
+lards*
+lardy ,,1
+large*2777,361,435,17,79,140,88
+largo 1
+larks*5,2,1
+larva*26
+lased
+laser*13
+lases
+lasso*17,2
+lasts*40,1,1,1,2,1,2
+latch*12,5,1,,1
+later*1599,396,464,12,24,135,29
+latex*10,2,1
+lathe*37,1,3
+laths*1
+latin+,1,,1
+latus
+laude 1
+lauds*
+laugh*287,28,30,,18
+lavas*3
+laved
+laver ,,,,15
+laves 1
+lawns*37,5,6
+lawny
+lawzy
+laxer+,,1
+laxly*
+layer*259,12,26,1
+layup+
+lazed ,,1
+lazes
+leach*
+leads*120,33,31,4,33,10,33
+leafs*
+leafy*30,1,1,,5
+leaks*14,3,1,2,1
+leaky*10,2
+leans*18,1,2,,4
+leant 5,,8
+leaps*36,4,3,1,3
+leapt*10,2,5
+learn*1674,83,115,2,66,64,15
+lease*11,10,37,1
+leash*16,3,1,,1
+least*878,343,314,49,40,71,71
+leave*964,205,216,20,147,31,16
+ledge*61,4,5,,8
+ledes
+leech*4,,,,1
+leeks*,,,,1
+leers*1
+leery+
+lefts*1
+lefty+,,,,,1
+legal*66,72,50,30,3,28,9
+leggo+
+leggy+,1,1
+legit+,,,,,,1
+legos
+lemma+,4,,,,,12
+lemme 9,1
+lemon*44,15,36
+lemur*2
+lends*14,4,4,,4
+lento 1
+leper*1,,1,,16
+lepta
+letup+2
+levee*2,1
+level*531,212,205,22,13,81,7
+lever*128,13,6
+levis+,2
+liars*1,1,4,,8
+libel+1,1,4
+libra 4
+licit
+licks*9,,,,1
+liege 3
+liens+,1
+liers
+liest
+lieth
+lifer+,1
+lifts*42,2,3,,11
+light*2376,325,284,5,297,6,5
+ligne
+liked*610,58,54,,,,1
+liken*,,1,,6
+liker
+likes*229,20,27,4,1,4,1
+lilac*10,1,5
+lilts*
+lilty
+limbo+,1
+limbs*69,5,8,,8
+limby
+limed ,,2
+limen ,,1
+limes*8
+limey+
+limit*92,48,39,11,9,8,42
+limns
+limos+
+limps*,1
+lined*,16,6,,4,4,2
+linen*58,6,13,,105
+liner*19,3,9
+lines*1715,197,152,33,3,486,59
+lingo+4,2,,,,,1
+lings
+links*47,7,19,2,,2
+lints*
+linty+
+lions*128,5,4,,58
+lipid+
+lippy
+liras
+lisps*
+lists*98,34,15,,,91,19
+liter*6,2,3
+lites 1
+lithe*6,4
+litre ,,1,1
+lived*1372,115,118,7,150,3,1
+liven+2
+liver*51,16,7,,17
+lives*742,81,97,8,171,1
+livid*8,1,2
+llama*18
+loads*80,10,7,,4,4
+loafs*
+loams*
+loamy+1,,1
+loans*26,31,23,3
+loath*5,3,1,1,1,1
+lobar
+lobby*13,19,5
+lobed 3
+lobes*2,5,5,,,1
+local*286,282,402,23,4,50,1
+lochs
+locks*37,7,4,,10,1
+locos 2
+locus+6,2,1
+lodes*1
+lodge*40,11,9,,2
+loess 8
+lofts*
+lofty*32,5,1,,21
+loges
+loggy
+logic*21,16,19,3,1,3,3
+logos+1,,,,,2
+loins*4,2,,,62
+lolls*
+lolly 8,,2
+loner+2
+longs*1,1,1,,7
+looks*756,78,91,6,31,86,36
+looky+1,1
+looms*17,2,2,,1
+loons*2
+loony+
+loops*37,1,1,2,14,24
+loopy+
+loose*227,53,32,,35,16
+loots*
+loped*4,1
+loper
+lopes*1
+loppy
+lords*44,1,1,,43
+lordy
+lores*,,1
+lorry+,,1
+loser*9,1,,2,,,1
+loses*70,15,14,4,10,3,4
+lotsa
+lotta 2
+lotto+
+lotus*3,1,1,,2
+louis 1,8,,2
+louse*2,3,2,,,1
+lousy*8,11,2
+louts+1
+loved*347,56,68,2,112
+lover*41,16,23,1,6
+loves*75,19,14,,83
+lowed*
+lower*659,119,118,29,19,35,58
+lowly*18,,2,,17
+loxes
+loyal*38,18,15,2,12
+luaus+
+lubes+
+lubra ,2
+lucid*4,4,3
+lucks*,1
+lucky*166,21,39,1,,4,1
+lucre 1
+lulab ,,2
+lulls*2,1
+lulus+
+lumen+,1
+lumps*43,3,5,,1
+lumpy+6,2,1
+lunar*55,10,2
+lunch*357,33,63
+lunes
+lunge*7,1,1
+lungs*207,20,14
+lurch*4,3,1
+lured*6,3,1,,1
+lurer
+lures*6,,,1
+lurid*2,3,2
+lurks*1,1,,,2,,1
+lusts+,1,1,,2
+lusty*7,3,1,,1
+luted
+lutes*2,,,,1
+luvya
+luxes
+lycra
+lying*275,36,94,1,82,3
+lymph*7,2,1
+lynch*1,,,3
+lyres*,,,,18
+lyric*21,12,5
+macaw+
+maced
+macer
+maces
+macho+
+macro+,,,,,441
+madam*34,1,2
+madly*19,4,2
+mafia+,,,1
+magic*279,37,15,,8,9,5
+magma+44
+magna ,,1,,,,1
+mahua ,1
+maids*21,12,2,,23
+mails*8,7,2
+maims*
+mains*8,1,5,1
+maize*8,,7
+major*597,229,110,18,,6
+maker+36,12,7,,7
+makes*1311,172,147,25,168,207,43
+males*44,19,8,1,18
+malls*
+malts*1
+malty
+mamas*1
+mambo+
+mamma*5
+mammy 5
+maned 4
+manes*6,2
+mange+
+mango*7
+mangy+2
+mania*2,5,3
+manic+1,2
+manly*9,2,3,,1
+manna+,,3,,18
+manor*15,3,8
+manse ,1
+manta 2
+maple*94,6
+march*130,23,15,3,24
+mares*12,1,2
+marge 2,,1
+maria
+marks*469,28,30,4,7,63,3
+marls
+marry*141,18,83,,3
+marsh*52,,10,,3
+marts*,1
+maser 3
+mashy
+masks*33,3,1,,1
+mason*6,2,,1
+masse ,,2
+masts*46,2
+match*353,41,57,4,3,25,9
+mated*1,4
+mater 4,1
+mates*20,10,5
+matey+3
+maths*,,1
+matte+
+matzo+,,2
+mauls*
+mauve*1,1,4
+maven+
+mavis ,1
+maxim*6,1,2
+maxis
+maybe*779,132,85,1,,5,15
+mayor*95,12,11,4
+mayst 1,1
+mazed
+mazer
+mazes*1
+meads
+meals*147,26,16,,3,1
+mealy*1
+means*1962,298,317,44,83,176,54
+meant*539,100,113,7,19,11,1
+meany*
+meats*52,12,3,,1
+meaty*3,1
+mebbe 5,,2
+mecca+1,,,1
+mecum ,2
+medal*28,3,37,2
+media*15,13,9,7
+medic*
+meets*,35,25,2,10,3
+melba+1
+melds+
+melee+,3
+melon*16,1,3
+melts*69,,,,9
+memes
+memos*1,1
+mends*3
+menus*11,2
+meows*
+mercy*49,19,24,2,235
+merge*9,10,4,,,,2
+merit*15,27,11,1,1
+merry*97,6,7,,29
+merse ,,1
+mesas*8
+mesne
+meson+
+messy*12,3,2,1,,1,5
+metal*782,60,57,8,1,6
+meted*2,2,1,,1
+meter*206,6,10,,,,2
+metes*
+metre 1,1,5
+metro+,,2
+mewed*3,1
+mezzo ,1
+miaow
+micas*1
+micks
+micro+
+middy*6
+midis
+midst*67,19,14,,295,16
+miens
+miffs+
+might*2824,671,786,85,448,323,105
+miked 1
+mikes*3
+milch ,,,,3
+miler+2
+miles*2146,169,124,,7,1,1
+milks*4,2
+milky*13
+mills*175,14,12,,1,,1
+mimed+
+mimeo+
+mimer
+mimes+
+mimic*5,,1
+mimsy 2
+minas ,,,,9
+mince*8,1,1
+minds*110,56,52,10,38,1
+mined*58,3
+miner*22,1,3
+mines*170,28,19,,1
+minim+1
+minis+
+minks*7
+minor*223,53,49,11,,4
+mints*3,,,1,,,1
+minus*53,8,1,2,,93,15
+mired*5
+mires*
+mirth*10,2,2,,13
+miser*3,,2
+missy ,1
+mists*25,2,2,,2
+misty*19,4,7
+miter*6,1
+mites*5
+mitre 1,1,2
+mitts*1,,1
+mixed*324,37,60,4,58,4
+mixer+9,2,4
+mixes*16,,2,,1,2
+moans*3,1,1,,3
+moats*1,,1
+mocha*
+mocks*4,,1,,5
+modal+8,3
+model*332,63,116,3,2,1
+modem+
+modes+19,8,14,,,70,1
+modus 1,1
+mogul+,,,1
+mohel
+moire+,1
+moist*135,11,7,1,3,1
+molal ,2,1
+molar*3,1
+molas
+molds*63,7,,,2
+moldy*5,,,,2
+moles*10,,,,1
+molls+
+molly 1,1
+molto 1
+molts*9
+mommy+2
+monad
+mondo+
+money*1694,263,318,56,189,1,4
+monic+,3
+monks*2,10,3
+monte
+month*403,130,95,16,289,7,6
+mooch+
+moods*32,7,8,,,1
+moody*6,2,2
+mooed*2,1
+moola+
+moons*59,3,1,2,13
+moony 1
+moors*4,1,4
+moose*52
+moots
+moped*2
+moper
+mopes*1
+moral*53,140,85,12,,3,1
+moray+1
+morel
+mores*5,7
+morns*3
+moron*2
+morph
+morts 1
+mosey+
+mossy*12,,2
+mosts
+motel*34,20,,1
+motes+2
+motet+,1,1
+moths*58,2,2
+mothy
+motif+3,8,3
+motor*198,53,58,2
+motto*17,3,6,1
+mould+2,1,11,1
+moult+,,2
+mound*51,8,,,9
+mount*42,10,9,7,24,1
+mourn*14,2,1,,55
+mouse*207,9,6,,1
+mousy+,1,2
+mouth*725,103,98,1,395,17
+moved*994,181,140,5,56,20,1
+mover+5,,1
+moves*485,36,22,5,7,20,31
+movie*151,29,4
+mowed*15,1,,,2
+mower*13,,3
+moxie+
+mrads ,2
+mucho 1
+mucks*
+mucky+
+mucus*19,2,3
+muddy*89,10,4
+muffs+
+mufti+
+muggy*8,1
+mujik
+mulch*,6
+mulct
+mules*51,3,3,,12
+muley
+mulls*
+mumbo ,,,,,1
+mummy*14,,2
+mumps*15
+munch*3,1
+munge
+mungs
+mungy
+muons
+mural+5,1,3
+murks*
+murky*11,5,1
+mused*6,4,6,,1
+muser
+muses*
+mushy*4
+music*2100,200,211,15,27,8
+musks*
+musky*2
+musos
+mussy
+musta ,1
+musts*,1
+musty*10,,1
+muted*10,3,2,1
+muter
+mutes*3
+mutts*
+muxes+
+mylar+
+mynah+
+mynas
+myrrh*5,2,,,21
+myths*36,6,10,1,5
+nabla+
+nabob+
+nacho+
+nadir+,2,1
+naiad+
+nails*168,14,11,1,9
+naive*6,7,6,4
+naked*54,32,15,1,41,1
+named*946,84,46,3,95,15,8
+namer+
+names*1016,88,100,8,94,82,11
+nanny+,,1
+napes*
+nappy+1
+narco+
+narcs+
+nards+
+nares
+nasal*22,2,1
+nasty*19,5,8,1,,1,1
+natal+2,2
+natch+,1
+nates
+natty+1,1
+naval*50,21,29
+navel*3,2,,,2,,2
+naves
+nears*8,,,1
+neath ,,1
+neato+
+necks*37,2,5,,14
+needs*616,152,107,42,11,52,15
+needy*10,5,3,2,54
+negro 3,5,1
+neigh*4,,,,1
+neons*
+nerds+
+nerdy
+nerfs
+nerts
+nerve*121,12,39,1
+nervy+,,1
+nests*110,3,3,,8
+never*3115,695,689,25,256,97,3
+newel+1,1,1
+newer*30,20,8,1
+newly*90,28,28,1,3,11,3
+newsy+2
+newts*
+nexus+
+nicad
+nicer*11,2,2,,,5,9
+niche*10,3,1,1,1
+nicks*3
+niece*17,8,14
+nifty*
+night*2307,400,373,15,365,1,1
+nihil
+nimbi
+nines*6,,1
+ninja
+ninny+,,1
+ninth*41,15,7,,35,2
+nippy 1
+nisei+
+niter
+nitro+
+nitty
+nixed+
+nixes+
+nixie
+nobby+
+noble*57,23,28,2,44
+nobly+6,,2,,13
+nodal 3,,1
+noddy
+nodes+,2,1,,,,3
+noels+
+nohow
+noire ,1
+noise*411,37,47,,38,3
+noisy*94,6,9,1,3
+nomad*6,,1
+nonce+,1
+nones
+nonny
+nooks*2,1
+nooky
+noons*
+noose*7,3
+norms+,24,4
+north*793,64,98,14,154
+nosed*5,,2
+noses*56,6,4,,1
+nosey+1
+notch*27,6,2,,,,5
+noted*145,90,65,6,1,3,3
+noter
+notes*534,55,63,,2,16,3
+nouns*530,3,9,,,1
+novae*
+novas*1,,,,,1
+novel*71,59,67,3
+noway+
+nuder
+nudes+,2
+nudge*17,2,1
+nudie
+nuked+
+nukes+1
+nulls+,,,,,1
+numbs+
+nurbs
+nurse*16,16,14,,16
+nutsy+
+nutty+3
+nylon*58,1,5
+nymph*22,1,2
+oaken*6,1
+oakum
+oared
+oases*22,2
+oasis*27
+oaten
+oaths*12,3,2,,13
+obeah
+obese+2,,3
+obeys*6,1,3,,6,4,1
+obits+
+oboes*9,,4
+occur*215,43,65,2,3,121,37
+ocean*843,32,9,4
+ocher ,1
+ochre+2,2
+octal+,,,,,26
+octet+
+odder*2,,1
+oddly*28,9,19,1
+odium+,,1,1
+odors*37,7,,,3
+odour ,,5
+offal 1,1,1
+offed
+offen 2
+offer*185,80,103,13,218,1,1
+often*2611,368,416,20,49,122,91
+ogled+,2
+ogler+
+ogles+
+ogres*
+ohhhh 2
+ohmic ,1
+oiled+18,3,4
+oiler
+oinks+
+oinky
+okapi*
+okays*
+okras
+olden*10,1,2,,,2
+older*404,93,102,8,13,,1
+oldie+
+oleos
+olios
+olive*65,4,5,,45
+ombre
+omega+,,,2,,3
+omens*7,,1,,3
+omits*5,2,2,,,4
+oncet 1
+onion*42,15,3
+onset*8,15,3
+oodle+
+oomph+1
+oozed*6,2
+oozes*3
+opals*4
+opens*82,16,20,1,25,3
+opera*177,29,54,2
+opine+
+opium*5,16,1
+opted+,2,2
+optic*3
+orate ,1
+orbed
+orbit*233,16,9,3,,,1
+orcas+
+order*1507,363,336,32,187,181,82
+organ*90,12,17,1,2
+orlon+1
+ortho 1
+osier
+other*10729,1700,1535,181,510,520,272
+otter*29,5,1
+ought*220,68,106,15,56,27,11
+ouija+,,,1
+ounce*48,3,2
+ousel
+ousts*
+outdo*5,3,2,,1
+outen 3
+outer*252,27,29,3,33,34,7
+outgo+1
+outta 1,2
+ouzel 1
+ovals*4,2,,,,,1
+ovary*29
+ovate
+ovens*11,1,6,,1
+overs
+overt+2,11,6,1
+ovoid ,,3
+ovule*2
+owest
+oweth
+owing*20,4,29,2,1
+owlet+
+owned*198,34,21,5,1
+owner*172,33,42,1,24,,2
+oxbow*
+oxide*51,3,2
+oxlip
+ozone*2,3,2
+paced*15,11,3
+pacer+6,1
+paces*22,7,1,,1,1
+packs*25,2,5
+pacts*2,,1
+paddy*16,,2
+padre+6,,1
+paean+,2
+pagan*13,1,10,,,1
+paged*
+pager+
+pages*723,31,42,2,,112,11
+pails*22,4
+pains*33,15,17,1,14,2
+paint*437,37,45,4,4
+pairs*455,14,21,,5,43,29
+paled*6,1,1
+paler*4,,2
+pales*1,1,,,,,1
+palls*1
+pally
+palms*55,8,5,,7
+palmy
+palsy*2,1,1
+pampa+
+panda*9
+paned+
+panel*49,31,33
+panes*18,3,1,,,,1
+panga ,,1
+pangs*10,2,2,,2
+panic*44,22,15,,18,1,4
+pansy*10,6,1
+pants*77,9,2
+panty+
+papal+11,6,3
+papas*
+papaw*
+paper*2372,155,187,23,3,34,5
+pappy 1
+paras ,,3
+parch*
+pards
+pared*,,1
+paren
+parer 1,,,1
+pares*
+parka*4
+parks*92,15,46,9,1
+parry*
+parse+
+parts*2331,110,122,9,65,49,47
+party*625,195,400,209,12
+pasha
+pasta*1
+paste*96,10,6,,,3
+pasts
+pasty+,2
+patch*97,13,20,2,2,,2
+paten
+pater 2,1
+pates+
+paths*73,14,6,,56,96,1
+patio*8,2
+patsy+,1
+patty*2
+pause*109,21,29,,,5,1
+pavan
+paved*45,5,3,,2
+paver
+paves*,,1
+pawed*7
+pawer
+pawky ,,1
+pawls
+pawns*1
+payed 1
+payee+,,1
+payer+,,1
+peace*343,138,159,16,399,1
+peach*76,2,6
+peaks*102,8,8,,,,1
+peaky+,1
+peals*,1,,,4
+pearl*85,3,7,,2
+pears*31,2
+pease
+peats
+peaty+,,2
+pecan*6,1
+pecks*8
+pedal*39,4,8
+peeks*2,,,,,,1
+peels*1,1
+peens
+peeps*
+peers*8,8,6,1,2
+peeve+
+pekoe+
+pelts*15,9
+penal+1,1,3,2
+pence*4,,5
+penes
+pengo
+penis*1
+penny*134,10,8,1,3,,2
+peons*2
+peony*1
+peppy*
+perch*36,1,4
+perdu ,,3
+peril*16,8,5,2,9
+perks*,,,2
+perky*1,2,1
+perms+
+pesky+2
+pesos*9,,1
+pesto+
+pests*21,2,5
+petal*9
+peter+,4,,4
+petit 3,1,2
+petri
+petty*7,6,12,1,1
+pewee*
+pewit
+pffft
+phage+
+phase*37,66,39
+phial
+phlox*1
+phone*73,53,21,,,2
+phony*1,12,3,1
+photo*50,5,1
+phyla+,1
+piano*418,30,17,,,4
+picas+,,,,,5
+picks*70,4,4,,3,2
+picky+2,,,,,,1
+picot
+piece*1198,129,107,10,42,16,3
+piers*10,5,2
+pieta
+piety*5,4,4,,13
+piggy*5,,1
+pigmy*2
+piing
+piker+
+pikes*4,,1
+pilaf+
+pilau
+piled*90,16,4,,3
+piles*67,2,3,1
+pills*18,8,2
+pilot*167,44,19,2,2
+pimps+,2,1
+pinch*30,6,5,,,1
+pined*1,,2,,2
+pines*37,2,2,,1
+piney+5
+pings+
+pinko+
+pinks*3,2
+pinky*
+pinto*17,1
+pints*49,,6
+pinup+
+pions ,,3
+pious*7,10,6,,3
+piped*22,2,6,,2
+piper+4,,2
+pipes*117,7,13,1,2
+pipet
+pique+2,2,1
+pismo
+pitas+
+pitch*273,22,22,1,15
+piths*
+pithy*2,1
+piton+
+pivot*23,2,2
+pixel+,,,,,151
+pixie*
+pizza*16,3,1,,,,3
+place*4240,551,471,26,905,104,37
+plaid*15,1,1
+plain*338,48,78,7,63,471
+plait*1
+plane*990,114,49,,5,,9
+plank*35,7,2
+plans*308,112,83,27,33,1
+plant*1051,123,85,7,62,3
+plash
+plasm 1,1
+plate*346,20,37,1,21
+plats 1
+plays*304,66,54,2,2,3,9
+plaza*12
+plead*7,5,5,1,12
+pleas*3,1,3,,1
+pleat*12
+plebe+
+plebs
+plein ,,2
+plena
+plied*8,2
+plies*3
+plink
+plods*2
+plonk
+plops*
+plots*19,8,7,,11,2
+plows*31,3,,,2
+ploys+
+pluck*50,2,,2,19
+plugs*14,2,1
+plumb*15,5,,,5
+plume*10,2,1
+plump*37,4,14,,2
+plums*25,,1
+plumy 1
+plunk 1
+plush*5,3,1
+plyer
+poach*,1,,,,2
+pocks
+pocky
+podgy ,,1
+podia
+poems*156,78,28
+poesy ,1
+poets*79,32,20,,1,1
+point*1904,376,423,35,31,335,42
+poise*14,6,6
+poked*42,4,7
+poker*9,5,1
+pokes*8,3
+pokey*
+polar*85,7,5,1,,,1
+poled*4
+poler
+poles*264,8,9,1,39
+polio*57,1,1
+polis ,1
+polka*12,1,1
+polls*8,10,6,31
+polly+,,,1
+polos
+polyp*7,,4
+pomps
+ponds*70,7,1,,1
+pones
+pooch*
+pooey
+poohs
+pools*57,15,12,1,11
+poops
+popes*6
+poppy*15,2,2
+porch*168,42,9,,3,,1
+pored*3,1,2
+pores*17,3,3
+porgy
+porks
+porky+
+porno+
+ports*79,4,9,,1
+posed*14,7,6,1,,1,1
+poser+,,1
+poses*9,1,4,1
+poset+
+posit+
+posse*5,11,3
+poste
+posts*75,22,9,2,8
+potty+
+pouch*35,2
+poufs+
+pound*227,28,20,,5,7
+pours*40,2,4,,15
+pouts*
+power*1065,329,318,108,348,5,109
+poxed
+poxes
+prams+,1
+prank*,1,1
+prate+
+prats
+prawn+
+prays*3,,3,,14
+preen*3
+preps+
+press*247,109,94,25,29,1,1
+prest
+prexy+
+preys*2,,,,1
+price*289,103,124,17,34,2
+prick+9,2,,,1
+pride*145,40,40,1,73,1
+pried*1
+prier
+pries*2
+prigs+,,1
+prima 1,,5,1
+prime*335,37,14,68,2,13,167
+primo
+primp+
+prims
+prink+
+print*134,18,16,6,1,27
+prior*19,47,28,3,1,3
+prise
+prism*80,,1
+privy+2,1
+prize*173,18,28,3,1
+probe+31,6,11,1,,,5
+prods*1,,1
+proem
+profs+
+promo+
+proms+
+prone*7,14,7,1
+prong*2,,1
+proof*80,40,49,,9,32,11
+props*6,6,1
+prose*30,13,7,1
+prosy+
+proud*361,50,44,5,58
+prove*257,53,81,10,28,10,337
+prowl*10,2,,,2
+prows*1
+proxy*,7
+prude*
+prune*8,1,,2,2
+pruta ,1
+pryer
+psalm*6,2,10,,4
+pseud
+pshaw 1
+psoas ,,1
+pssst 1
+psych+
+pubes
+pubic
+pubis
+pucks*
+pudgy+2
+puffs*27,1,3,,2
+puffy*4,2
+puked+
+pukes+
+pukka 1,,1
+pulls*134,9,4
+pulps*
+pulpy*2,,2
+pulse*53,9,7
+pumas*3
+pumps*51,5,1
+punch*54,5,8,1,,,4
+punks*1,1
+punts*,,1
+pupae*19
+pupal
+pupas*1
+pupil*95,20,23,,1
+puppy*87,2
+puree+2
+purer*4,,1,,2
+purge*4,2,6,1,14
+purls 1
+purrs*
+purse*59,12,16,2,6
+purty 3
+pushy+
+pussy*8,5
+putts*
+putty*10,1,1
+pygmy*5
+pylon+2
+pyres*
+pyxie
+qophs
+quack*23,9,3
+quads+1,,,,,2
+quaff*,,1
+quail*22,,1
+quais+
+quake*9,2,,,8
+qualm*
+quals+
+quark+
+quart*85,3,2,,1
+quash+
+quasi+,,1
+quays*3,,1
+queen*206,21,13,3,36,,2
+queer*102,6,14
+quell*1,2,,,,,1
+query*3,1,3
+quest*18,16,12,4,,,2
+queue*4,,7,1
+quick*394,67,70,4,8,7,6
+quids
+quiet*533,75,79,2,48,2
+quiff ,,1
+quill*17,9,1
+quilt*34,,15
+quint+,4,2
+quips*
+quipu+6
+quire+2,,1
+quirk*4,1
+quirt 2,8
+quite*967,281,484,28,6,80,38
+quits*2,1,1
+quoin
+quoit
+quota*12,3,7,3
+quote*13,17,17,1,1,34
+quoth+7
+rabbi*5,7,,,2
+rabid*,2
+raced*181,12,8,,1
+racer*1
+races*109,21,29,,1
+racks*9,2,1,,3
+radar*70,23,1
+radii*7,4,1
+radio*587,113,49,18,,1,1
+radix+16,,,,,3,3
+radon+1
+rafts*16,1,1,,3
+raged*25,8,2,,4
+rages*5,1,,1,2
+raids*19,5,4,,5
+rails*59,9,5
+rains*121,5,3,,5
+rainy*122,4,3,,1
+raise*344,51,38,12,77,3,4
+rajah*,1
+rajas
+raked*18,4,1
+raker+
+rakes*,,1
+rally*63,10,20,1,3
+ramps*1,1,1
+ranch*243,26,5,1,,,1
+rands
+randy+
+range*351,159,141,16,2,24,37
+rangy+1,2
+ranks*51,20,22,3,12,2
+rants+
+raped+2,2
+raper+
+rapes+,1
+rapid*107,43,39,3,,1
+rarer*5,1,2,,,1
+rasae
+rasps*1,1
+raspy+1
+rated*17,9,6,,1,3
+rater
+rates*86,102,77,14,,3,2
+raths 2
+ratio*111,36,61,,,26,44
+ratty+1
+raved*,,1,,2
+ravel*2
+raven*4,,,,7
+raver
+raves*2
+rawer+
+rawly
+rayed 1
+rayon*47,,1
+razed*1,,2,,4
+razer
+razes*
+razor*20,15,5,,8,1
+reach*648,106,83,11,27,17,1
+react*45,15,11,3
+reads*120,16,14,2,3,61,4
+ready*1207,143,138,9,125,27,9
+realm*26,19,19,1,8,1,1
+reals+,,,,,,5
+reams*3,2
+reaps*,,,,2
+rearm+,,1
+rears*,,,,,1
+rebar
+rebel*23,11,17,1,14
+rebid+
+rebox ,,,,,3
+rebus+1
+rebut+,6,1
+recap+,,,,,,1
+recta
+recto+
+recur*4,2,,1,,1
+recut+
+redid+
+redip
+redly 1
+redox
+redux
+reeds*70,,2,,8
+reedy+3,2,2
+reefs*17,1,1
+reeks+
+reeky
+reels*5,,1,,1
+reeve
+refer*202,27,50,2,,43,1
+refit*1,,1
+refix+
+refly
+regal*5,2,1,,1
+rehab+
+reify+
+reign*30,7,27,1,186,1
+reins*53,9,8,1
+relax*40,18,12,3,2,9,2
+relay*44,2,6
+relet
+relic*4,6,3,,1
+remit*,,1,,,1
+remix+
+renal ,1,3
+rends*
+renew*12,4,9,,15
+rente
+rents*7,4,33,2
+repay*15,7,6,,27
+repel*22,8,3,,1
+reply*96,42,83,1,12,6
+repro+
+reran+
+rerun+,,,,,,1
+resaw
+resay
+reset+3,,,,,11
+resew+
+resin*17,9,16
+rests*49,18,13,1,17
+retch+,1,1
+retro+
+retry+
+reuse+
+revel*3,3,1,,3
+revet
+revue+3,,6
+rewed+
+rheas*
+rheum 1,1
+rhino+14,,1
+rhumb
+rhyme*226,3,3,,,2
+rials
+ribby
+riced
+ricer
+rices
+rider*112,12,4,,13
+rides*86,10,8,,5
+ridge*82,12,15,,1
+ridgy
+rifer
+rifle*140,61,2
+rifts*1
+right*4815,607,597,79,480,387,117
+rigid*49,24,23,3,1,5
+rigor*2,,2,,4,,2
+riled+2
+riles+,,1
+rille
+rills*2
+rimed 1
+rimer
+rimes
+rinds*2
+rings*158,6,21,3,47,,1
+rinks*1
+rinse*22,6,2,,1
+riots*15,1,7,1
+ripen*15,,1,,2
+riper*
+risen*44,10,27,1,33
+riser+7,,1
+rises*174,19,19,17,36,1
+risks*21,5,20,4,,1,1
+risky*16,3,4,1
+rites*10,4,4,,6
+ritzy+
+rival*34,11,22,5,5
+rived
+riven+,1,,1
+river*1170,78,83,12,106
+rives
+rivet*22,,2
+roach*3,1,16
+roads*359,55,33,11,8
+roams*1,,1
+roans+
+roars*17,1,2,,3
+roast*55,10,6,,1
+robed*3,1,,,3
+robes*33,4,8,1,29
+robin*57,1,1,2
+roble
+robot*71,1,3
+rocks*740,23,34,3,24
+rocky*144,9,11,,7,,2
+rodeo*52,1
+roger+2,3
+rogue*3,1,1
+roids
+roils+
+roily
+roles*25,34,12,,,,2
+rolls*113,10,9,,,,1
+roman+,,1,4,,77
+romps*
+rondo+27
+roods
+roofs*63,5,8,,4
+rooks*
+rooky
+rooms*209,54,48,1,2
+roomy*5,1,3
+roost*14,1,4
+roots*444,23,24,,24,8,31
+rooty
+roped*13,1,2
+roper+3
+ropes*99,4,11,,17
+roses*82,7,16,,2,1
+rosin+9
+rotor*20,6,14
+rouge*4,2,1
+rough*292,41,29,2,4,2,4
+round*1076,77,335,10,262,37,14
+rouse*12,2,6,,9
+roust+
+route*196,33,21,,2,3,2
+routs*1
+roved*,1
+rover*5
+roves*1,,1
+rowan ,,1
+rowdy+4,4,2
+rowed*43,2,1,,2
+rower+
+royal*105,27,163,7,83,1
+rubes+
+ruble+
+ruche
+ruddy*6,3,2,,4
+ruder*
+ruffs*1,,1
+rugby*2,,5
+ruing
+ruins*56,8,13,2,48
+ruled*130,31,16,6,27,5
+ruler*260,3,28,,82,4,3
+rules*444,76,72,9,30,272,26
+rumba
+rumen+,2
+rummy*,1
+rumor*10,7,,,1
+rumps*4
+runes+2,1
+rungs*4,,1
+runic+3
+runny+1
+runts*2
+runty+1
+rupee+,6
+rural*59,47,37,11,1
+ruses*
+rusks+,,1
+russe ,1
+rusts*4
+rusty*55,7,1
+rutty+
+saber*6,1
+sable*,2,1
+sabra 1
+sabre+2,2,1
+sacks*35,1,7,,1
+sadly*109,12,17,2,1
+safer*50,5,8,4,,3
+safes*1,,1
+sagas*3,,1
+sager
+sages*,1,,,1
+sahib
+sails*110,2,11,,1
+saint*17,10,13,,1
+saith 4,4,3
+sakes*19,,2,,1
+salad*84,9,8
+sales*100,130,66,1
+sally+3,3,,,1
+salon+4,1,3
+salsa+
+salts*14,6,2,,,1
+salty*54,4,3,,1
+salve*1,3,3,,1
+salvo+2,2
+samba+2
+sands*43,7,11,,1
+sandy+117,6,11,,1
+saner*1,1,1
+sappy+,1
+saran
+sarge+
+saris*
+sassy*8
+sated+,,1,,1
+sates
+satin*17,5,3
+satyr*,,,,1
+sauce*62,20,5
+saucy*8,1
+sauna+
+saute+1,1
+saved*256,43,51,7,137,18,4
+saver+4,1
+saves*32,5,1,,16,17,1
+savor*3,1
+savvy+1,1
+sawed*14,,,,1
+sawer
+saxes+,,1
+sayer+
+scabs*2,,,,2
+scads*
+scald*1,1
+scale*737,55,115,4,6,12,4
+scalp*34,4,4,,2
+scaly*9
+scamp*7
+scams+
+scans*4,2,,,,3
+scant*10,5,1,2,4
+scare*55,3,3,3,1
+scarf*50,4,6
+scarp 3
+scars*18,10,4
+scary*23,2,,1,,2,3
+scats
+scene*302,102,100,4
+scent*69,6,15,1,5
+schmo
+schwa*79
+scion+,1
+scoff*7,,1,,7
+scold*19
+scone+
+scoop*16,5
+scoot*3
+scope*24,27,42,12,,8,6
+scops ,1
+score*411,66,77,4,,1,8
+scorn*18,4,6,,2
+scour*2,1,2
+scout*53,6,2
+scowl*7,,1
+scows*3
+scram*2,,1
+scrap*43,8,7,2
+screw*100,20,9
+scrim+,1
+scrip+1,,6
+scrod+
+scrub*36,9,1,1
+scrum ,,1
+scuba*13
+scudi
+scudo
+scuds
+scuff*5,1
+scull*,,1
+scums*
+scurf ,,3
+scuse ,1
+scuzz+
+seals*49,4,7,,11
+seams*82,9,4,,1
+seamy+,,1
+sears*
+seats*143,15,27,49,8
+sebum
+secco ,3
+sects*8,2
+sedan*6,2
+seder+,,3
+sedge*
+sedgy
+sedum
+seeds*560,42,19,1,9
+seedy+1,,2
+seeks*25,10,11,2,41
+seems*638,258,297,101,42,18,43
+seeps*11
+seers*1,1,,,4
+seest ,,,,4
+seeth
+segue+1
+seine+,,9,,2
+seize*40,5,4,,48
+selah
+selfs
+sells*66,13,5,1,12
+semen ,,,,6
+semis+
+sends*82,4,7,,26,5
+sense*556,311,265,32,25,26,27
+sepal*
+sepia+,1
+sepoy
+septa ,6
+serfs*14,1,2
+serge*1,1,1
+serif+,,,,,18
+serum*10,18,22
+serve*317,107,80,10,244,14,1
+servo+,5
+setup+7,8,,,,6,2
+seven*687,106,116,15,488,40,9
+sever*4,3,2,,1
+sewed*33,1,2,,2
+sewer*8,9
+sexed
+sexes*8,11,9,1
+shack*40,1,6
+shade*203,28,30,,18
+shads ,,3
+shady*30,1,4
+shaft*69,11,13,,12
+shags+
+shahs+
+shake*143,17,17,,32
+shaky*19,5,3,3
+shale*19,,3,1
+shall*1051,266,355,11,6976,113,7
+shalt+22,,8,,2
+shame*67,21,18,1,191
+shams*,1
+shank*13,1,2
+shape*766,84,98,4,,71,2
+shard+
+share*354,96,91,25,53,3
+shark*92
+sharp*499,71,70,2,25,31,1
+shave*15,6,1,,14
+shawl*40,3,1
+shawm
+shays
+sheaf*6,3,2,,7
+shear*10,40,7,,3
+sheds*19,4,1,,6
+sheen*9,2
+sheep*464,23,27,,205
+sheer*50,14,27,,4,,1
+sheet*367,45,46,,2,2,1
+sheik*,4
+shelf*150,12,12,1
+shell*245,21,12
+sherd ,,,,1
+shews
+shied+3,3,,1
+shier
+shies+1,1
+shift*70,41,29,2,,29,17
+shiki
+shill+,1
+shims+1,1
+shine*157,4,5,,36
+shins*3
+shiny*123,3,15
+ships*731,44,37,2,37,2
+shire+
+shirk*1,,1
+shirr
+shirt*222,26,29,,1
+shish+,1
+shits
+shlep
+shmoo
+shnor
+shoal*3,,5,,2
+shoat
+shock*100,31,53,1,2
+shoed+
+shoer
+shoes*461,44,36,,1
+shoji ,1
+shone*119,5,12,,2
+shook*420,57,53,1,14
+shoos*
+shoot*214,27,22,,16,,1
+shops*126,16,64,7
+shore*447,43,29,1,6
+shorn*4,,1,,5
+short*1534,208,228,16,23,58,1
+shots*78,29,36,1
+shout*143,9,10,,46
+shove*15,2,2
+shown*1490,166,230,16,79,84,4
+shows*1184,94,146,6,25,68,52
+showy*15,1,2
+shred*1,3,3
+shrew*4
+shrub*25,1,1,,1
+shrug*11,2,2
+shuck*
+shuns*1,2,1,,1
+shunt+1,1
+shush*2
+shute ,,1
+shuts*9,1,,,5,1
+shyer*1
+shyly*19,4,5
+sibyl
+sicko+
+sicks
+sided*4,1,,1,2
+sides*827,99,87,20,35,18,85
+sidle*2,1
+siege*12,5,3,1,41
+sieve*15,1,5,,3,,1
+sifts*2
+sighs*20,1,3,,1
+sight*565,86,98,4,345,,1
+sigma+,,,,,2,1
+signs*352,68,52,5,101,89,2
+silks*21,,9
+silky*32,1,3
+sills*6,,1
+silly*150,15,29,1,3,4,1
+silos*1,2,1
+silts*2
+silty+
+since*2041,624,541,62,196,373,251
+sines+,,,,,2,1
+sinew*12,,,,3
+singe*1
+sings*127,10,5,,6
+sinks*30,,6,1,5,1
+sinus*1,1
+sired+,3,2
+siree+3
+siren*12,1,1
+sires*
+sirup*1
+sisal*11
+sissy+5,,,1
+sitar+1
+sited 1,,6
+sites*28,16,43,9,1,1
+situs ,5
+sixes*22
+sixth*99,20,14,1,50,4,1
+sixty*108,21,23,1,47
+sized*10,4,3
+sizer
+sizes*201,12,14,,,39,9
+skate*33,1,1
+skeet+,2
+skein*3
+skews*
+skids+,1
+skied*2
+skier*11,,1
+skies*74,9,4,,14
+skiff*14,9
+skill*262,41,42,,19,1
+skimp*1
+skims*3
+skins*168,7,5,,19
+skint ,,2
+skips*21,1,3,,1,6
+skirt*123,21,24,,9
+skits*2,1,1
+skoal+1
+skulk*,1
+skull*77,3,4,,5
+skunk*7
+skyed+
+slabs*23,,5
+slack*13,8,5,,7,1,1
+slags*1
+slain*27,,,,165
+slake*1
+slams*6
+slang*27,2,2
+slant*91,3,4,,,34
+slaps*11,1
+slash*37,3,2,,,22
+slate*20,6,3,,,1
+slats*6,1,2
+slave*175,30,4,,9
+slaws
+slays*1,,,,5
+sleds*34
+sleek*37,2,4,,6
+sleep*717,65,61,6,88
+sleet*22,1,4
+slept*200,27,24,,49
+slews*2
+slice*88,13,17,,,,1
+slick*28,7,1,1,,2,3
+slide*182,20,7
+slier
+slily
+slime*11,,4,,2
+slims+
+slimy*7,,3
+sling*9,1,1,,9
+slink*5,,1
+slips*34,8,3,,8,1
+slits*24,2,1
+slobs+1
+sloes ,,1
+slogs+
+slomo
+sloop*11,1
+slope*146,19,18,,2,8,2
+slops*1
+slosh*4
+sloth*20,,1,,1
+slots*17,5,2,,,1,1
+slows*22,,,,,1
+slued
+slues*
+sluff+
+slugs*7,4,2
+slump*4,8,6,3
+slums*22,7,8
+slung*22,2,5,,2
+slunk*1
+slurp+2
+slurs*3,,,,,1
+slush*2
+sluts+
+slyer*
+slyly*9,2
+smack+14,4,3,,,2
+small*3555,529,522,21,101,86,9
+smart*109,21,11,,3,1,3
+smash*20,4,7
+smear*,2,1
+smell*378,34,30,1,12
+smelt*7,3,4,,1
+smile*281,58,76,,1
+smirk*3,3,1
+smite*3,,,,5
+smith*7,,2,,4
+smock*2,,8
+smogs
+smoke*328,40,42,1,62,20,1
+smoky*12,2,2
+smote*8,,1,,93
+smurf
+smuts
+snack*29,6,2
+snafu+
+snags*5,1,6
+snail*47,1,1,,1
+snake*226,42,18,,2
+snaky*1
+snaps*25,,1,,1
+snare*26,1,2,1,49
+snarf
+snark
+snarl*15,,3
+sneak*25,2,1,,,1
+sneer*5,1,3
+snide+
+sniff*30,2,,,1
+snipe*2
+snips*13,1
+snits+
+snobs*2,1
+snood
+snook
+snoop*,1
+snoot+,,1
+snore*8,,3
+snort*14,3,5
+snots+
+snout*24,1,1,,1
+snows*29,7,,,2
+snowy*56,4,2,1
+snubs*,,1
+snuck+,1
+snuff*10,,1
+snugs
+soaks*16
+soaps*12,3
+soapy*8,1
+soars*5,,,,1
+sober*24,16,7,1,8
+socko+
+socks*78,7,8
+socle
+sodas*5
+sofas*2,3
+softs
+softy+
+soggy*16,3,2
+soils*54,15,26
+solar*198,14,3,6
+soled*,,1
+soles*18,5,4,,8
+solid*390,77,61,3,4,8,1
+solon 1
+solos*10,3
+solum ,,1
+solve*874,20,24,7,4,51,66
+somas
+sonar*25,7
+songs*658,58,33,3,41
+sonic*8,2
+sonly+
+sonny+2,1,2
+sooth+
+soots*
+sooty+4,,1
+soppy+
+sorer*
+sores*5,3,1,,8
+sorry*282,47,70,1,7,6,1
+sorta+3
+sorts*76,12,25,1,14,16
+souls*25,23,11,,48,,1
+sound*4667,202,157,4,161,5
+soups*11,,1
+soupy+3
+sours*,1
+souse+
+south*709,62,107,49,122,1,1
+sowed*6,,2,,12
+sower+1,,1,,9
+soyas
+space*1499,175,114,10,12,551,27
+spacy+
+spade*7,4,2
+spake 8,,,1
+spang
+spank*4
+spans*6,5,1,,,7
+spare*94,23,26,3,51,1
+spark*76,10,6,,4,6
+spars*9
+spasm*4,3,6
+spate+1,2,2
+spats*1,1
+spawn*4,,8,,,2
+spays+
+spazz
+speak*661,109,105,6,399,6,2
+spear*99,6,4,,6
+speck*27,7,3,,7
+specs+1,,,,,1,1
+speed*750,81,103,16,6,20,2
+spell*1052,19,23,1
+spelt+5,,9,,3
+spend*418,53,86,17,36,4,2
+spent*522,104,132,13,33,3
+sperm*6
+spews*1,,,,,1
+spice*19,4,11,,3
+spics
+spicy*10,1
+spied*31,,1,,8
+spiel+1
+spier
+spies*15,2,4,,15
+spiff
+spike*18,2
+spiky*4
+spill*23,1,4,,,1
+spilt*3,,4,,1
+spina
+spine*35,6,5
+spins*52,,3,1
+spiny*16
+spire*4,5,2
+spite*173,56,79,4,14,8,2
+spits*5,,1,,2
+spitz 1
+spivs ,,1
+splat+1
+splay+
+split*159,30,39,3,7,34,11
+spoil*59,3,11,1,85,1,1
+spoke*512,87,111,5,284,1
+spoof+,1
+spook*4
+spool*26
+spoon*92,6,7
+spoor
+spore*22
+sport*117,17,20,3,17
+spots*157,31,15,2,5,2,18
+spout*29,1,5
+sprat 1
+spray*72,16,12,1
+spree*2,4,3,1
+sprig*2,1,,,1
+sprit 5
+sprog
+sprue ,2
+spuds*
+spued 1
+spume ,1,1
+spumy
+spunk*3,,,1
+spurn+1,,1,,8
+spurs*25,3,,,,1
+spurt*12,2,2
+sputa
+squab*1
+squad*16,17,2
+squat*16,7,2
+squaw*16,1
+squib+1
+squid*19,,1
+stabs*3,1,2
+stack*41,7,1,,,39,6
+staff*164,104,129,10,46
+stage*344,172,210,13,2,6,3
+stags*2,1
+stagy
+staid+2,1,1
+stain*19,6,5,,5
+stair*18,2,3
+stake*47,20,11,4,2,,6
+stale*14,4,3
+stalk*72,,1,,2
+stall*95,17,8,1,2
+stamp*76,8,46,3,2,2
+stand*1081,147,158,19,279,41,11
+stank*1,,1,,1
+staph+
+stare*70,14,10,,4,1
+stark*10,4,6
+stars*713,27,55,1,7
+start*1087,153,184,14,1,58,36
+stash+
+state*1281,563,270,135,15,27,14
+stats+
+stave*5,2,3,1,,1
+stays*90,5,7,,7,7,6
+stead*8,5,3,,84
+steak*30,8,1,1
+steal*83,5,7,2,22
+steam*340,17,31
+steed*12,1,1,,1
+steel*565,39,52,1,1
+steep*184,13,6,3,6
+steer*79,9,4,1,,,2
+stein+,4,,,,,1
+stela
+stele
+stems*171,32,30,3,,8,1
+steno
+steps*747,115,93,3,59,15,21
+stern*75,22,17,4,9,1
+stets
+stews*3,1,1
+stick*502,39,40,1,15,23,6
+stied
+sties*1
+stiff*138,21,19,,1
+stile*5,,2
+still*3421,781,823,63,248,72,54
+stilt*1
+sting*34,5,6,1,3
+stink*4,3,2,,1
+stint*7,6,4,,1
+stirs*10,3,4,,14
+stoae
+stoas
+stoat 1,,1
+stock*227,141,86,4,5,5,4
+stogy
+stoic+1
+stoke+1
+stole*52,10,17,,7
+stoma
+stomp*8
+stone*593,47,75,,196
+stony*24,5,2,,2
+stood*1387,212,196,4,284
+stool*58,8,7,,4
+stoop*29,4,,,2
+stops*132,7,13,2,5,19,5
+store*681,72,42,4,14,8,1
+stork*7,,,,5
+storm*319,26,31,,34,,1
+story*2237,149,201,8,26,60,7
+stoup
+stout*48,2,13,,3,2
+stove*183,15,12,,1
+stows*1
+strap*41,2,3
+straw*213,15,13,,21
+stray*38,12,5,,3
+strep+2
+strew*2,,,,2
+strip*230,29,34,2,21,,1
+strop+
+strum*26,,1
+strut*4,2,6,,,14
+stubs*6,2,1
+stuck*186,23,20,2,3,1,2
+studs*8,3,1
+study*2581,241,146,11,4,50,25
+stuff*129,31,37,2,37,12,8
+stump*39,2,3,,7
+stung*27,2,4,,1
+stunk*,1
+stuns*,,1
+stunt*31,1,2
+styes
+style*356,97,101,13,2,140,2
+styli
+suave+,2,2
+sucks*1
+sudsy+
+suede*3,,1
+suers
+suets*
+suety+
+sugar*574,34,61,,,3
+suing*3,1
+suite*26,21,10,,,,1
+suits*108,25,9,4,3
+sulfa*2
+sulks*,1,1
+sulky*3,4,1
+sully+
+sumac+6,1
+summa 1
+sumps+,,1
+sunny*116,12,12,1
+sunup*12
+super+21,7,10,,,3,3
+supes
+supra ,3
+suras+
+surds+,,,,,1
+surer*5,,1
+surfs*
+surge*20,9,5,1,2
+surly*3,2,2
+sushi+,2
+sutra+
+swabs*
+swags
+swain+1
+swami+,1
+swamp*64,5,1,1,1
+swank+1,1
+swans*15,1,,,1
+swaps*1
+sward 3,,1
+sware
+swarf ,,1
+swarm*24,3,1,,9
+swart 2,1
+swash+4
+swath+2,1,1
+swats*
+sways*2,,,,1
+swear*34,10,11,,59
+sweat*105,23,19,,5
+swede
+sweep*81,15,11,2,17
+sweet*319,69,43,,49
+swell*49,7,7,,7,1
+swept*161,34,28,4,19,1
+swift*131,14,19,,29,2
+swigs+
+swill*,,,1
+swims*47,,1
+swine*7,3,1,,15
+swing*189,20,13,12,1
+swipe*,2
+swirl*14,2,3
+swish*36,,2
+swiss+36
+swive
+swoon*1,,1,,1
+swoop*14,2,2,1,2,1
+sword*93,6,13,,48
+swore*28,14,9,,92
+sworn*9,5,4,1,54
+swung*164,48,29,2,3
+sylph 1
+synch+,,,,,1
+syncs
+synod+1
+syrup*50,4,1
+tabby+2,,1
+table*1502,153,279,,110,108,67
+taboo*3,3,1,1
+tabor 5
+tabus
+tacet
+tacit+2,2,1
+tacks*25,,2
+tacky+1
+tacos*3
+tacts
+taels
+taffy*3,1
+tagua 1,1
+tails*123,7,4,,5,,24
+taint*3,1,1
+taken*1015,281,423,36,350,31,11
+taker+1
+takes*835,86,98,12,87,81,28
+talcs*1,,1
+tales*140,19,19
+talks*85,18,91,,,1
+talky ,1
+tally*16,4,3
+talon*
+talus+
+tamed*32,,1,,2
+tamer*1
+tames*1,,,,1
+tamps+
+tango+2,2
+tangs
+tangy*6,1
+tanks*110,18,35
+tansy+,1
+taped*7,1,2
+taper*10,3,19,,,1
+tapes*18,4,1
+tapir*6
+tapis ,1
+tardy*3,1
+tared ,,1
+tares+1,,3
+tarns+
+taros
+tarot+
+tarps+
+tarry*8,1,,,18
+tarts*10,,1
+tasks*63,29,18,1,4,6
+taste*283,57,77,4,28,2
+tasty*29,2,3
+tater
+tatty
+taunt*3,4,,1,17
+taupe+
+tawny*6,4,4,,1
+taxed*10,13,7,3,1
+taxer+
+taxes*104,44,20,15,11,1
+taxis*21,3,2
+taxol
+taxon
+teach*254,41,35,1,102,4
+teaks
+teals*
+teams*150,22,10,1
+tears*223,34,49,1,63,1
+teary 1
+tease*28,6,3
+teats 1,2
+techs+,,1
+techy
+teddy*4,2
+teems*1,1,,,2
+teens*35,5,1,1
+teeny+2,,,,,2
+teeth*538,103,62,,54
+telex+
+tells*808,34,47,1,21,51,91
+telly+,,5
+tempi+,,1
+tempo*90,4,7
+temps+,,4
+tempt*4,2,3,1,4,1
+tench ,,1
+tends*62,34,15,2,4,7,4
+tenet+1
+tenon+7
+tenor*18,6,6
+tense*194,15,11,,1,2
+tenth*73,5,12,,68,2,1
+tents*85,10,5,1,6
+tepee*8
+tepid*2,1,3
+terce
+terms*425,162,235,36,19,51,306
+terns+12
+terra+3,1,1
+terry ,1
+terse*,2,2,,,2
+tesla+
+tests*185,61,105,4,6,16
+testy+1
+tetra
+texas+
+texts*9,4,26,,,23,3
+thane+
+thank*301,33,60,,34,5
+thanx 1
+thats 2
+thaws*7
+thees 1
+theft*11,10,8,,5
+their*13258,2667,2808,349,4889,216,9
+theme*183,55,45,1,1,1,1
+thens
+there*15194,2713,3321,305,2124,427,353
+therm
+these*11611,1571,1504,100,1128,422,241
+theta+,,,,,9,2
+thews+
+thick*540,67,69,,37,35,2
+thief*68,8,7,,28
+thigh*21,9,5,1,36
+thine*13,1,3,,32
+thing*1828,331,341,29,258,74,28
+think*4746,433,575,17,81,64,24
+thins*3
+third*945,182,135,23,208,53,37
+thong*6,1,,,4
+thorn*27,3,5,,7
+those*2647,850,957,136,1669,149,64
+thous
+three*4413,592,698,78,523,228,97
+threw*342,46,54,1,61,,1
+throb*6,,1
+throe+
+throw*281,41,19,6,52,,6
+thrum 1
+thuds*4,1
+thugs+1,2,,2
+thumb*150,11,13,,5,3
+thump*62,3,2
+thunk ,1
+thwap 2
+thyme*4,,1
+tiara*,,3,,2
+tibia+2
+ticks*18,2,,,,1
+tidal*59,1,7
+tided
+tides*110,4,12
+tiers*,3,1,,2
+tiffs+
+tiger*112,6,3
+tight*208,28,32,1,3,7,2
+tikes
+tikis
+tilde+1,,,,,14
+tiled*7,4,1
+tiler
+tiles*44,6,3,,1,,2
+tills*,,,,2
+tilth ,1,1
+tilts*7,2
+timed*17,9,2
+timer+7
+times*2051,264,262,25,207,91,68
+timid*23,5,7,1,4
+tines*5,2
+tinge*2,,2
+tings
+tinny+4
+tints*7,1,3
+tippy*
+tipsy+,2,1
+tired*461,48,52,,2,1,2
+tires*85,12,2
+tiros ,,1
+titan+1,,1
+titer+,4
+tithe*1,,6,,23
+title*302,54,61,1,2,63,2
+titre ,,1
+titty
+tizzy+
+toads*89,,1
+toady+
+toast*57,18,17
+today*1923,282,287,33,115,2,1
+toddy+
+toffs+
+toffy
+togas*
+toile
+toils*3,,2,,7
+toked+
+token*18,10,4,,2,427
+toker+
+tokes+
+tolls*8,2
+tombs*29,2,1,1,23
+tomes+,1
+tommy*1,7
+tonal+99,9,2
+toned*,,1
+toner+,3
+tones*275,15,12
+tongs*12,1,,,3
+tonic*26,1,4
+tools*379,34,34,1,,3,9
+toons+
+tooth*91,20,10,,1
+toots*4
+topaz*2,,,,5
+toped+
+toper+
+topes+
+topic*370,9,12,1,,6,1
+topoi
+topos
+toque ,,2
+torch*28,2,10,,6
+toric
+torsi
+torso*1,7,2
+torte+
+torts+
+total*531,211,197,17,3,45,62
+toted*2
+totem*11,,1
+toter
+totes*3
+totty
+touch*432,86,78,2,43,9,3
+tough*173,36,38,13,,1,5
+tours*7,9,3
+touts+
+toves 7
+towed*18,1,4
+towel*48,6,6,,2
+tower*170,12,45,1,31,,15
+towns*337,50,90,1,78
+toxic*6,3,1,1
+toxin+2,1
+toyed*,,2
+toyer
+toyon
+trace*151,23,27,,5,6
+track*312,37,30,1,2,11
+tract*24,15,10,,,4
+trade*479,134,214,30,16,2
+trail*317,29,13
+train*556,77,90,8,6,4
+trait*26,3,4
+tramp*40,1,2
+trams+1,,5,6
+trans 9
+traps*53,8,3,,1,1
+trash*20,2,3
+trawl*1,,19
+trays*19,3,6,,3
+tread*15,5,5,,3
+treap
+treat*113,26,20,,18,20,3
+treed+2
+trees*1645,96,99,3,146,,15
+treks*2,,,1
+trend*27,46,26,12
+tress*2
+trews
+treys
+triad+6,1,1
+trial*130,119,40,11,15,20,1
+tribe*169,4,15,1,253
+tribs
+trice+3,,2
+trick*189,15,25,4,,25,41
+tried*1077,170,162,16,42,22,8
+trier
+tries*123,13,20,2,1,25,1
+trike+1
+trill*2,3,2
+trims*2,1,1
+trios*1
+tripe*2,,1
+trips*152,29,8,4,,,3
+trite*1,2,,1
+troll*9
+troop*35,9,3,,3
+troth+1,,,,1
+trots*6
+trout*53,1,3
+trove+
+trows
+truce*8,5
+truck*410,56,10,,,1
+trued
+truer*4,2,1
+trues
+truly*146,57,32,1,59,6,4
+trump+,1
+trunk*186,8,8,,1,3
+truss*13
+trust*103,50,74,3,96,,1
+truth*215,124,151,9,191,18,11
+tryst+
+tsars*2
+tuans ,,1
+tubal
+tubas*
+tubby+,,2
+tubed
+tuber*3
+tubes*177,24,14,,1
+tucks*8,,2
+tufas
+tufts*12,1,1
+tufty+,,1
+tulip*20,3,4
+tulle+1,1,1
+tummy+3,,3,,,1
+tumor*32,13
+tunas*
+tuned*65,3,2,,,,2
+tuner+7
+tunes*79,7,4,,1
+tunic*4,1,1,,5
+tunny
+tuple+
+turbo+1
+turds
+turdy
+turfs*
+turfy
+turns*440,38,29,,68,73,87
+turps ,,1
+tusks*38,3,,,1
+tusky ,,1
+tutor*16,4,15
+tutti ,,1
+tutus+
+tuxes+
+twain*7
+twang*8,,1
+twats
+tweak+,,,,,,1
+tweed*6,5,4
+tweet+
+twerp+
+twice*400,74,73,1,30,37,26
+twigs*67,1,3,,2
+twill+3,,2
+twine*19,,,,1
+twink
+twins*67,8,3,,6
+twiny
+twirl*6
+twirp
+twist*81,17,18,,4
+twits+
+twixt+
+tying*22,5,2
+tykes+
+typal
+typed*9,3,4,,,71
+types*334,116,92,5,1,75,2
+typos+,,,,,1
+tyres ,,2
+tyros+
+tzars*
+udder*3
+ukase ,,1
+ulcer*5,5,2
+ulnar
+ulnas
+ultra*2,,3
+umbel
+umber+,4
+umbra*2
+umiak
+umped+2
+umpty+
+unapt
+unarc
+unarm
+unary+1,,,,,2
+unate
+unban
+unbar*1
+unbox ,,,,,1
+uncap ,1
+uncle*196,25,24,1,11
+uncut+3,,,,,1
+under*2987,703,646,84,410,45,24
+undid*8,1,3,,2
+undue*5,13,9,2
+unfed+1
+unfit*9,1,8,,3,1
+unfix
+unhip
+unhit
+unify*4,2,3,,,1
+union*104,83,148,45,3,2,2
+unite*29,10,6,,2
+units*483,87,79,2,1,122,1
+unity*64,66,44,2,4,3,8
+unlit+,,1
+unman
+unpeg
+unpin+1
+unrig
+unsay
+unsee ,1
+unset+,,,,,3
+unsew
+unsex
+untie*14,2,,,9
+until*2596,461,478,47,497,115,56
+unwed+,12
+unwon
+unzip+1
+upend+
+upped*1,2
+upper*327,70,60,10,47,35,91
+upset*108,14,21,1,1,3
+urban*50,41,28,3
+ureas
+urged*74,35,27,4,37
+urger
+urges*7,8,2,,1
+urine*20,1,7,,2
+usage*42,14,9,4,,19
+users+13,6,15,2,,46
+usher*7,2,2
+using*1825,143,167,9,5,249,123
+usual*313,96,118,5,,45,16
+usurp*,1
+usury+
+uteri
+utero
+utter*25,13,13,,47
+uvula
+vacua
+vacuo
+vague*30,25,27,4,,2
+vagus+
+vails
+vales*2,,1
+valet*3,2,1
+valid*15,22,31,7,3,12,46
+valor*5,1,,,31
+value*512,200,239,29,22,409,247
+valve*40,3,6
+vamps+
+vaned
+vanes*14
+vapes
+vapid+
+vapor*209,12,,,3
+varia
+vases*10,11,2
+vault*16,2,3,,3
+vaunt+,,1,,2
+veals*
+veeps+
+veers*2,1,,,,1
+vegan+
+veils*7,3,4,,3
+veins*79,6,16
+veiny+
+velds
+veldt+9,1
+venal+
+vends*
+venom*5,2,1,,7
+vents*2,4,2
+venue+,,2
+verbs*583,7,13
+verge*4,2,5,,,,1
+versa+8,6,3,1,,6,4
+verse*117,28,51,,,4
+verso+,,1
+verst
+verve+3,4,1
+vests*1,1
+vetch+1
+vexed*5,2,4,2,6
+vexes*,1
+vials*1
+viand+
+vibes+,1
+vicar*2,4,13
+vices*,5,1,,1
+video*2,2,,,,3
+viers
+views*117,51,83,12,1
+vigil*8,1,1
+vigor*27,14,,,6
+viler*
+villa*5,3,6
+ville
+vinca
+vined
+vines*66,8,3,,15
+vinyl*3,4
+viola*24,2
+viols+1
+viper*3,,1,,5
+viral+1
+vireo*
+vires ,,4
+virus*48,13,5
+visas*1
+vised
+vises*
+visit*443,109,143,2,39
+visor*6,,1
+vista*1,2,2
+vitae+2,,1
+vital*65,56,40,7,,1
+vitam
+vitas+
+vitro+,4
+vivas+
+vivid*67,25,14
+vivre ,,1
+vixen*2
+vizor+1
+vocab
+vocal*94,14,26
+vodka+4,,4
+vogue*2,4,3,2,,,1
+voice*1280,221,271,,463,1
+voids*,1
+voila+1
+voile*2
+volts*16,1,1
+vomit*4,,1,,1
+voted*60,27,11,9
+voter*7,4,1,9
+votes*54,20,23,27
+vouch*2
+vowed*8,5,1,,19
+vowel*1484,7
+vower
+voxel
+vroom 2
+vulva
+vying*1,3
+wacko+
+wacky+,1
+waded*33,2,2
+wader+
+wades*5
+wadis+1
+wafer*,,1,,3
+wafts*
+waged*8,7,2,2,4
+wager*8,3,,,2
+wages*74,42,61,7,41
+wagon*356,53,10,,1
+wahoo 1
+waifs*
+wails*2,2,,,2
+waist*80,11,16,,3
+waits*28,2,,1,11,3
+waive*,1,3
+waked*8,2,,,1
+waken*4,,2
+waker
+wakes*23,1,,,2
+waled+
+wales+1,2
+walks*140,13,10,,39,2,1
+walls*478,70,62,5,108
+waltz*29,1,12
+wands*2,,1,,1
+waned*5,2,1,,1
+wanes*2,,,,1
+wanly*1,,1
+wanna 6,5,3
+wanta 6,1
+wants*461,71,72,13,3,23,2
+wards*3,3,4,1
+wares*19,1,2,,14
+warms*31,1,1,,2
+warns*15,3,4,1,2,2
+warps*
+warts*4,5,1
+warty+9,1
+washy
+wasps*15,,,,1
+waspy
+wassa 1
+waste*191,35,55,9,120,2,2
+watch*969,80,80,4,68,17,2
+water*7194,436,387,10,518
+watsa 1
+watts*7
+waved*173,16,13,,13,,1
+waver*5,3,,,3
+waves*647,51,22,1,41
+waxed*173,4,6,,2
+waxen*3,1,2
+waxer+5
+waxes*647
+wazoo
+weald
+weals
+weans*
+wears*74,5,8,1,3,1
+weary*104,16,18,,48,1
+weave*53,4,3,,4
+webby
+wedge*34,4,1,1,1
+wedgy
+weeds*105,5,8,,12
+weedy*4,,3
+weeks*526,142,127,24,22,,1
+weeny
+weeps*3,,,,2
+weepy+
+weest
+wefts
+weigh*199,4,9,1,1
+weird*32,9,3,,,12,4
+weirs ,1
+welch+,5
+welds*2,,2,,,1
+wells*78,4,1,1,5
+welsh ,1
+welts*2,1,1
+wench+3
+wends*
+wests
+wetly 1,1
+whack*11,1,1,,,2
+whale*274,,8,,1
+whams+
+whang+
+wharf*42,2,6,3
+whats
+wheal
+wheat*342,9,12,10,53
+wheee 1
+wheel*418,54,32,,27,,4
+whelk*1
+whelm
+whelp*1,,,,2
+whens 2
+where*5611,930,1041,86,474,300,321
+whets*
+whews
+wheys*
+which*14016,3560,4467,347,3083,756,362
+whiff*6,1,2
+while*2837,679,590,110,384,132,35
+whims*1,1,1,1
+whine*13,4,2
+whiny+1
+whips*17,1,1,,6
+whipt 1
+whirl*26,3,2,,2
+whirr+5
+whirs*1
+whish+
+whisk*12,,1
+whist+5,,2
+white*2085,260,261,14,71,36,1
+whits*
+whizz+3
+whoas
+whole*1886,309,435,28,384,52,17
+whomp+1
+whooo 1
+whoop*19,1
+whops+
+whore 1,2,1
+whorl+
+whose*799,251,301,40,346,180,103
+whoso
+whump
+wicks*
+widen*14,5,3,2,,1
+wider*83,17,43,10,,17,1
+widow*54,24,28,,70,9
+width*149,14,12,,2,250,2
+wield*3,1,,,5
+wifey
+wilco
+wilds*13
+wiled
+wiles*4,2,,,4
+wills*8,1,2,,8
+wilts*1,,1
+wimps+
+wimpy+
+wince*4
+winch+4,,2
+winds*367,19,16,,32,,1
+windy*53,2,4,1,2
+wined+
+wines*20,24,25,,1
+wings*514,25,29,2,102
+winks*3,,,,4
+winos+,1
+wiped*79,19,14,1,16,2,3
+wiper+3
+wipes*4,,,,3,2,1
+wired*22,11,1
+wirer
+wires*205,13,6
+wised ,,1
+wiser*21,7,6,2,9
+wises
+wisps*8,1,1
+wispy*,2
+wists
+witch*109,5,2
+withs
+witty*4,10,8
+wives*68,17,50,2,15
+wizen
+woken*,,4
+wolds
+woman*750,217,243,5,409
+wombs*,,,,2
+women*592,184,198,14,251,,1
+wonks
+wonts
+woods*557,24,12,,4,1
+woody*24
+wooed*1,1,2,,1
+wooer+
+woofs*1
+wools*
+wooly*
+woosh 3
+woozy+1
+words*11215,272,315,16,660,184,49
+wordy*3,1
+works*485,124,165,15,234,90,45
+world*2799,687,586,81,353,12,11
+worms*119,4,7,,13
+wormy*1,1
+worry*214,55,44,4,5,13,2
+worse*180,50,90,9,37,8,1
+worst*108,34,45,8,3,2,4
+worth*327,91,118,19,18,13,1
+worts
+would*11188,2714,2799,460,696,450,102
+wound*161,28,26,,31
+woven*84,9,3,,13
+wowed*1
+wowee
+wrack+1,1
+wraps*12,2,,,1,,1
+wrath*17,8,4,,278
+wreak*1,1,,,1
+wreck*75,8,8,1,1
+wrens*8
+wrest*4,1,,1
+wrier
+wring*6,2,1,,2
+wrist*61,9,17
+write*9846,106,101,3,89,105,125
+writs+1,1
+wrong*606,129,162,20,101,29,12
+wrote*877,181,120,5,103,6,1
+wroth ,,,,1
+wrung*7,,1,1,2
+wryer*
+wryly*3,3,4
+wurst+
+xenon+3,1
+xerox+
+xored
+xylem+1,4
+yacht*16,1,17
+yahoo
+yanks*3,1,,1
+yards*360,63,57,,1,1
+yarns*63,6,2
+yawed 1
+yawls 2
+yawns+1,,2
+yawny 1
+yawps 1
+yearn*4,1,1,,1
+years*3966,958,1086,185,594,9,15
+yeast*47,3,1
+yecch
+yella 7
+yells*26
+yelps*2,1
+yenta
+yerba
+yeses*
+yield*47,35,42,5,52,16,17
+yikes+
+yipes+1
+yobbo
+yodel*2,1
+yogas*
+yogic
+yogis+
+yoked*2,,,,3
+yokel+1,1
+yokes*4,,,,2
+yolks+12,,1
+yores
+young*1920,367,485,22,358
+yourn 1
+yours*170,25,48,,76,2
+youse 1
+youth*201,75,48,8,102
+yowls*
+yoyos+
+yucca*12,1
+yucky+
+yukky
+yules*
+yummy+3
+yurts
+zappy
+zayin
+zeals*
+zebra*25,1
+zebus+1
+zeros*42,2,7,,,2,3
+zests*
+zesty+
+zetas+
+zilch+
+zincs
+zings+
+zippy+
+zloty
+zombi
+zonal+,,2
+zoned*,1
+zones*43,3,9,2
+zonks
+zooey
+zooks
+zooms*3,1
+zowie 4
+* End of file "words.dat"