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