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