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>