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

通讯编程

开发平台:

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{GB_,RAMAN}
  5. let==equiv % congruence sign
  6. prerequisite{GB_,GRAPH}
  7. @* Introduction. This GraphBase module contains the |raman| subroutine,
  8. which creates a family of ``Ramanujan graphs'' based on a theory
  9. developed by Alexander Lubotzky, Ralph Phillips, and Peter Sarnak
  10. @^Lubotzky, Alexander@>
  11. @^Phillips, Ralph Saul@>
  12. @^Sarnak, Peter@>
  13. [see {sl Combinatorica bf8} (1988), 261--277].
  14. Ramanujan graphs are defined by the following properties:
  15. @^Ramanujan graphs@>
  16. They are connected, undirected graphs in which every vertex has
  17. degree~$k$, and every eigenvalue of the adjacency matrix
  18. is either $pm k$ or has absolute value $le2sqrt{mathstrut k-1}$.
  19. Such graphs are known to have good expansion properties, small diameter,
  20. and relatively small independent sets; they cannot be colored with
  21. fewer than $k/bigl(2sqrt{mathstrut k-1},bigr)$ colors unless they are
  22. bipartite. The particular examples of Ramanujan graphs constructed here
  23. are based on interesting properties of quaternions with integer coefficients.
  24. An example of the use of this procedure can be found in the demo program
  25. called {sc GIRTH}.
  26. @(gb_raman.h@>=
  27. extern Graph *raman();
  28. @ The subroutine call |raman(p,q,type,reduce)|
  29. constructs an undirected graph in which each vertex has degree~|p+1|.
  30. The number of vertices is~|q+1| if |type=1|, or~${1over2}q(q+1)$ if |type=2|,
  31. or ${1over2}(q-1)q(q+1)$ if |type=3|, or |(q-1)q(q+1)| if
  32. |type=4|. The graph will be bipartite if and only if it has type~4.
  33. Parameters |p| and |q| must be distinct prime numbers,
  34. and |q|~must be odd. Furthermore there are additional restrictions:
  35. If |p=2|, the other parameter |q| must satisfy $qbmod8in{1,3}$
  36. and $qbmod13in{1,3,4,9,10,12}$; this rules out about one fourth of
  37. all primes. Moreover, if |type=3| the value of |p| must be a
  38. quadratic residue modulo~$q$; in other words, there must be an
  39. integer~$x$ such that $x^2=p$ (mod~$q$). If |type=4|, the value of |p|
  40. must not be a quadratic residue.
  41. If you specify |type=0|, the procedure
  42. will choose the largest permissible type (either 3 or~4);
  43. the value of the type selected will
  44. appear as part of the string placed in the resulting graph's |id| field.
  45. For example, if |type=0|, |p=2|, and |q=43|, a type~4 graph will be
  46. generated, because 2 is not a quadratic residue modulo~43. This
  47. graph will have $44times43times42=79464$ vertices, each of degree~3.
  48. (Notice that graphs of types 3 and~4 can be quite large even when
  49. |q| is rather small.)
  50. The largest permissible value of |q| is 46337; this is the largest
  51. prime whose square is less than $2^{31}$. Of course you would use
  52. it only for a graph of type~1.
  53. If |reduce| is nonzero, loops and multiple edges will be suppressed.
  54. In this case the degrees of some vertices might turn out to be less than~|p+1|,
  55. in spite of what was said above.
  56. Although type 4 graphs are bipartite, the vertices
  57. are not separated into two blocks as in other bipartite
  58. graphs produced by GraphBase routines.
  59. All edges of the graphs have length 1.
  60. @ If the |raman| routine encounters a problem, it returns |NULL|
  61. (.{NULL}), after putting a code number into the external variable
  62. |panic_code|. This code number identifies the type of failure.
  63. Otherwise |raman| returns a pointer to the newly created graph, which
  64. will be represented with the data structures explained in {sc GB_,GRAPH}.
  65. (The external variable |panic_code| is itself defined in
  66. {sc GB_,GRAPH}.)
  67. @d panic(c) @+{@+panic_code=c;@+gb_trouble_code=0;@+return NULL;@+}
  68. @d dead_panic(c) {@+gb_free(working_storage);@+panic(c);@+}
  69. @d late_panic(c) {@+gb_recycle(new_graph);@+dead_panic(c);@+}
  70. @ The CEE/ file .{gb_raman.c} has the following general shape:
  71. @p
  72. #include "gb_graph.h" /* we will use the {sc GB_,GRAPH} data structures */
  73. @h@#
  74. @<Type declarations@>@;
  75. @<Private variables and routines@>@;
  76. @#
  77. Graph *raman(p,q,type,reduce)
  78.   long p; /* one less than the desired degree; must be prime */
  79.   long q; /* size parameter; must be prime and properly related to |type| */
  80.   unsigned long type; /* selector between different possible constructions */
  81.   unsigned long reduce; /* if nonzero, multiple edges and self-loops won't occur */
  82. {@+@<Local variables@>@;@#
  83.   @<Prepare tables for doing arithmetic modulo~|q|@>;
  84.   @<Choose or verify the |type|, and determine the number |n| of vertices@>;
  85.   @<Set up a graph with |n| vertices, and assign vertex labels@>;
  86.   @<Compute |p+1| generators that will define the graph's edges@>;
  87.   @<Append the edges@>;
  88.   if (gb_trouble_code)
  89.     late_panic(alloc_fault);
  90.        /* oops, we ran out of memory somewhere back there */
  91.   gb_free(working_storage);
  92.   return new_graph;
  93. }
  94. @ @<Local var...@>=
  95. Graph *new_graph; /* the graph constructed by |raman| */
  96. Area working_storage; /* place for auxiliary tables */
  97. @* Brute force number theory. Instead of using routines like Euclid's
  98. algorithm to compute inverses and square roots modulo~|q|, we have
  99. plenty of time to build complete tables, since |q| is smaller than
  100. the number of vertices we will be generating.
  101. We will make three tables: |q_sqr[k]| will contain $k^2$ modulo~|q|;
  102. |q_sqrt[k]| will contain one of the values of $sqrt{mathstrut k}$
  103. if $k$ is a quadratic residue; and |q_inv[k]| will contain the multiplicative
  104. inverse of~|k|.
  105. @<Private...@>=
  106. static long *q_sqr; /* squares */
  107. static long *q_sqrt; /* square roots (or $-1$ if not a quadratic residue) */
  108. static long *q_inv; /* reciprocals */
  109. @ @<Prepare tables for doing arithmetic modulo~|q|@>=
  110. if (q<3 || q>46337) panic(very_bad_specs);
  111.   /* |q| is way too small or way too big */
  112. if (p<2) panic(very_bad_specs+1); /* |p| is way too small */
  113. init_area(working_storage);
  114. q_sqr=gb_typed_alloc(3*q,long,working_storage);
  115. if (q_sqr==0) panic(no_room+1);
  116. q_sqrt=q_sqr+q;
  117. q_inv=q_sqrt+q; /* note that |gb_alloc| has initialized everything to zero */
  118. @<Compute the |q_sqr| and |q_sqrt| tables@>;
  119. @<Find a primitive root |a|, modulo |q|, and its inverse |aa|@>;
  120. @<Compute the |q_inv| table@>;
  121. @ @<Compute the |q_sqr| and |q_sqrt| tables@>=
  122. for (a=1; a<q; a++) q_sqrt[a]=-1;
  123. for (a=1,aa=1; a<q; aa=(aa+a+a+1)%q,a++) {
  124.   q_sqr[a]=aa;
  125.   q_sqrt[aa]=q-a; /* the smaller square root will survive */
  126.   q_inv[aa]=-1;
  127.      /* we make |q_inv[aa]| nonzero when |aa| can't be a primitive root */
  128. }
  129. @ @<Local v...@>=
  130. register long a, aa, k; /* primary indices in loops */
  131. long b, bb, c, cc, d, dd; /* secondary indices */
  132. long n; /* the number of vertices */
  133. long n_factor; /* either ${1over2}(q-1)$ (type~3) or $q-1$ (type 4) */
  134. register Vertex *v; /* the current vertex of interest */
  135. @ Here we implicitly test that |q| is prime, by finding a primitive
  136. root whose powers generate everything. If |q| is not prime, its smallest
  137. divisor will cause the inner loop in this step to terminate with |k>=q|,
  138. because no power of that divisor will be congruent to~1.
  139. @<Find a primitive root |a|, modulo |q|, and its inverse |aa|@>=
  140. for (a=2; ; a++)
  141.   if (q_inv[a]==0) {
  142.     for (b=a,k=1; b!=1&&k<q; aa=b,b=(a*b)%q,k++) q_inv[b]=-1;
  143.     if (k>=q) dead_panic(bad_specs+1); /* |q| is not prime */
  144.     if (k==q-1) break; /* good, |a| is the primitive root we seek */
  145.   }
  146. @ As soon as we have discovered
  147. a primitive root, it is easy to generate all the inverses. (We
  148. could also generate the discrete logarithms if we had a need for them.)
  149. We set |q_inv[0]=q|; this will be our internal representation of $infty$.
  150. @<Compute the |q_inv| table@>=
  151. for (b=a,bb=aa; b!=bb; b=(a*b)%q,bb=(aa*bb)%q) q_inv[b]=bb,q_inv[bb]=b;
  152. q_inv[1]=1; q_inv[b]=b; /* at this point |b| must equal |q-1| */
  153. q_inv[0]=q;
  154. @ The conditions we stated for validity of |q| when |p=2| are equivalent
  155. to the existence of $sqrt{-2}$ and $sqrt{13}$ modulo~|q|, according
  156. to the law of quadratic reciprocity (see, for example, {sl Fundamental
  157. Algorithms}, exercise 1.2.4--47).
  158. @<Choose or verify the |type|...@>=
  159. if (p==2) {
  160.   if (q_sqrt[13%q]<0 || q_sqrt[q-2]<0)
  161.     dead_panic(bad_specs+2); /* improper prime to go with |p=2| */
  162. }
  163. if ((a=p%q)==0) dead_panic(bad_specs+3); /* |p| divisible by |q| */
  164. if (type==0) type=(q_sqrt[a]>0? 3: 4);
  165. n_factor=(type==3? (q-1)/2: q-1);
  166. switch (type) {
  167.  case 1: n=q+1;@+break;
  168.  case 2: n=q*(q+1)/2;@+break;
  169.  default: if ((q_sqrt[a]>0 && type!=3) || (q_sqrt[a]<0 && type!=4))@/
  170.              dead_panic(bad_specs+4); /* wrong type for |p| modulo |q| */
  171.    if (q>1289) dead_panic(bad_specs+5); /* way too big for types 3, 4 */
  172.    n=n_factor*q*(q+1);
  173.    break;
  174. }
  175. if (p>=(long)(0x3fffffff/n)) dead_panic(bad_specs+6); /* $(p+1)nge2^{30}$ */
  176. @* The vertices. Graphs of type 1 have vertices from the
  177. set ${0,1,ldots,q-1,infty}$, namely the integers modulo~|q| with
  178. an additional ``infinite'' element thrown in. The idea is to
  179. operate on these quantities by adding constants, and/or multiplying by
  180. constants, and/or taking reciprocals, modulo~|q|.
  181. Graphs of type 2 have vertices that are unordered pairs of
  182. distinct elements from that same $(q+1)$-element set.
  183. Graphs of types 3 and 4 have vertices that are $2times2$ matrices
  184. having nonzero determinants modulo~|q|. The determinants of type~3 matrices
  185. are, in fact, nonzero quadratic residues. We consider two matrices to be
  186. equivalent if one is obtained from the other by multiplying all entries
  187. by a constant (modulo~|q|); therefore we will normalize all the matrices
  188. so that the second row is either $(0,1)$ or has the form $(1,x)$ for
  189. some~$x$. The total number of equivalence classes of type~4 matrices obtainable
  190. in this way is $(q+1)q(q-1)$, because we can choose the second row in
  191. $q+1$ ways, after which there are two cases: Either the second row is
  192. $(0,1)$, and we can select the upper right corner element arbitrarily
  193. and choose the upper left corner element nonzero; or the second row is $(1,x)$,
  194. and we can select the upper left corner element arbitrarily and then choose
  195. an upper right corner element to make the determinant nonzero. For type~3
  196. the counting is similar, except that ``nonzero'' becomes ``nonzero
  197. quadratic residue,'' hence there are exactly half as many choices.
  198. It is easy to verify that the equivalence classes of matrices that
  199. correspond to vertices in these graphs of types 3 and~4 are closed
  200. under matrix multiplication. Therefore the vertices can be regarded as the
  201. elements of finite groups. The type~3 group for a given |q| is often
  202. called the linear fractional group $LF(2,{bf F}_q)$, or the
  203. projective special linear group $PSL(2,{bf F}_q)$, or the linear
  204. simple group $L_2(q)$; it can also be regarded as the group of
  205. $2times2$ matrices with determinant~1 (mod~$q$), when the matrix $A$
  206. is considered equivalent to $-A$. (This group is a simple group for
  207. all primes |q>2|.) The type~4 group is officially known as the
  208. projective general linear group of degree~2 over the field of |q|~elements,
  209. $PGL(2,{bf F}_q)$.
  210. @<Set up a graph...@>=
  211. new_graph=gb_new_graph(n);
  212. if (new_graph==NULL)
  213.   dead_panic(no_room); /* out of memory before we try to add edges */
  214. sprintf(new_graph->id,"raman(%ld,%ld,%lu,%lu)",p,q,type,reduce);
  215. strcpy(new_graph->util_types,"ZZZIIZIZZZZZZZ");
  216. v=new_graph->vertices;
  217. switch(type) {
  218.  case 1: @<Assign labels from the set ${0,1,ldots,q-1,infty}$@>;@+break;
  219.  case 2: @<Assign labels for pairs of distinct elements@>;@+break;
  220.  default: @<Assign projective matrix labels@>;@+break;
  221. }
  222. @ Type 1 graphs are the easiest to label. We store a serial number
  223. in utility field |x.I|, using $q$ to represent~$infty$.
  224. @<Assign labels from the set ${0,1,ldots,q-1,infty}$@>=
  225. new_graph->util_types[4]='Z';
  226. for (a=0;a<q;a++) {
  227.   sprintf(name_buf,"%ld",a);
  228.   v->name=gb_save_string(name_buf);
  229.   v->x.I=a;
  230.   v++;
  231. }
  232. v->name=gb_save_string("INF");
  233. v->x.I=q;
  234. v++;
  235. @ @<Private...@>=
  236. static char name_buf[]="(1111,1111;1,1111)"; /* place to form vertex names */
  237. @ The type 2 labels run from ${0,1}$ to ${q-1,infty}$; we put the
  238. coefficients into |x.I| and |y.I|, where they might prove useful in
  239. some applications.
  240. @<Assign labels for pairs...@>=
  241. for (a=0;a<q;a++)
  242.   for (aa=a+1;aa<=q;aa++) {
  243.     if (aa==q) sprintf(name_buf,"{%ld,INF}",a);
  244.     else sprintf(name_buf,"{%ld,%ld}",a,aa);
  245.     v->name=gb_save_string(name_buf);
  246.     v->x.I=a;@+v->y.I=aa;
  247.     v++;
  248.   }
  249. @ For graphs of types 3 and 4, we set the |x.I| and |y.I| fields to
  250. the elements of the first row of the matrix, and we set the |z.I|
  251. field equal to the ratio of the elements of the second row (again with $q$
  252. representing~$infty$).
  253. The vertices in this case consist of |q(q+1)| blocks of vertices
  254. having a given second row and a given element in the upper left or upper right
  255. position. Within each block of vertices, the determinants are
  256. respectively congruent modulo~|q| to $1^2$, $2^2$, dots,~$({q-1over2})^2$
  257. in the case of type~3 graphs, or to 1,~2, dots,~$q-1$ in the case of type~4.
  258. @<Assign projective matrix labels@>=
  259. new_graph->util_types[5]='I';
  260. for (c=0;c<=q;c++)
  261.   for (b=0;b<q;b++)
  262.     for (a=1;a<=n_factor;a++) {
  263.       v->z.I=c;
  264.       if (c==q) { /* second row of matrix is $(0,1)$ */
  265.         v->y.I=b;
  266.         v->x.I=(type==3? q_sqr[a]: a); /* determinant is $a^2$ or $a$ */
  267.         sprintf(name_buf,"(%ld,%ld;0,1)",v->x.I,b);
  268.       }@+else { /* second row of matrix is $(1,c)$ */
  269.         v->x.I=b;
  270.         v->y.I=(b*c+q-(type==3? q_sqr[a]: a))%q;
  271.             /* determinant is $a^2$ or $a$ */
  272.         sprintf(name_buf,"(%ld,%ld;1,%ld)",b,v->y.I,c);
  273.       }
  274.       v->name=gb_save_string(name_buf);
  275.       v++;
  276.     }
  277.     
  278. @* Group generators. We will define a set of |p+1| permutations ${pi_0,
  279. pi_1,ldots,pi_p}$ of the vertices, such that the arcs of our graph will
  280. go from $v$ to $vpi_k$ for |0<=k<=p|. Thus, each path in the graph will be
  281. defined by a product of permutations; the cycles of the graph will correspond
  282. to vertices that are left fixed by a product of permutations.
  283. The graph will be undirected, because the inverse of each $pi_k$ will
  284. also be one of the permutations of the generating set.
  285. In fact, each permutation $pi_k$ will be defined by a $2times2$ matrix.
  286. For graphs of types 3 and~4, the permutations will therefore correspond to
  287. certain vertices, and the vertex $vpi_k$ will simply be the product of matrix
  288. $v$ by matrix $pi_k$.
  289. For graphs of type 1, the permutations will be defined by linear fractional
  290. transformations, which are mappings of the form
  291. $$v;longmapsto; {av+bover
  292.                     cv+d}bmod q,.$$
  293. This transformation applies
  294. to all $vin{0,1,ldots,q-1,infty}$, under the usual conventions
  295. that $x/0=infty$ when $xne0$ and $(xinfty+x')/(yinfty+y')=x/y$.
  296. The composition of two such transformations is again a linear fractional
  297. transformation, corresponding to the product of the two associated
  298. matrices $bigl({a,batop c,d}bigr)$.
  299. Graphs of type 2 will be handled just like graphs of type 1,
  300. except that we will compute the images of two distinct points
  301. $v={v_1,v_2}$ under the linear fractional transformation. The two
  302. images will be distinct, because the transformation is invertible.
  303. When |p=2|, a special set of three generating matrices $pi_0$, $pi_1$,
  304. $pi_2$ can be shown to define Ramanujan graphs; these matrices are
  305. described below. Otherwise |p| is odd, and the generators are based on the
  306. theory of integral quaternions. Integral quaternions, for our purposes,
  307. are quadruples of the form
  308. $alpha=a_0+a_1i+a_2j+a_3k$, where $a_0$, $a_1$, $a_2$, and~$a_3$ are
  309. integers; we multiply them by using the associative but
  310. noncommutative multiplication rules $i^2=j^2=k^2=ijk=-1$. If we write
  311. $alpha=a+A$, where $a$ is the ``scalar'' $a_0$ and $A$ is the ``vector''
  312. $a_1i+a_2j+a_3k$, the product of quaternions $alpha=a+A$ and $beta=b+B$
  313. can be expressed as
  314. $$(a+A)(b+B)=ab-Acdot B+aB+bA+Atimes B,,$$
  315. where $Acdot B$ and $Atimes B$ are the usual dot product and cross
  316. product of vectors. The conjugate of $alpha=a+A$ is $overlinealpha=a-A$,
  317. and we have $alphaoverlinealpha=a_0^2+a_1^2+a_2^2+a_3^2$. This
  318. important quantity is called $N(alpha)$, the norm of $alpha$. It
  319. is not difficult to verify that $N(alphabeta)=N(alpha)N(beta)$,
  320. because of the basic identity
  321. $overline{mathstrutalphabeta}=overline{mathstrutbeta}
  322. ,overline{mathstrutalpha}$ and the fact that
  323. $alpha x=xalpha$ when $x$ is scalar.
  324. Integral quaternions have a beautiful theory; for example, there is a
  325. nice variant of Euclid's algorithm by which we can compute the greatest common
  326. left divisor of any two integral quaternions having odd norm. This algorithm
  327. makes it possible to prove that integral quaternions whose coefficients are
  328. relatively prime can be canonically factored into quaternions whose norm is
  329. prime. However, the details of that theory are beyond the scope of this
  330. documentation. It will suffice for our purposes
  331. to observe that we can use quaternions to define the finite groups
  332. $PSL(2,{bf F}_q)$ and $PGL(2,{bf F}_q)$ in a different way from the
  333. definitions given earlier: Suppose
  334. we consider two quaternions to be equivalent if
  335. one is a nonzero scalar multiple of the other,
  336. modulo~$q$. Thus, for example, if $q=3$ we consider $1+4i-j$ to
  337. be equivalent to $1+i+2j$, and also equivalent to $2+2i+j$.
  338. It turns out that there are exactly $(q+1)q(q-1)$ such equivalence classes,
  339. when we omit quaternions whose norm is a multiple of~$q$;
  340. and they form a group under quaternion multiplication that is the same as the
  341. projective group of $2times2$ matrices under matrix multiplication,
  342. modulo~|q|. One way to prove this
  343. is by means of the one-to-one correspondence
  344. $$a_0+a_1i+a_2j+a_3k;longleftrightarrow;
  345.   left(matrix{a_0+a_1g+a_3h&a_2+a_3g-a_1hcr
  346.                -a_2+a_3g-a_1h&a_0-a_1g-a_3hcr}right),,$$
  347. where $g$ and $h$ are integers with $g^2+h^2=-1$ (mod~|q|).
  348. Jacobi proved that the number of ways to represent
  349. @^Jacobi, Carl Gustav Jacob@>
  350. any odd number |p| as a sum of four squares $a_0^2+a_1^2+a_2^2+a_3^2$
  351. is 8 times the sum of divisors of~|p|. [This fact appears in the
  352. concluding sentence of his monumental work {sl Fundamenta Nova
  353. Theoriae Functionum Ellipticorum}, K"onigsberg, 1829.]
  354. In particular, when |p| is prime,
  355. the number of such representations is $8(p+1)$; in other words, there are
  356. exactly $8(p+1)$ quaternions $alpha=a_0+a_1i+a_2j+a_3k$ with $N(alpha)=p$.
  357. These quaternions form |p+1| equivalence classes under multiplication
  358. by the eight ``unit quaternions'' ${pm1,pm i,pm j,pm k}$. We will
  359. select one element from each equivalence class, and the resulting |p+1|
  360. quaternions will correspond to |p+1| matrices, which will generate the |p+1|
  361. arcs leading from each vertex in the graphs to be constructed.
  362. @<Type de...@>=
  363. typedef struct {
  364.   long a0,a1,a2,a3; /* coefficients of a quaternion */
  365.   unsigned long bar; /* the index of the inverse (conjugate) quaternion */
  366. } quaternion;
  367. @ A global variable |gen_count| will be declared below,
  368. indicating the number of generators found so far. When |p| isn't prime,
  369. we will find more than |p+1| solutions, so we allocate an extra slot in
  370. the |gen| table to hold a possible overflow entry.
  371. @<Compute |p+1| generators...@>=
  372. gen=gb_typed_alloc(p+2,quaternion,working_storage);
  373. if (gen==NULL) late_panic(no_room+2); /* not enough memory */
  374. gen_count=0;@+max_gen_count=p+1;
  375. if (p==2) @<Fill the |gen| table with special generators@>@;
  376. else @<Fill the |gen| table with representatives of all quaternions
  377.   having norm~|p|@>;
  378. if (gen_count!=max_gen_count) late_panic(bad_specs+7); /* |p| is not prime */
  379. @ @<Private...@>=
  380. static quaternion *gen; /* table of the |p+1| generators */
  381. @ As mentioned above, quaternions of norm |p| come in sets of 8,
  382. differing from each other only by unit multiples; we need to choose one
  383. of the~8. Suppose $a_0^2+a_1^2+a_2^2+a_3^2=p$.
  384. If $pbmod4=1$, exactly one of the $a$'s will be odd;
  385. so we call it $a_0$ and assign it a positive sign. When $pbmod4=3$, exactly
  386. one of the $a$'s will be even; we call it $a_0$, and if it is nonzero we
  387. make it positive. If $a_0=0$, we make sure that one of the
  388. others---say the rightmost appearance of the largest one---is positive.
  389. In this way we obtain a unique representative from each set of 8 equivalent
  390. quaternions.
  391. For example, the four quaternions of norm 3 are $nullpm ipm j+k$; the six
  392. of norm~5 are $1pm2i$, $1pm2j$, $1pm2k$.
  393. In the program here we generate solutions to $a^2+b^2+c^2+d^2=p$ when
  394. $anot=b=c=d$ (mod~2) and $ble cle d$. The variables |aa|, |bb|, and |cc|
  395. hold the respective values $p-a^2-b^2-c^2-d^2$, $p-a^2-3b^2$, and
  396. $p-a^2-2c^2$. The |for| statements use the fact that $a^2$ increases
  397. by $4(a+1)$ when $a$ increases by~2.
  398. @<Fill the |gen| table with representatives...@>=
  399. {@+long sa,sb; /* $p-a^2$, $p-a^2-b^2$ */
  400.   long pp=(p>>1)&1; /* 0 if $pbmod4=1$,  1 if $pbmod4=3$ */
  401.   for (a=1-pp,sa=p-a;sa>0;sa-=(a+1)<<2,a+=2)
  402.     for (b=pp,sb=sa-b,bb=sb-b-b;bb>=0;bb-=12*(b+1),sb-=(b+1)<<2,b+=2)
  403.       for (c=b,cc=bb;cc>=0;cc-=(c+1)<<3,c+=2)
  404.         for (d=c,aa=cc;aa>=0;aa-=(d+1)<<2,d+=2)
  405.           if (aa==0) @<Deposit the quaternions associated with $a+bi+cj+dk$@>;
  406.   @<Change the |gen| table to matrix format@>;
  407. }
  408. @ If |a>0| and |0<b<c<d|, we obtain 48 different classes of quaternions
  409. having the same norm by permuting ${b,c,d}$ in six ways and attaching
  410. signs to each permutation in eight ways. This happens, for example,
  411. when $p=71$ and $(a,b,c,d)=(6,1,3,5)$. Fewer quaternions arise when
  412. |a=0| or |0=b| or |b=c| or |c=d|.
  413. The inverse of the matrix corresponding to a quaternion is the matrix
  414. corresponding to the conjugate quaternion. Therefore a generating
  415. matrix $pi_k$ will be its own inverse if and only if it comes from
  416. a quaternion with |a=0|.
  417. It is convenient to have a subroutine that deposits a new quaternion
  418. and its conjugate into the table of generators.
  419. @<Private...@>=
  420. static unsigned long gen_count; /* the next available quaternion slot */
  421. static unsigned long max_gen_count; /* $p+1$, stored as a global variable */
  422. static void deposit(a,b,c,d)
  423.   long a,b,c,d; /* a solution to $a^2+b^2+c^2+d^2=p$ */
  424. {
  425.   if (gen_count>=max_gen_count) /* oops, we already found |p+1| solutions */
  426.     gen_count=max_gen_count+1; /* this will happen only if |p| isn't prime */
  427.   else {
  428.     gen[gen_count].a0=gen[gen_count+1].a0=a;
  429.     gen[gen_count].a1=b;@+gen[gen_count+1].a1=-b;
  430.     gen[gen_count].a2=c;@+gen[gen_count+1].a2=-c;
  431.     gen[gen_count].a3=d;@+gen[gen_count+1].a3=-d;
  432.     if (a) {
  433.       gen[gen_count].bar=gen_count+1;
  434.       gen[gen_count+1].bar=gen_count;
  435.       gen_count+=2;
  436.     }@+else {
  437.       gen[gen_count].bar=gen_count;
  438.       gen_count++;
  439.     }
  440.   }
  441. }
  442. @ @<Deposit...@>=
  443. {
  444.   deposit(a,b,c,d);
  445.   if (b) {
  446.     deposit(a,-b,c,d);@+deposit(a,-b,-c,d);
  447.   }
  448.   if (c) deposit(a,b,-c,d);
  449.   if (b<c) {
  450.     deposit(a,c,b,d);@+deposit(a,-c,b,d);@+deposit(a,c,d,b);@+
  451.         deposit(a,-c,d,b);
  452.     if (b) {
  453.       deposit(a,c,-b,d);@+deposit(a,-c,-b,d);@+deposit(a,c,d,-b);@+
  454.         deposit(a,-c,d,-b);
  455.     }
  456.   }
  457.   if (c<d) {
  458.     deposit(a,b,d,c);@+deposit(a,d,b,c);
  459.     if (b) {
  460.       deposit(a,-b,d,c);@+deposit(a,-b,d,-c);@+deposit(a,d,-b,c);@+
  461.         deposit(a,d,-b,-c);
  462.     }
  463.     if (c) {
  464.       deposit(a,b,d,-c);@+deposit(a,d,b,-c);
  465.     }
  466.     if (b<c) {
  467.       deposit(a,d,c,b);@+deposit(a,d,-c,b);
  468.       if (b) {
  469.         deposit(a,d,c,-b);@+deposit(a,d,-c,-b);
  470.       }
  471.     }
  472.   }
  473. }
  474. @ Once we've found the generators in quaternion form, we want to
  475. convert them to $2times2$ matrices, using the correspondence mentioned
  476. earlier:
  477. $$a_0+a_1i+a_2j+a_3k;longleftrightarrow;
  478.   left(matrix{a_0+a_1g+a_3h&a_2+a_3g-a_1hcr
  479.                -a_2+a_3g-a_1h&a_0-a_1g-a_3hcr}right),,$$
  480. where $g$ and $h$ are integers with $g^2+h^2=-1$ (mod~|q|).
  481. Appropriate values for $g$ and~$h$ can always be found by the formulas
  482. $$g=sqrt{mathstrut k}qquadhbox{and}qquad h=sqrt{mathstrut q-1-k},$$
  483. where $k$ is the largest quadratic residue modulo~|q|. For if $q-1$ is
  484. not a quadratic residue, and if $k+1$ isn't a residue either, then
  485. $q-1-k$ must be a quadratic residue because it is congruent to the
  486. product $(q-1)(k+1)$ of nonresidues. (We will have |h=0| if and
  487. only if $qbmod4=1$; |h=1| if and only if $qbmod8=3$; $h=sqrt{mathstrut2}$
  488. if and only if $qbmod24=7$ or 15; etc.)
  489. @<Change the |gen| table to matrix format@>=
  490. {@+register long g,h;
  491.   long a00,a01,a10,a11; /* entries of $2times2$ matrix */
  492.   for (k=q-1;q_sqrt[k]<0;k--) ; /* find the largest quadratic residue, |k| */
  493.   g=q_sqrt[k];@+h=q_sqrt[q-1-k];
  494.   for (k=p;k>=0;k--) {
  495.     a00=(gen[k].a0+g*gen[k].a1+h*gen[k].a3)%q;
  496.     if (a00<0) a00+=q;
  497.     a11=(gen[k].a0-g*gen[k].a1-h*gen[k].a3)%q;
  498.     if (a11<0) a11+=q;
  499.     a01=(gen[k].a2+g*gen[k].a3-h*gen[k].a1)%q;
  500.     if (a01<0) a01+=q;
  501.     a10=(-gen[k].a2+g*gen[k].a3-h*gen[k].a1)%q;
  502.     if (a10<0) a10+=q;
  503.     gen[k].a0=a00;@+gen[k].a1=a01;@+gen[k].a2=a10;@+gen[k].a3=a11;
  504.   }
  505. }
  506. @ When |p=2|, the following three appropriate generating matrices
  507. have been found by Patrick~Chiu:
  508. @^Chiu, Patrick@>
  509. $$left(matrix{1&0cr 0&-1cr}right),,qquad
  510.   left(matrix{2+s&tcr t&2-scr}right),,qquadhbox{and}qquad
  511.   left(matrix{2-s&-tcr-t&2+scr}right),,$$
  512. where $s^2=-2$ and $t^2=-26$ (mod~$q$). The determinants of
  513. these matrices are respectively $-1$, $32$, and~$32$; the product of
  514. the second and third matrices is 32 times the identity matrix. Notice that when
  515. 2 is a quadratic residue (this happens when $q=8k+1$), the determinants
  516. are all quadratic residues, so we get a graph of type~3.
  517. When 2 is a quadratic nonresidue (which happens when $q=8k+3$),
  518. the determinants are all nonresidues, so we get a graph of type~4.
  519. @<Fill the |gen| table with special generators@>=
  520. {@+long s=q_sqrt[q-2], t=(q_sqrt[13%q]*s)%q;
  521.   gen[0].a0=1;@+gen[0].a1=gen[0].a2=0;@+gen[0].a3=q-1;@+gen[0].bar=0;
  522.   gen[1].a0=gen[2].a3=(2+s)%q;
  523.   gen[1].a1=gen[1].a2=t;
  524.   gen[2].a1=gen[2].a2=q-t;
  525.   gen[1].a3=gen[2].a0=(q+2-s)%q;
  526.   gen[1].bar=2;@+gen[2].bar=1;
  527.   gen_count=3;
  528. }
  529. @* Constructing the edges. The remaining task is to use the permutations
  530. defined by the |gen| table to create the arcs of the graph and
  531. their inverses.
  532. The |ref| fields in each arc will refer to the permutation leading to the
  533. arc. In most cases each vertex |v| will have degree exactly |p+1|, and the
  534. edges emanating from it will appear in a linked list having
  535. the respective |ref| fields 0,~1, dots,~|p| in order. However,
  536. if |reduce| is nonzero, self-loops and multiple edges will be eliminated,
  537. so the degree might be less than |p+1|; in this case the |ref| fields
  538. will still be in ascending order, but some generators won't be referenced.
  539. There is a subtle case where |reduce=0| but the degree of a vertex might
  540. actually be greater than |p+1|.
  541. We want the graph |g| generated by |raman| to satisfy the
  542. conventions for undirected graphs stated in {sc GB_,GRAPH}; therefore,
  543. if any of the generating permutations has a fixed point, we will create
  544. two arcs for that fixed point, and the corresponding vertex |v| will
  545. have an edge running to itself. Since each edge consists of two arcs, such
  546. an edge will produce two consecutive entries in the list |v->arcs|.
  547. If the generating permutation happens to be its own inverse,
  548. there will be two consecutive entries with the same |ref| field;
  549. this means there will be more than |p+1| entries in |v->arcs|,
  550. and the total number of arcs |g->m| will exceed |(p+1)n|.
  551. Self-inverse generating permutations arise only when |p=2| or
  552. when $p$ is expressible as a sum of three odd squares (hence
  553. $pbmod8=3$); and such permutations will have fixed points only when
  554. |type<3|. Therefore this anomaly does not arise often. But it does
  555. occur, for example, in the smallest graph generated by |raman|, namely
  556. when |p=2|, |q=3|, and |type=1|, when there are 4~vertices and 14 (not~12)
  557. arcs.
  558. @d ref a.I /* the |ref| field of an arc refers to its permutation number */
  559. @<Append the edges@>=
  560. for (k=p;k>=0;k--) {@+long kk;
  561.   if ((kk=gen[k].bar)<=k) /* we assume that |kk=k| or |kk=k-1| */
  562.     for (v=new_graph->vertices;v<new_graph->vertices+n;v++) {
  563.       register Vertex* u;
  564.       @<Compute the image, |u|, of |v|
  565.             under the permutation defined by |gen[k]|@>;
  566.       if (u==v) {
  567.         if (!reduce) {
  568.           gb_new_edge(v,v,1L);
  569.           v->arcs->ref=kk;@+(v->arcs+1)->ref=k;
  570.                /* see the remarks above regarding the case |kk=k| */
  571.         }
  572.       }@+else {@+register Arc* ap;
  573.         if (u->arcs && u->arcs->ref==kk)
  574.           continue; /* |kk=k| and we've already done this two-cycle */
  575.         else if (reduce)
  576.           for (ap=v->arcs;ap;ap=ap->next)
  577.             if (ap->tip==u) goto done;
  578.                 /* there's already an edge between |u| and |v| */
  579.         gb_new_edge(v,u,1L);
  580.         v->arcs->ref=k;@+u->arcs->ref=kk;
  581.         if ((ap=v->arcs->next)!=NULL && ap->ref==kk) {
  582.           v->arcs->next=ap->next;@+ap->next=v->arcs;@+v->arcs=ap;
  583.         } /* now the |v->arcs| list has |ref| fields in order again */
  584.        done:;
  585.       }
  586.     }
  587. }
  588. @ For graphs of types 3 and 4, our job is to compute a $2times2$ matrix
  589. product, reduce it modulo~|q|, and find the appropriate
  590. equivalence class~|u|.
  591. @<Compute the image, |u|, of |v| under the permutation defined by |gen[k]|@>=
  592. if (type<3) @<Compute the image, |u|, of |v| under the linear fractional
  593.   transformation defined by |gen[k]|@>@;
  594. else {@+long a00=gen[k].a0,a01=gen[k].a1,a10=gen[k].a2,a11=gen[k].a3;
  595.   a=v->x.I;@+b=v->y.I;
  596.   if (v->z.I==q) c=0,d=1;
  597.   else c=1,d=v->z.I;
  598.   @<Compute the matrix product |(aa,bb;cc,dd)=(a,b;c,d)*(a00,a01;a10,a11)|@>;
  599.   a=(cc? q_inv[cc]: q_inv[dd]); /* now |a| is a normalization factor */
  600.   d=(a*dd)%q;@+c=(a*cc)%q;@+b=(a*bb)%q;@+a=(a*aa)%q;
  601.   @<Set |u| to the vertex whose label is |(a,b;c,d)|@>;
  602. }
  603. @ @<Compute the matrix product...@>=
  604. aa=(a*a00+b*a10)%q;
  605. bb=(a*a01+b*a11)%q;
  606. cc=(c*a00+d*a10)%q;
  607. dd=(c*a01+d*a11)%q;
  608. @ @<Set |u|...@>=
  609. if (c==0) d=q,aa=a;
  610. else {
  611.   aa=(a*d-b)%q;
  612.   if (aa<0) aa+=q;
  613.   b=a;
  614. } /* now |aa| is the determinant of the matrix */
  615. u=new_graph->vertices+((d*q+b)*n_factor+(type==3? q_sqrt[aa]: aa)-1);
  616. @* Linear fractional transformations. Given a nonsingular $2times2$ matrix
  617. $bigl({a,batop c,d}bigr)$, the linear fractional transformation
  618. $zmapsto(az+b)/(cz+d)$ is defined modulo~$q$ by the
  619. following subroutine. We assume that the matrix $bigl({a,batop c,d}bigr)$
  620. appears in row |k| of the |gen| table.
  621. @<Private...@>=
  622. static long lin_frac(a,k)
  623.   long a; /* the number being transformed; $q$ represents $infty$ */
  624.   long k; /* index into |gen| table */
  625. {@+register long q=q_inv[0]; /* the modulus */
  626.   long a00=gen[k].a0, a01=gen[k].a1, a10=gen[k].a2,
  627.     a11=gen[k].a3; /* the coefficients */
  628.   register long num, den; /* numerator and denominator */
  629.   if (a==q) num=a00, den=a10;
  630.   else num=(a00*a+a01)%q, den=(a10*a+a11)%q;
  631.   if (den==0) return q;
  632.   else return (num*q_inv[den])%q;
  633. }
  634. @ We are computing the same values of |lin_frac| over and over again in type~2
  635. graphs, but the author was too lazy to optimize this.
  636. @<Compute the image, |u|, of |v| under the linear fractional
  637.   transformation defined by |gen[k]|@>=
  638. if (type==1) u=new_graph->vertices+lin_frac(v->x.I,k);
  639. else {
  640.   a=lin_frac(v->x.I,k);@+aa=lin_frac(v->y.I,k);
  641.   u=new_graph->vertices+(a<aa? (a*(2*q-1-a))/2+aa-1:
  642.                                (aa*(2*q-1-aa))/2+a-1);
  643. }
  644. @* Index. Here is a list that shows where the identifiers of this program are
  645. defined and used.