girth.w
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
源码类别:

通讯编程

开发平台:

Visual C++

  1. % This file is part of the Stanford GraphBase (c) Stanford University 1993
  2. @i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
  3. @i gb_types.w
  4. deftitle{GIRTH}
  5. let==equiv % congruence sign
  6. prerequisite{GB_,RAMAN}
  7. @* Introduction. This demonstration program uses graphs
  8. constructed by the |raman| procedure in the {sc GB_,RAMAN} module to produce
  9. an interactive program called .{girth}, which computes the girth and
  10. diameter of a class of Ramanujan graphs.
  11. The girth of a graph is the length of its shortest cycle; the diameter
  12. is the maximum length of a shortest path between two vertices.
  13. A Ramanujan graph is a connected, undirected graph in which every vertex
  14. @^Ramanujan graphs@>
  15. has degree~|p+1|, with the property that every eigenvalue of its adjacency
  16. matrix is either $pm(p+1)$ or has absolute value $le2sqrt{mathstrut p}$.
  17. Exact values for the girth are of interest because the bipartite graphs
  18. produced by |raman| apparently have larger girth than any other known
  19. family of regular graphs, even if we consider graphs whose existence
  20. is known only by nonconstructive methods, except for the cubic ``sextet''
  21. graphs of Biggs, Hoare, and Weiss [{sl Combinatorica/ bf3} (1983),
  22. @^Biggs, Norman L.@>
  23. @^Hoare, M. J.@>
  24. @^Weiss, Alfred@>
  25. 153--165; {bf4} (1984), 241--245].
  26. Exact values for the diameter are of interest because the diameter of
  27. any Ramanujan graph is at most twice the minimum possible diameter
  28. of any regular graph.
  29. The program will prompt you for two numbers, |p| and |q|. These should
  30. be distinct prime numbers, not too large, with |q>2|.  A graph is
  31. constructed in which each vertex has degree~|p+1|. The number of
  32. vertices is $(q^3-q)/2$ if |p| is a quadratic residue modulo~|q|, or
  33. $q^3-q$ if |p| is not a quadratic residue. In the latter case, the
  34. graph is bipartite and it is known to have rather large girth.
  35. If |p=2|, the value of |q| is further restricted to be of the form
  36. $104k+(1,3,9,17,25,27,35,43,49,allowbreak51,75,81)$. This means that the only
  37. feasible values of |q| to go with |p=2| are probably 3, 17, and 43;
  38. the next case, |q=107|, would generate a bipartite graph with
  39. 1,224,936 vertices and 3,674,808 arcs, thus requiring approximately
  40. 113 megabytes of memory (not to mention a nontrivial amount of
  41. computer time). If you want to compute the girth and diameter
  42. of Ramanujan graphs for large |p| and/or~|q|, much better methods are
  43. available based on number theory; the present program is merely a
  44. demonstration of how to interface with the output of |raman|.
  45. Incidentally, the graph for |p=2| and |q=43| turns
  46. out to have 79464 vertices, girth 20, and diameter~22.
  47. The program will examine the graph and compute its girth and its diameter,
  48. then will prompt you for another choice of |p| and |q|.
  49. @ Here is the general layout of this program, as seen by the CEE/ compiler:
  50. @p
  51. #include "gb_graph.h" /* the standard GraphBase data structures */
  52. #include "gb_raman.h" /* Ramanujan graph generator */
  53. @h@#
  54. @<Global variables@>@;
  55. main()
  56. {
  57.   printf(
  58.     "This program explores the girth and diameter of Ramanujan graphs.n");
  59.   printf("The bipartite graphs have q^3-q vertices, and the non-bipartiten");
  60.   printf("graphs have half that number. Each vertex has degree p+1.n");
  61.   printf("Both p and q should be odd prime numbers;n");
  62.   printf("  or you can try p = 2 with q = 17 or 43.n");
  63.   while (1) {
  64.     @<Prompt the user for |p| and |q|; |break| if unsuccessful@>;
  65.     g=raman(p,q,0L,0L);
  66.     if (g==NULL) @<Explain that the graph could not be constructed@>@;
  67.     else {
  68.       @<Print the theoretical bounds on girth and diameter of |g|@>;
  69.       @<Compute and print the true girth and diameter of |g|@>;
  70.       gb_recycle(g);
  71.     }
  72.   }
  73.   return 0; /* normal exit */
  74. }
  75. @ @<Global...@>=
  76. Graph *g; /* the current Ramanujan graph */
  77. long p; /* the branching factor (degree minus one) */
  78. long q; /* cube root of the graph size */
  79. char buffer[16]; /* place to collect what the user types */
  80. @ @d prompt(s)
  81.     {@+printf(s);@+fflush(stdout); /* make sure the user sees the prompt */
  82.       if (fgets(buffer,15,stdin)==NULL) break;@+}
  83. @<Prompt...@>=
  84. prompt("nChoose a branching factor, p: ");
  85. if (sscanf(buffer,"%ld",&p)!=1) break;
  86. prompt("OK, now choose the cube root of graph size, q: ");
  87. if (sscanf(buffer,"%ld",&q)!=1) break;
  88. @ @<Explain that the graph could not be constructed@>=
  89. printf(" Sorry, I couldn't make that graph (%s).n",@|
  90.  panic_code==very_bad_specs?  "q is out of range":@|
  91.  panic_code==very_bad_specs+1? "p is out of range":@|
  92.  panic_code==bad_specs+5?   "q is too big":@|
  93.  panic_code==bad_specs+6?    "p is too big":@|
  94.  panic_code==bad_specs+1?   "q isn't prime":@|
  95.  panic_code==bad_specs+7?   "p isn't prime":@|
  96.  panic_code==bad_specs+3?    "p is a multiple of q":@|
  97.  panic_code==bad_specs+2?    "q isn't compatible with p=2":@|
  98.                    "not enough memory");
  99. @* Bounds. The theory of Ramanujan graphs allows us to predict the
  100. girth and diameter to within a factor of 2~or~so.
  101. In the first place, we can easily derive an upper bound on the girth
  102. and a lower bound on the diameter, valid for any $n$-vertex regular graph
  103. of degree~$p+1$. Such a graph has at most $(p+1)p^{k-1}$ points at
  104. distance~$k$ from any given vertex; this implies a lower bound
  105. on the diameter~$d$:
  106. $$1+(p+1)+(p+1)p+(p+1)p^2+cdots+(p+1)p^{d-1};ge;n.$$
  107. Similarly, if the girth $g$ is odd, say $g=2k+1$, the points at
  108. distance~$le k$ from any vertex must be distinct, so we have
  109. $$1+(p+1)+(p+1)p+(p+1)p^2+cdots+(p+1)p^{k-1};le;n;$$
  110. and if $g=2k+2$, at least $p^k$ further points must exist at distance
  111. $k+1$, because the $(p+1)p^k$ paths of length $k+1$ can end at
  112. a particular vertex at most $p+1$ times. Thus
  113. $$1+(p+1)+(p+1)p+(p+1)p^2+cdots+(p+1)p^{k-1}+p^k;le;n$$
  114. when the girth is even.
  115. In the following code we let $|pp|=p^{dl}$ and
  116. $s=1+(p+1)+cdots+(p+1)p^{dl}$.
  117. @<Compute the ``trivial'' bounds |gu| and |dl| on girth and diameter@>=
  118. s=p+2;@+dl=1;@+pp=p;@+gu=3;
  119. while (s<n) {
  120.   s+=pp;
  121.   if (s<=n) gu++;
  122.   dl++;
  123.   pp*=p;
  124.   s+=pp;
  125.   if (s<=n) gu++;
  126. }
  127. @ When |p>2|, we can use the theory of integral quaternions to derive a lower
  128. bound on the girth of the graphs produced by |raman|. A path of length~$g$
  129. from a vertex to itself exists if and only if there is an integral
  130. quaternion $alpha=a_0+a_1i+a_2j+a_3k$ of norm $p^g$ such that
  131. the $a$'s are not all multiples of~$p$, while
  132. $a_1$, $a_2$, and $a_3$ are multiples of~$q$ and $a_0not=a_1=a_2=a_3$
  133. (mod~2). This means we have integers $(a_0,a_1,a_2,a_3)$ with
  134. $$a_0^2+a_1^2+a_2^2+a_3^2=p^{,g},$$ satisfying the stated properties
  135. mod~$q$ and mod~2.
  136. If $a_1$, $a_2$, and $a_3$ are even, they cannot all be zero so
  137. we must have $p^{,g}ge1+4q^2$; if they are odd, we must have
  138. $p^{,g}ge4+3q^2$. (The latter is possible only when $g$ is odd and
  139. $pbmod4=3$.) Since $n$ is roughly proportional to~$q^3$, this means
  140. $g$ must be at least about ${2over3}log_p n$. Thus $g$~isn't
  141. too much less than the maximum girth possible in any regular graph,
  142. which we have shown is at most about $2log_p n$.
  143. When the graph is bipartite we can, in fact, prove that $g$ is
  144. approximately ${4over3}log_p n$. The bipartite case occurs if and
  145. only if $p$ is not a quadratic residue modulo~|q|; hence the
  146. number~$g$ in the previous paragraph must be even, say $g=2r$. Then
  147. $p^{,g}bmod4=1$, and $a_0$ must be odd.  The congruence $a_0^2=p^{2r}$
  148. (mod~$q^2$) implies that $a_0=pm p^r$, because all numbers
  149. relatively prime to $q^2$ are powers of a primitive root. We can
  150. assume without loss of generality that $a_0=p^r-2mq^2$, where
  151. $0<m<p^r/q^2$; it follows in particular that $p^r>q^2$.  Conversely,
  152. if $p^r-q^2$ can be written as a sum of three squares
  153. $b_1^2+b_2^2+b_3^2$, then
  154. $p^{2r}=(p^r-2q^2)^2+(2b_1q)^2+(2b_2q)^2+(2b_3q)^2$ is a
  155. representation of the required type. If $p^r-q^2$ is a positive
  156. integer that cannot be represented as a sum of three squares, a
  157. well-known theorem of Legendre tells us that $p^r-q^2=4^ts$, where
  158. $s=7$ (mod~8).  Since $p$ and $q$ are odd, we have $tge1$; hence
  159. $p^r-2q^2$ is odd. If $p^r-2q^2$ is a positive odd integer, Legendre's
  160. theorem tells us that we can write $2p^r-4q^2=b_1^2+b_2^2+b_3^2$;
  161. hence $p^{2r}=(p^r-4q^2)^2+ (2b_1q)^2+(2b_2q)^2+(2b_3q)^2$. We
  162. conclude that the girth is either $2lceillog_pq^2rceil$ or
  163. $2lceillog_p2q^2rceil$. (This explicit calculation, which makes our
  164. program for calculating the girth unnecessary or at best redundant in
  165. the bipartite case, is due to G. A. Margulis and, independently, to
  166. @^Margulis, Grigori{ui} Aleksandrovich@>
  167. @^Biggs, Norman L.@>
  168. @^Boshier, A. G.@>
  169. Biggs and Boshier [{sl Journal of Combinatorial Theory/ bf B49}
  170. (1990), 190--194].)
  171. A girth of 1 or 2 can occur, since these graphs might have self-loops
  172. or multiple edges if |p| is sufficiently large.
  173. @<Compute a lower bound |gl| on the girth@>=
  174. if (bipartite) {@+long b=q*q;
  175.   for (gl=1,pp=p;pp<=b;gl++,pp*=p) ; /* iterate until $p^{,g}>q^2$ */
  176.   gl+=gl;
  177. }@+else {@+long b1=1+4*q*q, b2=4+3*q*q; /* bounds on $p^{,g}$ */
  178.   for (gl=1,pp=p;pp<b1;gl++,pp*=p) {
  179.     if (pp>=b2 && (gl&1) && (p&2)) break;
  180.   }
  181. }
  182. @ Upper bounds on the diameter of any Ramanujan graph can be derived
  183. as shown in the paper by Lubotzky, Phillips, and Sarnak in
  184. @^Lubotzky, Alexander@>
  185. @^Phillips, Ralph Saul@>
  186. @^Sarnak, Peter@>
  187. {sl Combinatorica bf8} (1988), page~275. (However, a slight correction
  188. to their proof is necessary---their parameter~$l$ should be~odd
  189. when $x$ and~$y$ lie in different parts of a bipartite graph.)
  190. Their argument demonstrates that $p^{(d-1)/2}<2n$ in the
  191. nonbipartite case and $p^{(d-2)/2}<n$ in the bipartite case; therefore
  192. we obtain the upper bound $dle 2log_p n+O(1)$, which is about twice the lower
  193. bound that holds in an arbitrary regular graph.
  194. @<Compute an upper bound |du| on the diameter@>=
  195. {@+long nn=(bipartite? n: 2*n);
  196.   for (du=0,pp=1; pp<nn; du+=2,pp*=p) ;
  197.   @<Decrease |du| by 1, if $|pp|/|nn|gesqrt p$@>;
  198.   if (bipartite) du++;
  199. }
  200. @ Floating point arithmetic might not be accurate enough for the test
  201. required in this section. We avoid it by using an all-integer method
  202. analogous to Euclid's algorithm, based on the continued fraction for
  203. $sqrt p$ [{sl Seminumerical Algorithms}, exercise 4.5.3--12]. In the
  204. loop here we want to compare |nn/pp| to $(sqrt p+a)/b$, where $sqrt p+a
  205. >b>0$ and $p-a^2$ is a multiple of~$b$.
  206. @<Decrease |du|...@>=
  207. {@+long qq=pp/nn;
  208.   if (qq*qq>p) du--;
  209.   else if ((qq+1)*(qq+1)>p) { /* $|qq|=lfloorsqrt p,rfloor$ */
  210.     long aa=qq, bb=p-aa*aa, parity=0;
  211.     pp-=qq*nn;
  212.     while (1) {
  213.       long x=(aa+qq)/bb, y=nn-x*pp;
  214.       if (y<=0) break;
  215.       aa=bb*x-aa; /* now $0<|aa|<sqrt p$ */
  216.       bb=(p-aa*aa)/bb;
  217.       nn=pp;@+pp=y;
  218.       parity^=1;
  219.     }
  220.     if (!parity) du--;
  221.   }
  222. }
  223. @ @<Print the theoretical bounds on girth and diameter of |g|@>=
  224. n=g->n;
  225. if (n==(q+1)*q*(q-1)) bipartite=1;
  226. else bipartite=0;
  227. printf(
  228.   "The graph has %ld vertices, each of degree %ld, and it is %sbipartite.n",
  229.   n,p+1,bipartite? "": "not ");
  230. @<Compute the ``trivial'' bounds |gu| and |dl| on girth and diameter@>;
  231. printf("Any such graph must have diameter >= %ld and girth <= %ld;n",
  232.   dl,gu);
  233. @<Compute an upper bound |du| on the diameter@>;
  234. printf("theoretical considerations tell us that this one's diameter is <= %ld",
  235.   du);
  236. if (p==2) printf(".n");
  237. else {
  238.   @<Compute a lower bound |gl| on the girth@>;
  239.   printf(",nand its girth is >= %ld.n",gl);
  240. }
  241. @ We had better declare all the variables we've been using so freely.
  242. @<Global...@>=
  243. long gl,gu,dl,du; /* theoretical bounds */
  244. long pp; /* power of $p$ */
  245. long s; /* accumulated sum */
  246. long n; /* number of vertices */
  247. char bipartite; /* is the graph bipartite? */
  248. @*Breadth-first search. The graphs produced by |raman| are symmetrical, in
  249. the sense that there is an automorphism taking any vertex into any
  250. other. Each vertex $V$ and each edge $P$ corresponds to a $2times2$
  251. matrix, and the path $P_1P_2ldots P_k$ leading from vertex~$V$ to
  252. vertex $VP_1P_2ldots P_k$ has the same properties as the path leading
  253. from vertex~$U$ to vertex $UP_1P_2ldots P_k$. Therefore we can find
  254. the girth and the diameter by starting at any vertex $v_0$.
  255. We compute the number of points at distance $k$ from $v_0$ for
  256. all $k$, by explicitly forming a linked list of all such points.
  257. Utility field |link| is used for the links. The lists
  258. terminate with a non-null |sentinel| value, so that we can also
  259. use the condition |link==NULL| to tell if a vertex has been
  260. encountered before. Another utility field, |dist|, contains the
  261. distance from the starting point, and |back| points to a
  262. vertex one step closer.
  263. @d link w.V /* the field where we store links, initially |NULL| */
  264. @d dist v.I /* the field where we store distances, initially 0 */
  265. @d back u.V /* the field where we store backpointers, initially |NULL| */
  266. @<Compute and print the true girth and diameter of |g|@>=
  267. printf("Starting at any given vertex, there aren");
  268. {@+long k; /* current distance being generated */
  269.   long c; /* how many we've seen so far at this distance */
  270.   register Vertex *v; /* current vertex in list at distance $k-1$ */
  271.   register Vertex *u; /* head of list for distance $k$ */
  272.   Vertex *sentinel=g->vertices+n; /* nonzero link at end of lists */
  273.   long girth=999; /* length of smallest cycle found, initially infinite */
  274.   k=0;
  275.   u=g->vertices;
  276.   u->link=sentinel;
  277.   c=1;
  278.   while (c) {
  279.     for (v=u,u=sentinel,c=0,k++;v!=sentinel;v=v->link)
  280.       @<Place all vertices adjacent to |v| onto list |u|, unless they've
  281.          been encountered before, increasing |c| whenever the list grows@>;
  282.     printf("%8ld vertices at distance %ld%sn", c, k, c>0? ",": ".");
  283.   }
  284.   printf("So the diameter is %ld, and the girth is %ld.n",k-1,girth);
  285. }
  286. @ @<Place all...@>=
  287. {@+register Arc *a;
  288.   for (a=v->arcs;a;a=a->next) {@+register Vertex *w;
  289.                                 /* vertex adjacent to |v| */
  290.     w=a->tip;
  291.     if (w->link==NULL) {
  292.       w->link=u;
  293.       w->dist=k;
  294.       w->back=v;
  295.       u=w;
  296.       c++;
  297.     }@+else if (w->dist+k<girth && w!=v->back)
  298.       girth=w->dist+k;
  299.   }
  300. }
  301. @* Index. Finally, here's a list that shows where the identifiers of this
  302. program are defined and used.