diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/graphbase |
Initial commit
Diffstat (limited to 'support/graphbase')
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 Binary files differnew file mode 100644 index 0000000000..a532f0555e --- /dev/null +++ b/support/graphbase/abstract.pdf 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&} + \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" |