statlib.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:20k
源码类别:

数学计算

开发平台:

Unix_Linux

  1. /* statlib.c -- Statistical functions for testing the randomness of
  2.    number sequences. */
  3. /*
  4. Copyright 1999, 2000 Free Software Foundation, Inc.
  5. This file is part of the GNU MP Library.
  6. The GNU MP Library is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU Lesser General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or (at your
  9. option) any later version.
  10. The GNU MP Library is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  13. License for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  16. /* The theories for these functions are taken from D. Knuth's "The Art
  17. of Computer Programming: Volume 2, Seminumerical Algorithms", Third
  18. Edition, Addison Wesley, 1998. */
  19. /* Implementation notes.
  20. The Kolmogorov-Smirnov test.
  21. Eq. (13) in Knuth, p. 50, says that if X1, X2, ..., Xn are independent
  22. observations arranged into ascending order
  23. Kp = sqr(n) * max(j/n - F(Xj)) for all 1<=j<=n
  24. Km = sqr(n) * max(F(Xj) - (j-1)/n)) for all 1<=j<=n
  25. where F(x) = Pr(X <= x) = probability that (X <= x), which for a
  26. uniformly distributed random real number between zero and one is
  27. exactly the number itself (x).
  28. The answer to exercise 23 gives the following implementation, which
  29. doesn't need the observations to be sorted in ascending order:
  30. for (k = 0; k < m; k++)
  31. a[k] = 1.0
  32. b[k] = 0.0
  33. c[k] = 0
  34. for (each observation Xj)
  35. Y = F(Xj)
  36. k = floor (m * Y)
  37. a[k] = min (a[k], Y)
  38. b[k] = max (b[k], Y)
  39. c[k] += 1
  40. j = 0
  41. rp = rm = 0
  42. for (k = 0; k < m; k++)
  43. if (c[k] > 0)
  44. rm = max (rm, a[k] - j/n)
  45. j += c[k]
  46. rp = max (rp, j/n - b[k])
  47. Kp = sqr (n) * rp
  48. Km = sqr (n) * rm
  49. */
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <math.h>
  53. #include "gmp.h"
  54. #include "gmpstat.h"
  55. /* ks (Kp, Km, X, P, n) -- Perform a Kolmogorov-Smirnov test on the N
  56.    real numbers between zero and one in vector X.  P is the
  57.    distribution function, called for each entry in X, which should
  58.    calculate the probability of X being greater than or equal to any
  59.    number in the sequence.  (For a uniformly distributed sequence of
  60.    real numbers between zero and one, this is simply equal to X.)  The
  61.    result is put in Kp and Km.  */
  62. void
  63. ks (mpf_t Kp,
  64.     mpf_t Km,
  65.     mpf_t X[],
  66.     void (P) (mpf_t, mpf_t),
  67.     unsigned long int n)
  68. {
  69.   mpf_t Kt; /* temp */
  70.   mpf_t f_x;
  71.   mpf_t f_j; /* j */
  72.   mpf_t f_jnq; /* j/n or (j-1)/n */
  73.   unsigned long int j;
  74.   /* Sort the vector in ascending order. */
  75.   qsort (X, n, sizeof (__mpf_struct), mpf_cmp);
  76.   /* K-S test. */
  77.   /* Kp = sqr(n) * max(j/n - F(Xj)) for all 1<=j<=n
  78. Km = sqr(n) * max(F(Xj) - (j-1)/n)) for all 1<=j<=n
  79.   */
  80.   mpf_init (Kt); mpf_init (f_x); mpf_init (f_j); mpf_init (f_jnq);
  81.   mpf_set_ui (Kp, 0);  mpf_set_ui (Km, 0);
  82.   for (j = 1; j <= n; j++)
  83.     {
  84.       P (f_x, X[j-1]);
  85.       mpf_set_ui (f_j, j);
  86.       mpf_div_ui (f_jnq, f_j, n);
  87.       mpf_sub (Kt, f_jnq, f_x);
  88.       if (mpf_cmp (Kt, Kp) > 0)
  89. mpf_set (Kp, Kt);
  90.       if (g_debug > DEBUG_2)
  91. {
  92.   printf ("j=%lu ", j);
  93.   printf ("P()="); mpf_out_str (stdout, 10, 2, f_x); printf ("t");
  94.   printf ("jnq="); mpf_out_str (stdout, 10, 2, f_jnq); printf (" ");
  95.   printf ("diff="); mpf_out_str (stdout, 10, 2, Kt); printf (" ");
  96.   printf ("Kp="); mpf_out_str (stdout, 10, 2, Kp); printf ("t");
  97. }
  98.       mpf_sub_ui (f_j, f_j, 1);
  99.       mpf_div_ui (f_jnq, f_j, n);
  100.       mpf_sub (Kt, f_x, f_jnq);
  101.       if (mpf_cmp (Kt, Km) > 0)
  102. mpf_set (Km, Kt);
  103.       if (g_debug > DEBUG_2)
  104. {
  105.   printf ("jnq="); mpf_out_str (stdout, 10, 2, f_jnq); printf (" ");
  106.   printf ("diff="); mpf_out_str (stdout, 10, 2, Kt); printf (" ");
  107.   printf ("Km="); mpf_out_str (stdout, 10, 2, Km); printf (" ");
  108.   printf ("n");
  109. }
  110.     }
  111.   mpf_sqrt_ui (Kt, n);
  112.   mpf_mul (Kp, Kp, Kt);
  113.   mpf_mul (Km, Km, Kt);
  114.   mpf_clear (Kt); mpf_clear (f_x); mpf_clear (f_j); mpf_clear (f_jnq);
  115. }
  116. /* ks_table(val, n) -- calculate probability for Kp/Km less than or
  117.    equal to VAL with N observations.  See [Knuth section 3.3.1] */
  118. void
  119. ks_table (mpf_t p, mpf_t val, const unsigned int n)
  120. {
  121.   /* We use Eq. (27), Knuth p.58, skipping O(1/n) for simplicity.
  122.      This shortcut will result in too high probabilities, especially
  123.      when n is small.
  124.      Pr(Kp(n) <= s) = 1 - pow(e, -2*s^2) * (1 - 2/3*s/sqrt(n) + O(1/n)) */
  125.   /* We have 's' in variable VAL and store the result in P. */
  126.   mpf_t t1, t2;
  127.   mpf_init (t1); mpf_init (t2);
  128.   /* t1 = 1 - 2/3 * s/sqrt(n) */
  129.   mpf_sqrt_ui (t1, n);
  130.   mpf_div (t1, val, t1);
  131.   mpf_mul_ui (t1, t1, 2);
  132.   mpf_div_ui (t1, t1, 3);
  133.   mpf_ui_sub (t1, 1, t1);
  134.   /* t2 = pow(e, -2*s^2) */
  135. #ifndef OLDGMP
  136.   mpf_pow_ui (t2, val, 2); /* t2 = s^2 */
  137.   mpf_set_d (t2, exp (-(2.0 * mpf_get_d (t2))));
  138. #else
  139.   /* hmmm, gmp doesn't have pow() for floats.  use doubles. */
  140.   mpf_set_d (t2, pow (M_E, -(2 * pow (mpf_get_d (val), 2))));
  141. #endif
  142.   /* p = 1 - t1 * t2 */
  143.   mpf_mul (t1, t1, t2);
  144.   mpf_ui_sub (p, 1, t1);
  145.   mpf_clear (t1); mpf_clear (t2);
  146. }
  147. static double x2_table_X[][7] = {
  148.   { -2.33, -1.64, -.674, 0.0, 0.674, 1.64, 2.33 }, /* x */
  149.   { 5.4289, 2.6896, .454276, 0.0, .454276, 2.6896, 5.4289} /* x^2 */
  150. };
  151. #define _2D3 ((double) .6666666666)
  152. /* x2_table (t, v, n) -- return chi-square table row for V in T[]. */
  153. void
  154. x2_table (double t[],
  155.   unsigned int v)
  156. {
  157.   int f;
  158.   /* FIXME: Do a table lookup for v <= 30 since the following formula
  159.      [Knuth, vol 2, 3.3.1] is only good for v > 30. */
  160.   /* value = v + sqrt(2*v) * X[p] + (2/3) * X[p]^2 - 2/3 + O(1/sqrt(t) */
  161.   /* NOTE: The O() term is ignored for simplicity. */
  162.   for (f = 0; f < 7; f++)
  163.       t[f] =
  164. v +
  165. sqrt (2 * v) * x2_table_X[0][f] +
  166. _2D3 * x2_table_X[1][f] - _2D3;
  167. }
  168. /* P(p, x) -- Distribution function.  Calculate the probability of X
  169. being greater than or equal to any number in the sequence.  For a
  170. random real number between zero and one given by a uniformly
  171. distributed random number generator, this is simply equal to X. */
  172. static void
  173. P (mpf_t p, mpf_t x)
  174. {
  175.   mpf_set (p, x);
  176. }
  177. /* mpf_freqt() -- Frequency test using KS on N real numbers between zero
  178.    and one.  See [Knuth vol 2, p.61]. */
  179. void
  180. mpf_freqt (mpf_t Kp,
  181.    mpf_t Km,
  182.    mpf_t X[],
  183.    const unsigned long int n)
  184. {
  185.   ks (Kp, Km, X, P, n);
  186. }
  187. /* The Chi-square test.  Eq. (8) in Knuth vol. 2 says that if Y[]
  188.    holds the observations and p[] is the probability for.. (to be
  189.    continued!)
  190.    V = 1/n * sum((s=1 to k) Y[s]^2 / p[s]) - n */
  191. void
  192. x2 (mpf_t V, /* result */
  193.     unsigned long int X[], /* data */
  194.     unsigned int k, /* #of categories */
  195.     void (P) (mpf_t, unsigned long int, void *), /* probability func */
  196.     void *x, /* extra user data passed to P() */
  197.     unsigned long int n) /* #of samples */
  198. {
  199.   unsigned int f;
  200.   mpf_t f_t, f_t2; /* temp floats */
  201.   mpf_init (f_t); mpf_init (f_t2);
  202.   mpf_set_ui (V, 0);
  203.   for (f = 0; f < k; f++)
  204.     {
  205.       if (g_debug > DEBUG_2)
  206. fprintf (stderr, "%u: P()=", f);
  207.       mpf_set_ui (f_t, X[f]);
  208.       mpf_mul (f_t, f_t, f_t); /* f_t = X[f]^2 */
  209.       P (f_t2, f, x); /* f_t2 = Pr(f) */
  210.       if (g_debug > DEBUG_2)
  211. mpf_out_str (stderr, 10, 2, f_t2);
  212.       mpf_div (f_t, f_t, f_t2);
  213.       mpf_add (V, V, f_t);
  214.       if (g_debug > DEBUG_2)
  215. {
  216.   fprintf (stderr, "tV=");
  217.   mpf_out_str (stderr, 10, 2, V);
  218.   fprintf (stderr, "t");
  219. }
  220.     }
  221.   if (g_debug > DEBUG_2)
  222.     fprintf (stderr, "n");
  223.   mpf_div_ui (V, V, n);
  224.   mpf_sub_ui (V, V, n);
  225.   mpf_clear (f_t); mpf_clear (f_t2);
  226. }
  227. /* Pzf(p, s, x) -- Probability for category S in mpz_freqt().  It's
  228.    1/d for all S.  X is a pointer to an unsigned int holding 'd'. */
  229. static void
  230. Pzf (mpf_t p, unsigned long int s, void *x)
  231. {
  232.   mpf_set_ui (p, 1);
  233.   mpf_div_ui (p, p, *((unsigned int *) x));
  234. }
  235. /* mpz_freqt(V, X, imax, n) -- Frequency test on integers.  [Knuth,
  236.    vol 2, 3.3.2].  Keep IMAX low on this one, since we loop from 0 to
  237.    IMAX.  128 or 256 could be nice.
  238.    X[] must not contain numbers outside the range 0 <= X <= IMAX.
  239.    Return value is number of observations actually used, after
  240.    discarding entries out of range.
  241.    Since X[] contains integers between zero and IMAX, inclusive, we
  242.    have IMAX+1 categories.
  243.    Note that N should be at least 5*IMAX.  Result is put in V and can
  244.    be compared to output from x2_table (v=IMAX). */
  245. unsigned long int
  246. mpz_freqt (mpf_t V,
  247.    mpz_t X[],
  248.    unsigned int imax,
  249.    const unsigned long int n)
  250. {
  251.   unsigned long int *v; /* result */
  252.   unsigned int f;
  253.   unsigned int d; /* number of categories = imax+1 */
  254.   unsigned int uitemp;
  255.   unsigned long int usedn;
  256.   d = imax + 1;
  257.   v = (unsigned long int *) calloc (imax + 1, sizeof (unsigned long int));
  258.   if (NULL == v)
  259.     {
  260.       fprintf (stderr, "mpz_freqt(): out of memoryn");
  261.       exit (1);
  262.     }
  263.   /* count */
  264.   usedn = n; /* actual number of observations */
  265.   for (f = 0; f < n; f++)
  266.     {
  267.       uitemp = mpz_get_ui(X[f]);
  268.       if (uitemp > imax) /* sanity check */
  269. {
  270.   if (g_debug)
  271.     fprintf (stderr, "mpz_freqt(): warning: input insanity: %u, "
  272.      "ignored.n", uitemp);
  273.   usedn--;
  274.   continue;
  275. }
  276.       v[uitemp]++;
  277.     }
  278.   if (g_debug > DEBUG_2)
  279.     {
  280.       fprintf (stderr, "counts:n");
  281.       for (f = 0; f <= imax; f++)
  282. fprintf (stderr, "%u:t%lun", f, v[f]);
  283.     }
  284.   /* chi-square with k=imax+1 and P(x)=1/(imax+1) for all x.*/
  285.   x2 (V, v, d, Pzf, (void *) &d, usedn);
  286.   free (v);
  287.   return (usedn);
  288. }
  289. /* debug dummy to drag in dump funcs */
  290. void
  291. foo_debug ()
  292. {
  293.   if (0)
  294.     {
  295.       mpf_dump (0);
  296. #ifndef OLDGMP
  297.       mpz_dump (0);
  298. #endif
  299.     }
  300. }
  301. /* merit (rop, t, v, m) -- calculate merit for spectral test result in
  302.    dimension T, see Knuth p. 105.  BUGS: Only valid for 2 <= T <=
  303.    6. */
  304. void
  305. merit (mpf_t rop, unsigned int t, mpf_t v, mpz_t m)
  306. {
  307.   int f;
  308.   mpf_t f_m, f_const, f_pi;
  309.   mpf_init (f_m);
  310.   mpf_set_z (f_m, m);
  311.   mpf_init_set_d (f_const, M_PI);
  312.   mpf_init_set_d (f_pi, M_PI);
  313.   switch (t)
  314.     {
  315.     case 2: /* PI */
  316.       break;
  317.     case 3: /* PI * 4/3 */
  318.       mpf_mul_ui (f_const, f_const, 4);
  319.       mpf_div_ui (f_const, f_const, 3);
  320.       break;
  321.     case 4: /* PI^2 * 1/2 */
  322.       mpf_mul (f_const, f_const, f_pi);
  323.       mpf_div_ui (f_const, f_const, 2);
  324.       break;
  325.     case 5: /* PI^2 * 8/15 */
  326.       mpf_mul (f_const, f_const, f_pi);
  327.       mpf_mul_ui (f_const, f_const, 8);
  328.       mpf_div_ui (f_const, f_const, 15);
  329.       break;
  330.     case 6: /* PI^3 * 1/6 */
  331.       mpf_mul (f_const, f_const, f_pi);
  332.       mpf_mul (f_const, f_const, f_pi);
  333.       mpf_div_ui (f_const, f_const, 6);
  334.       break;
  335.     default:
  336.       fprintf (stderr,
  337.        "spect (merit): can't calculate merit for dimensions > 6n");
  338.       mpf_set_ui (f_const, 0);
  339.       break;
  340.     }
  341.   /* rop = v^t */
  342.   mpf_set (rop, v);
  343.   for (f = 1; f < t; f++)
  344.     mpf_mul (rop, rop, v);
  345.   mpf_mul (rop, rop, f_const);
  346.   mpf_div (rop, rop, f_m);
  347.   mpf_clear (f_m);
  348.   mpf_clear (f_const);
  349.   mpf_clear (f_pi);
  350. }
  351. double
  352. merit_u (unsigned int t, mpf_t v, mpz_t m)
  353. {
  354.   mpf_t rop;
  355.   double res;
  356.   mpf_init (rop);
  357.   merit (rop, t, v, m);
  358.   res = mpf_get_d (rop);
  359.   mpf_clear (rop);
  360.   return res;
  361. }
  362. /* f_floor (rop, op) -- Set rop = floor (op). */
  363. void
  364. f_floor (mpf_t rop, mpf_t op)
  365. {
  366.   mpz_t z;
  367.   mpz_init (z);
  368.   /* No mpf_floor().  Convert to mpz and back. */
  369.   mpz_set_f (z, op);
  370.   mpf_set_z (rop, z);
  371.   mpz_clear (z);
  372. }
  373. /* vz_dot (rop, v1, v2, nelem) -- compute dot product of z-vectors V1,
  374.    V2.  N is number of elements in vectors V1 and V2. */
  375. void
  376. vz_dot (mpz_t rop, mpz_t V1[], mpz_t V2[], unsigned int n)
  377. {
  378.   mpz_t t;
  379.   mpz_init (t);
  380.   mpz_set_ui (rop, 0);
  381.   while (n--)
  382.     {
  383.       mpz_mul (t, V1[n], V2[n]);
  384.       mpz_add (rop, rop, t);
  385.     }
  386.   mpz_clear (t);
  387. }
  388. void
  389. spectral_test (mpf_t rop[], unsigned int T, mpz_t a, mpz_t m)
  390. {
  391.   /* Knuth "Seminumerical Algorithms, Third Edition", section 3.3.4
  392.      (pp. 101-103). */
  393.   /* v[t] = min { sqrt (x[1]^2 + ... + x[t]^2) |
  394.      x[1] + a*x[2] + ... + pow (a, t-1) * x[t] is congruent to 0 (mod m) } */
  395.   /* Variables. */
  396.   unsigned int ui_t;
  397.   unsigned int ui_i, ui_j, ui_k, ui_l;
  398.   mpf_t f_tmp1, f_tmp2;
  399.   mpz_t tmp1, tmp2, tmp3;
  400.   mpz_t U[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
  401.     V[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
  402.     X[GMP_SPECT_MAXT],
  403.     Y[GMP_SPECT_MAXT],
  404.     Z[GMP_SPECT_MAXT];
  405.   mpz_t h, hp, r, s, p, pp, q, u, v;
  406.   /* GMP inits. */
  407.   mpf_init (f_tmp1);
  408.   mpf_init (f_tmp2);
  409.   for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++)
  410.     {
  411.       for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++)
  412. {
  413.   mpz_init_set_ui (U[ui_i][ui_j], 0);
  414.   mpz_init_set_ui (V[ui_i][ui_j], 0);
  415. }
  416.       mpz_init_set_ui (X[ui_i], 0);
  417.       mpz_init_set_ui (Y[ui_i], 0);
  418.       mpz_init (Z[ui_i]);
  419.     }
  420.   mpz_init (tmp1);
  421.   mpz_init (tmp2);
  422.   mpz_init (tmp3);
  423.   mpz_init (h);
  424.   mpz_init (hp);
  425.   mpz_init (r);
  426.   mpz_init (s);
  427.   mpz_init (p);
  428.   mpz_init (pp);
  429.   mpz_init (q);
  430.   mpz_init (u);
  431.   mpz_init (v);
  432.   /* Implementation inits. */
  433.   if (T > GMP_SPECT_MAXT)
  434.     T = GMP_SPECT_MAXT; /* FIXME: Lazy. */
  435.   /* S1 [Initialize.] */
  436.   ui_t = 2 - 1; /* NOTE: `t' in description == ui_t + 1
  437.    for easy indexing */
  438.   mpz_set (h, a);
  439.   mpz_set (hp, m);
  440.   mpz_set_ui (p, 1);
  441.   mpz_set_ui (pp, 0);
  442.   mpz_set (r, a);
  443.   mpz_pow_ui (s, a, 2);
  444.   mpz_add_ui (s, s, 1); /* s = 1 + a^2 */
  445.   /* S2 [Euclidean step.] */
  446.   while (1)
  447.     {
  448.       if (g_debug > DEBUG_1)
  449. {
  450.   mpz_mul (tmp1, h, pp);
  451.   mpz_mul (tmp2, hp, p);
  452.   mpz_sub (tmp1, tmp1, tmp2);
  453.   if (mpz_cmpabs (m, tmp1))
  454.     {
  455.       printf ("***BUG***: h*pp - hp*p = ");
  456.       mpz_out_str (stdout, 10, tmp1);
  457.       printf ("n");
  458.     }
  459. }
  460.       if (g_debug > DEBUG_2)
  461. {
  462.   printf ("hp = ");
  463.   mpz_out_str (stdout, 10, hp);
  464.   printf ("nh = ");
  465.   mpz_out_str (stdout, 10, h);
  466.   printf ("n");
  467.   fflush (stdout);
  468. }
  469.       if (mpz_sgn (h))
  470. mpz_tdiv_q (q, hp, h); /* q = floor(hp/h) */
  471.       else
  472. mpz_set_ui (q, 1);
  473.       if (g_debug > DEBUG_2)
  474. {
  475.   printf ("q = ");
  476.   mpz_out_str (stdout, 10, q);
  477.   printf ("n");
  478.   fflush (stdout);
  479. }
  480.       mpz_mul (tmp1, q, h);
  481.       mpz_sub (u, hp, tmp1); /* u = hp - q*h */
  482.       mpz_mul (tmp1, q, p);
  483.       mpz_sub (v, pp, tmp1); /* v = pp - q*p */
  484.       mpz_pow_ui (tmp1, u, 2);
  485.       mpz_pow_ui (tmp2, v, 2);
  486.       mpz_add (tmp1, tmp1, tmp2);
  487.       if (mpz_cmp (tmp1, s) < 0)
  488. {
  489.   mpz_set (s, tmp1); /* s = u^2 + v^2 */
  490.   mpz_set (hp, h); /* hp = h */
  491.   mpz_set (h, u); /* h = u */
  492.   mpz_set (pp, p); /* pp = p */
  493.   mpz_set (p, v); /* p = v */
  494. }
  495.       else
  496. break;
  497.     }
  498.   /* S3 [Compute v2.] */
  499.   mpz_sub (u, u, h);
  500.   mpz_sub (v, v, p);
  501.   mpz_pow_ui (tmp1, u, 2);
  502.   mpz_pow_ui (tmp2, v, 2);
  503.   mpz_add (tmp1, tmp1, tmp2);
  504.   if (mpz_cmp (tmp1, s) < 0)
  505.     {
  506.       mpz_set (s, tmp1); /* s = u^2 + v^2 */
  507.       mpz_set (hp, u);
  508.       mpz_set (pp, v);
  509.     }
  510.   mpf_set_z (f_tmp1, s);
  511.   mpf_sqrt (rop[ui_t - 1], f_tmp1);
  512.   /* S4 [Advance t.] */
  513.   mpz_neg (U[0][0], h);
  514.   mpz_set (U[0][1], p);
  515.   mpz_neg (U[1][0], hp);
  516.   mpz_set (U[1][1], pp);
  517.   mpz_set (V[0][0], pp);
  518.   mpz_set (V[0][1], hp);
  519.   mpz_neg (V[1][0], p);
  520.   mpz_neg (V[1][1], h);
  521.   if (mpz_cmp_ui (pp, 0) > 0)
  522.     {
  523.       mpz_neg (V[0][0], V[0][0]);
  524.       mpz_neg (V[0][1], V[0][1]);
  525.       mpz_neg (V[1][0], V[1][0]);
  526.       mpz_neg (V[1][1], V[1][1]);
  527.     }
  528.   while (ui_t + 1 != T) /* S4 loop */
  529.     {
  530.       ui_t++;
  531.       mpz_mul (r, a, r);
  532.       mpz_mod (r, r, m);
  533.       /* Add new row and column to U and V.  They are initialized with
  534.  all elements set to zero, so clearing is not necessary. */
  535.       mpz_neg (U[ui_t][0], r); /* U: First col in new row. */
  536.       mpz_set_ui (U[ui_t][ui_t], 1); /* U: Last col in new row. */
  537.       mpz_set (V[ui_t][ui_t], m); /* V: Last col in new row. */
  538.       /* "Finally, for 1 <= i < t,
  539.    set q = round (vi1 * r / m),
  540.    vit = vi1*r - q*m,
  541.    and Ut=Ut+q*Ui */
  542.       for (ui_i = 0; ui_i < ui_t; ui_i++)
  543. {
  544.   mpz_mul (tmp1, V[ui_i][0], r); /* tmp1=vi1*r */
  545.   zdiv_round (q, tmp1, m); /* q=round(vi1*r/m) */
  546.   mpz_mul (tmp2, q, m); /* tmp2=q*m */
  547.   mpz_sub (V[ui_i][ui_t], tmp1, tmp2);
  548.   for (ui_j = 0; ui_j <= ui_t; ui_j++) /* U[t] = U[t] + q*U[i] */
  549.     {
  550.       mpz_mul (tmp1, q, U[ui_i][ui_j]); /* tmp=q*uij */
  551.       mpz_add (U[ui_t][ui_j], U[ui_t][ui_j], tmp1); /* utj = utj + q*uij */
  552.     }
  553. }
  554.       /* s = min (s, zdot (U[t], U[t]) */
  555.       vz_dot (tmp1, U[ui_t], U[ui_t], ui_t + 1);
  556.       if (mpz_cmp (tmp1, s) < 0)
  557. mpz_set (s, tmp1);
  558.       ui_k = ui_t;
  559.       ui_j = 0; /* WARNING: ui_j no longer a temp. */
  560.       /* S5 [Transform.] */
  561.       if (g_debug > DEBUG_2)
  562. printf ("(t, k, j, q1, q2, ...)n");
  563.       do
  564. {
  565.   if (g_debug > DEBUG_2)
  566.     printf ("(%u, %u, %u", ui_t + 1, ui_k + 1, ui_j + 1);
  567.   for (ui_i = 0; ui_i <= ui_t; ui_i++)
  568.     {
  569.       if (ui_i != ui_j)
  570. {
  571.   vz_dot (tmp1, V[ui_i], V[ui_j], ui_t + 1); /* tmp1=dot(Vi,Vj). */
  572.   mpz_abs (tmp2, tmp1);
  573.   mpz_mul_ui (tmp2, tmp2, 2); /* tmp2 = 2*abs(dot(Vi,Vj) */
  574.   vz_dot (tmp3, V[ui_j], V[ui_j], ui_t + 1); /* tmp3=dot(Vj,Vj). */
  575.   if (mpz_cmp (tmp2, tmp3) > 0)
  576.     {
  577.       zdiv_round (q, tmp1, tmp3); /* q=round(Vi.Vj/Vj.Vj) */
  578.       if (g_debug > DEBUG_2)
  579. {
  580.   printf (", ");
  581.   mpz_out_str (stdout, 10, q);
  582. }
  583.       for (ui_l = 0; ui_l <= ui_t; ui_l++)
  584. {
  585.   mpz_mul (tmp1, q, V[ui_j][ui_l]);
  586.   mpz_sub (V[ui_i][ui_l], V[ui_i][ui_l], tmp1); /* Vi=Vi-q*Vj */
  587.   mpz_mul (tmp1, q, U[ui_i][ui_l]);
  588.   mpz_add (U[ui_j][ui_l], U[ui_j][ui_l], tmp1); /* Uj=Uj+q*Ui */
  589. }
  590.       vz_dot (tmp1, U[ui_j], U[ui_j], ui_t + 1); /* tmp1=dot(Uj,Uj) */
  591.       if (mpz_cmp (tmp1, s) < 0) /* s = min(s,dot(Uj,Uj)) */
  592. mpz_set (s, tmp1);
  593.       ui_k = ui_j;
  594.     }
  595.   else if (g_debug > DEBUG_2)
  596.     printf (", #"); /* 2|Vi.Vj| <= Vj.Vj */
  597. }
  598.       else if (g_debug > DEBUG_2)
  599. printf (", *"); /* i == j */
  600.     }
  601.   if (g_debug > DEBUG_2)
  602.     printf (")n");
  603.   /* S6 [Advance j.] */
  604.   if (ui_j == ui_t)
  605.     ui_j = 0;
  606.   else
  607.     ui_j++;
  608. }
  609.       while (ui_j != ui_k); /* S5 */
  610.       /* From Knuth p. 104: "The exhaustive search in steps S8-S10
  611.  reduces the value of s only rarely." */
  612. #ifdef DO_SEARCH
  613.       /* S7 [Prepare for search.] */
  614.       /* Find minimum in (x[1], ..., x[t]) satisfying condition
  615.  x[k]^2 <= f(y[1], ...,y[t]) * dot(V[k],V[k]) */
  616.       ui_k = ui_t;
  617.       if (g_debug > DEBUG_2)
  618. {
  619.   printf ("searching...");
  620.   /*for (f = 0; f < ui_t*/
  621.   fflush (stdout);
  622. }
  623.       /* Z[i] = floor (sqrt (floor (dot(V[i],V[i]) * s / m^2))); */
  624.       mpz_pow_ui (tmp1, m, 2);
  625.       mpf_set_z (f_tmp1, tmp1);
  626.       mpf_set_z (f_tmp2, s);
  627.       mpf_div (f_tmp1, f_tmp2, f_tmp1); /* f_tmp1 = s/m^2 */
  628.       for (ui_i = 0; ui_i <= ui_t; ui_i++)
  629. {
  630.   vz_dot (tmp1, V[ui_i], V[ui_i], ui_t + 1);
  631.   mpf_set_z (f_tmp2, tmp1);
  632.   mpf_mul (f_tmp2, f_tmp2, f_tmp1);
  633.   f_floor (f_tmp2, f_tmp2);
  634.   mpf_sqrt (f_tmp2, f_tmp2);
  635.   mpz_set_f (Z[ui_i], f_tmp2);
  636. }
  637.       /* S8 [Advance X[k].] */
  638.       do
  639. {
  640.   if (g_debug > DEBUG_2)
  641.     {
  642.       printf ("X[%u] = ", ui_k);
  643.       mpz_out_str (stdout, 10, X[ui_k]);
  644.       printf ("tZ[%u] = ", ui_k);
  645.       mpz_out_str (stdout, 10, Z[ui_k]);
  646.       printf ("n");
  647.       fflush (stdout);
  648.     }
  649.   if (mpz_cmp (X[ui_k], Z[ui_k]))
  650.     {
  651.       mpz_add_ui (X[ui_k], X[ui_k], 1);
  652.       for (ui_i = 0; ui_i <= ui_t; ui_i++)
  653. mpz_add (Y[ui_i], Y[ui_i], U[ui_k][ui_i]);
  654.       /* S9 [Advance k.] */
  655.       while (++ui_k <= ui_t)
  656. {
  657.   mpz_neg (X[ui_k], Z[ui_k]);
  658.   mpz_mul_ui (tmp1, Z[ui_k], 2);
  659.   for (ui_i = 0; ui_i <= ui_t; ui_i++)
  660.     {
  661.       mpz_mul (tmp2, tmp1, U[ui_k][ui_i]);
  662.       mpz_sub (Y[ui_i], Y[ui_i], tmp2);
  663.     }
  664. }
  665.       vz_dot (tmp1, Y, Y, ui_t + 1);
  666.       if (mpz_cmp (tmp1, s) < 0)
  667. mpz_set (s, tmp1);
  668.     }
  669. }
  670.       while (--ui_k);
  671. #endif /* DO_SEARCH */
  672.       mpf_set_z (f_tmp1, s);
  673.       mpf_sqrt (rop[ui_t - 1], f_tmp1);
  674. #ifdef DO_SEARCH
  675.       if (g_debug > DEBUG_2)
  676. printf ("done.n");
  677. #endif /* DO_SEARCH */
  678.     } /* S4 loop */
  679.   /* Clear GMP variables. */
  680.   mpf_clear (f_tmp1);
  681.   mpf_clear (f_tmp2);
  682.   for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++)
  683.     {
  684.       for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++)
  685. {
  686.   mpz_clear (U[ui_i][ui_j]);
  687.   mpz_clear (V[ui_i][ui_j]);
  688. }
  689.       mpz_clear (X[ui_i]);
  690.       mpz_clear (Y[ui_i]);
  691.       mpz_clear (Z[ui_i]);
  692.     }
  693.   mpz_clear (tmp1);
  694.   mpz_clear (tmp2);
  695.   mpz_clear (tmp3);
  696.   mpz_clear (h);
  697.   mpz_clear (hp);
  698.   mpz_clear (r);
  699.   mpz_clear (s);
  700.   mpz_clear (p);
  701.   mpz_clear (pp);
  702.   mpz_clear (q);
  703.   mpz_clear (u);
  704.   mpz_clear (v);
  705.   return;
  706. }