[BACK]Return to statlib.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / tests / rand

Annotation of OpenXM_contrib/gmp/tests/rand/statlib.c, Revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>