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