Annotation of OpenXM_contrib/pari-2.2/src/modules/mpqs.c, Revision 1.1
1.1 ! noro 1: /* $Id: mpqs.c,v 1.11 2001/10/01 12:11:33 karim Exp $
! 2:
! 3: Copyright (C) 2000 The PARI group.
! 4:
! 5: This file is part of the PARI/GP package.
! 6:
! 7: PARI/GP is free software; you can redistribute it and/or modify it under the
! 8: terms of the GNU General Public License as published by the Free Software
! 9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
! 10: ANY WARRANTY WHATSOEVER.
! 11:
! 12: Check the License for details. You should have received a copy of it, along
! 13: with the package; see the file 'COPYING'. If not, write to the Free Software
! 14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
! 15:
! 16: /* Written by Thomas Papanikolaou and Xavier Roblot
! 17: *
! 18: * Implementation of the Self-Initializing Multi-Polynomial Quadratic Sieve
! 19: * based on code developed as part of the LiDIA project
! 20: * (http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html)
! 21: */
! 22: #include "pari.h"
! 23:
! 24: #ifndef SEEK_SET
! 25: # define SEEK_SET 0
! 26: #endif
! 27:
! 28: #ifdef __CYGWIN32__
! 29: /* otherwise fseek() goes crazy due to silent \n <--> LF translations */
! 30: # define WRITE "wb"
! 31: # define READ "rb"
! 32: #else
! 33: # define WRITE "w"
! 34: # define READ "r"
! 35: #endif
! 36:
! 37: #ifdef MPQS_DEBUG_VERYVERBOSE
! 38: # ifndef MPQS_DEBUG_VERBOSE
! 39: # define MPQS_DEBUG_VERBOSE
! 40: # endif
! 41: #endif
! 42:
! 43: #ifdef MPQS_DEBUG_VERBOSE
! 44: # ifndef MPQS_DEBUG
! 45: # define MPQS_DEBUG
! 46: # endif
! 47: #endif
! 48:
! 49: #define MPQS_STRING_LENGTH (4 * 1024)
! 50: #define MPQS_CANDIDATE_ARRAY_SIZE 2000
! 51: #define MPQS_PRIMES_FOR_MULTIPLIER 5
! 52: /* `large primes' must be smaller than
! 53: * max(MPQS_LP_BOUND, largest_prime_in_FB) * MPQS_LP_FACTOR
! 54: */
! 55: #define MPQS_LP_BOUND 125000 /* works for 32 and 64bit */
! 56: #define MPQS_LP_FACTOR 80
! 57:
! 58: typedef ulong *mpqs_gauss_row;
! 59: typedef long *mpqs_gauss_indices;
! 60: typedef mpqs_gauss_row *mpqs_gauss_matrix;
! 61:
! 62: /* BEGIN: global variables to disappear as soon as possible */
! 63: /* names for temp. files, set in mpqs_get_filename */
! 64: static char *FREL_str;
! 65: static char *FNEW_str;
! 66: static char *LPREL_str;
! 67: static char *LPNEW_str;
! 68: static char *TMP_str;
! 69: static char *COMB_str;
! 70:
! 71: /* our own pointer to PARI's or to our own prime diffs table.
! 72: * NB the latter is never freed, unless we need to replace it with
! 73: * an even larger one. */
! 74: static byteptr mpqs_diffptr = NULL;
! 75: static long mpqs_prime_count = 0;
! 76:
! 77: /* END: global variables to disappear as soon as possible */
! 78:
! 79: /******************************/
! 80:
! 81: /**
! 82: ** determines a unique name for a file based on a short nickname
! 83: **/
! 84:
! 85: /* name is allocated on the stack */
! 86: static char *
! 87: mpqs_get_filename(char *s)
! 88: {
! 89: char *buf;
! 90:
! 91: s = pari_unique_filename(s);
! 92: buf = (char*) new_chunk((strlen(s) / sizeof(long)) + 2);
! 93: return strcpy(buf, s);
! 94: }
! 95:
! 96: /**
! 97: ** compares two `large prime' relations according to their
! 98: ** first element (the large prime itself).
! 99: **/
! 100:
! 101: static int
! 102: mpqs_relations_cmp(const void *a, const void *b)
! 103: {
! 104: char **sa = (char **) a;
! 105: char **sb = (char **) b;
! 106: long qa = strtol(*sa, NULL, 10);
! 107: long qb = strtol(*sb, NULL, 10);
! 108: /* atol() isn't entirely portable for the Full Relations case where the
! 109: strings of digits are too long to fit into a long --GN */
! 110: if (qa < qb) return -1;
! 111: else if (qa > qb) return 1;
! 112: else return strcmp(*sa, *sb);
! 113: }
! 114:
! 115: /**
! 116: ** Given a file "filename" containing full or `large prime' relations,
! 117: ** this function rearranges the file so that relations are sorted by
! 118: ** their first elements. Works also for sorting full relations.
! 119: ** Works in memory, discards duplicate lines, and overwrites the
! 120: ** original file.
! 121: **/
! 122:
! 123: #define bummer(fn) err(talker, "error whilst writing to file %s", fn)
! 124: #define min_bufspace 120 /* use new buffer when < min_bufspace left */
! 125: #define buflist_size 1024 /* size of list-of-buffers blocks */
! 126:
! 127: static long
! 128: mpqs_sort_lp_file(char *filename)
! 129: {
! 130: pariFILE *pTMP;
! 131: FILE *TMP;
! 132: char *old_s, **sort_table = (char**)avma, *buf, *cur_line;
! 133: static char **buflist_head = NULL;
! 134: char **buflist, **next_buflist;
! 135: long i, j, bufspace, length, count, av=avma;
! 136:
! 137: if (!buflist_head)
! 138: {
! 139: buflist_head = (char **) gpmalloc(buflist_size * sizeof(char *));
! 140: buflist = buflist_head;
! 141: *buflist++ = NULL; /* flag this as last and only buflist block */
! 142: }
! 143: else
! 144: buflist = buflist_head + 1;
! 145: /* this block will never be freed, and extra blocks may be allocated as
! 146: needed and linked ahead of it. NB it turns out that whilst extra
! 147: buflist blocks might have been needed when we were still sorting
! 148: entire FREL files (more than 1023 buffers, corresponding to about
! 149: 20000 lines of c.200 characters), they should never be touched now
! 150: that we only sort LPNEW and FNEW files, which are rather shorter.
! 151: But the code might as well stay around for paranoia, or for future
! 152: upgrades to handling even larger numbers (and factor bases and thus
! 153: relations files). It only costs one comparison per buffer allocation.
! 154: --GN */
! 155:
! 156: pTMP = pari_fopen(filename, READ);
! 157: TMP = pTMP->file;
! 158: /* get first buffer and read first line, if any, into it */
! 159: buf = (char *) gpmalloc(MPQS_STRING_LENGTH * sizeof(char));
! 160: cur_line = buf;
! 161: bufspace = MPQS_STRING_LENGTH;
! 162:
! 163: if (fgets(cur_line, bufspace, TMP) == NULL)
! 164: { /* file empty */
! 165: avma = av;
! 166: free(buf);
! 167: pari_fclose(pTMP);
! 168: return 0;
! 169: }
! 170: /* enter first buffer into buflist */
! 171: *buflist++ = buf; /* can't overflow the buflist block */
! 172: length = strlen(cur_line) + 1; /* count the \0 byte as well */
! 173: bufspace -= length;
! 174:
! 175: /* at start of loop, one line from the file is sitting in cur_line inside
! 176: buf, the next will go into cur_line + length, and there's room for
! 177: bufspace further characters in buf.
! 178: The loop reads another line if one exists, and if this overruns the
! 179: current buffer, it allocates a fresh one --GN */
! 180:
! 181: for (i=0, sort_table--; /* until end of file */; i++, sort_table--)
! 182: {
! 183: /* sort_table is allocated on the stack, 0x100 cells at a time. Hence the
! 184: * stack must be left alone in the rest of the loop to keep the array
! 185: * connected. In particular, buffers can't be new_chunk'ed --KB */
! 186: if ((i & 0xff) == 0) new_chunk(0x100);
! 187: *sort_table = cur_line;
! 188: cur_line += length;
! 189:
! 190: /* if very little room is left, allocate a fresh buffer before
! 191: attempting to read a line, and remember to free it if no
! 192: further line is forthcoming. This avoids some copying of
! 193: partial lines --GN */
! 194: if (bufspace < min_bufspace)
! 195: {
! 196: if (
! 197: #ifdef MPQS_DEBUG
! 198: 1 ||
! 199: #endif
! 200: DEBUGLEVEL >= 7)
! 201: fprintferr("MQPS: short of space -- another buffer for sorting\n");
! 202: buf = (char *) gpmalloc(MPQS_STRING_LENGTH * sizeof(char));
! 203: cur_line = buf;
! 204: bufspace = MPQS_STRING_LENGTH;
! 205: if (fgets(cur_line, bufspace, TMP) == NULL)
! 206: {
! 207: free(buf); break;
! 208: }
! 209: else
! 210: {
! 211: /* remember buffer for later deallocation */
! 212: if (buflist - buflist_head >= buflist_size)
! 213: {
! 214: /* need another buflist block */
! 215: next_buflist =
! 216: (char **) gpmalloc(buflist_size * sizeof(char *));
! 217: *next_buflist = (char *)buflist_head; /* link */
! 218: buflist_head = next_buflist;
! 219: buflist = buflist_head + 1;
! 220: }
! 221: *buflist++ = buf;
! 222: length = strlen(cur_line) + 1;
! 223: bufspace -= length;
! 224: continue;
! 225: }
! 226: }
! 227:
! 228: /* normal case: try fitting another line into the current buffer,
! 229: break if none exists */
! 230: if (fgets(cur_line, bufspace, TMP) == NULL) break;
! 231: length = strlen(cur_line) + 1;
! 232: bufspace -= length;
! 233:
! 234: /* check whether we got the entire line or only part of it */
! 235: if (bufspace == 0 && cur_line[length-2] != '\n')
! 236: {
! 237: long lg1;
! 238: if (
! 239: #ifdef MPQS_DEBUG
! 240: 1 ||
! 241: #endif
! 242: DEBUGLEVEL >= 7)
! 243: fprintferr("MQPS: line wrap -- another buffer for sorting\n");
! 244: buf = (char *) gpmalloc(MPQS_STRING_LENGTH * sizeof(char));
! 245: /* remember buffer for later deallocation */
! 246: if (buflist - buflist_head >= buflist_size)
! 247: {
! 248: /* need another buflist block */
! 249: next_buflist =
! 250: (char **) gpmalloc(buflist_size * sizeof(char *));
! 251: *next_buflist = (char *)buflist_head; /* link */
! 252: buflist_head = next_buflist;
! 253: buflist = buflist_head + 1;
! 254: }
! 255: *buflist++ = buf;
! 256:
! 257: /* copy what we've got to the new buffer */
! 258: (void)strcpy(buf, cur_line); /* cannot overflow */
! 259: cur_line = buf + length - 1; /* point at the \0 byte */
! 260: bufspace = MPQS_STRING_LENGTH - length + 1;
! 261: /* read remainder of line */
! 262: if (fgets(cur_line, bufspace, TMP) == NULL)
! 263: err(talker,"MPQS: relations file truncated?!\n");
! 264: lg1 = strlen(cur_line);
! 265: length += lg1; /* we already counted the \0 once */
! 266: bufspace -= (lg1 + 1); /* but here we must take it into account */
! 267: cur_line = buf; /* back up to the beginning of the line */
! 268: }
! 269: } /* for */
! 270:
! 271: pari_fclose(pTMP);
! 272:
! 273: #if 0 /* caught above, can no longer happen */
! 274: if (i == 0)
! 275: {
! 276: avma = av; return 0;
! 277: }
! 278: #endif
! 279:
! 280: /* sort the whole lot in place by swapping pointers */
! 281: qsort(sort_table, i, sizeof(char *), mpqs_relations_cmp);
! 282:
! 283: /* copy results back to the original file, skipping exact duplicates */
! 284: pTMP = pari_fopen(filename, WRITE); /* NOT safefopen */
! 285: TMP = pTMP->file;
! 286: old_s = sort_table[0];
! 287: if (fputs(sort_table[0], TMP) < 0)
! 288: bummer(filename);
! 289: count = 1;
! 290: for(j = 1; j < i; j++)
! 291: {
! 292: if (strcmp(old_s, sort_table[j]) != 0)
! 293: {
! 294: if (fputs(sort_table[j], TMP) < 0)
! 295: bummer(filename);
! 296: count++;
! 297: }
! 298: old_s = sort_table[j];
! 299: }
! 300: pari_fclose(pTMP);
! 301: if (
! 302: #ifdef MPQS_DEBUG
! 303: 1 ||
! 304: #endif
! 305: DEBUGLEVEL >= 6)
! 306: fprintferr("MPQS: done sorting one file.\n");
! 307:
! 308: /* deallocate buffers and any extraneous buflist blocks except the first */
! 309: while (*--buflist)
! 310: {
! 311: if (buflist != buflist_head) /* not a linkage pointer */
! 312: free((void *) *buflist); /* free a buffer */
! 313: else /* linkage pointer */
! 314: {
! 315: next_buflist = (char **)(*buflist);
! 316: free((void *)buflist_head); /* free a buflist block */
! 317: buflist_head = next_buflist;
! 318: buflist = buflist_head + buflist_size;
! 319: }
! 320: }
! 321: #if 0
! 322: for (j = 0; j < i; j++)
! 323: {
! 324: buf = (char *)(sort_table[j]) - 1;
! 325: if (*buf) /* check: deallocation flag or \0 ? */
! 326: free(buf);
! 327: }
! 328: #endif
! 329: avma = av; return count;
! 330: }
! 331:
! 332: /**
! 333: ** appends contents of file fp1 to file fp of name filename
! 334: ** (auxiliary routine for merge sort) and returns number of
! 335: ** lines copied.
! 336: ** fp assumed open for appending and fp1 for reading; fp will
! 337: ** be closed afterwards.
! 338: **/
! 339:
! 340: static long
! 341: mpqs_append_file(pariFILE *f, FILE *fp1)
! 342: {
! 343: FILE *fp = f->file;
! 344: char line[MPQS_STRING_LENGTH];
! 345: long c = 0;
! 346: while (fgets(line, MPQS_STRING_LENGTH, fp1) != NULL)
! 347: {
! 348: if (fputs(line, fp) < 0)
! 349: err(talker, "error whilst appending to file %s", f->name);
! 350: c++;
! 351: }
! 352: if (fflush(fp))
! 353: err(warner, "error whilst flushing file %s", f->name);
! 354: pari_fclose(f);
! 355: return c;
! 356: }
! 357:
! 358: /**
! 359: ** Does a merge-sort on the files LPREL and LPNEW;
! 360: ** assumes that LPREL and LPNEW are already sorted.
! 361: ** Creates/truncates the TMP file, writes result to it and closes it
! 362: ** (via a call to mpqs_append_file()).
! 363: ** Instead of LPREL, LPNEW we may also call this with FREL, FNEW.
! 364: ** In the latter case mode should be 1 (and we return the count of
! 365: ** all full relations), in the former 0 (and we return the count
! 366: ** of frels we expect to be able to combine out of the present lprels).
! 367: ** Moreover, if mode is 0, the combinable lprels are written out to a
! 368: ** separate file (COMB) which we also create and close (the caller
! 369: ** will find it exists iff our return value is nonzero), and we keep
! 370: ** only one occurrence of each `large prime' in TMP (i.e. in the future
! 371: ** LPREL file). --GN
! 372: **/
! 373:
! 374: #define swap_lines { \
! 375: line_tmp = line_new_old; \
! 376: line_new_old = line_new; \
! 377: line_new = line_tmp; \
! 378: }
! 379:
! 380: static long
! 381: mpqs_mergesort_lp_file0(FILE *LPREL, FILE *LPNEW, long mode)
! 382: {
! 383: /* TMP (renamed upon return) and COMB (deleted upon return) guaranteed not
! 384: * to exist yet --> safefopen for both temp files */
! 385: pariFILE *pTMP = pari_safefopen(TMP_str, WRITE);
! 386: FILE *TMP = pTMP->file;
! 387: pariFILE *pCOMB = NULL;
! 388: FILE *COMB = NULL; /* gcc -Wall */
! 389: char line1[MPQS_STRING_LENGTH], line2[MPQS_STRING_LENGTH];
! 390: char line[MPQS_STRING_LENGTH];
! 391: char *line_new = line1, *line_new_old = line2, *line_tmp;
! 392: long q_new, q_new_old = -1, q, i = 0, c = 0;
! 393: long comb_in_progress;
! 394:
! 395: /* if LPNEW is empty, copy LPREL to TMP. Could be done by a rename
! 396: if we didn't want to count the lines (again)... however, this
! 397: case will not normally happen */
! 398:
! 399: if (fgets(line_new, MPQS_STRING_LENGTH, LPNEW) == NULL)
! 400: {
! 401: i = mpqs_append_file(pTMP, LPREL);
! 402: return (mode ? i : 0);
! 403: }
! 404: /* we now have a line_new from LPNEW */
! 405:
! 406: /* if LPREL is empty, copy LPNEW to TMP... almost. */
! 407:
! 408: if (fgets(line, MPQS_STRING_LENGTH, LPREL) == NULL)
! 409: {
! 410: if (fputs(line_new, TMP) < 0)
! 411: bummer(TMP_str);
! 412: if (mode) /* full relations mode */
! 413: {
! 414: i = mpqs_append_file(pTMP, LPNEW);
! 415: return i + 1; /* COMB cannot be open here */
! 416: }
! 417:
! 418: /* LP mode: check for combinable relations */
! 419: q_new_old = atol(line_new);
! 420: /* we need to retain a copy of the old line just for a moment, because
! 421: we may yet have to write it to COMB, too. Do this simply by swapping
! 422: the two buffers */
! 423: swap_lines;
! 424: comb_in_progress = 0;
! 425: i = 0;
! 426:
! 427: while (fgets(line_new, MPQS_STRING_LENGTH, LPNEW) != NULL)
! 428: {
! 429: q_new = atol(line_new);
! 430: if (q_new_old == q_new)
! 431: {
! 432: /* found combinables, check whether we're already busy on this
! 433: particular `large prime' */
! 434: if (!comb_in_progress)
! 435: {
! 436: /* if not, write first line to COMB, creating and opening the
! 437: file first if it isn't open yet */
! 438: if (!pCOMB)
! 439: {
! 440: pCOMB = pari_safefopen(COMB_str, WRITE);
! 441: COMB = pCOMB->file;
! 442: }
! 443: if (fputs(line_new_old, COMB) < 0)
! 444: bummer(COMB_str);
! 445: comb_in_progress = 1;
! 446: }
! 447: /* in any case, write the current line, and count it */
! 448: if (fputs(line_new, COMB) < 0)
! 449: bummer(COMB_str);
! 450: i++;
! 451: }
! 452: else
! 453: { /* not combinable */
! 454: q_new_old = q_new;
! 455: comb_in_progress = 0;
! 456: /* and dump it to the TMP file */
! 457: if (fputs(line_new, TMP) < 0)
! 458: bummer(TMP_str);
! 459: /* and stash it away for a moment */
! 460: swap_lines;
! 461: comb_in_progress = 0;
! 462: }
! 463: } /* while */
! 464: if (pCOMB) pari_fclose(pCOMB);
! 465: pari_fclose(pTMP);
! 466: return i;
! 467: }
! 468:
! 469: /* normal case: both LPNEW and LPREL are not empty */
! 470: q_new = atol(line_new);
! 471: q = atol(line);
! 472:
! 473: for(;;) /* main merging loop */
! 474: {
! 475: comb_in_progress = 0;
! 476: i = 0;
! 477:
! 478: /* first the harder case: let LPNEW catch up with LPREL, and possibly
! 479: overtake it, checking for combinables coming from LPNEW alone */
! 480:
! 481: while (q > q_new)
! 482: {
! 483: if (mode || !comb_in_progress)
! 484: {
! 485: if (fputs(line_new, TMP) < 0)
! 486: bummer(TMP_str);
! 487: }
! 488: if (mode)
! 489: c++; /* in FREL mode, count lines written */
! 490: else if (!comb_in_progress)
! 491: {
! 492: q_new_old = q_new;
! 493: swap_lines;
! 494: }
! 495: if (fgets(line_new, MPQS_STRING_LENGTH, LPNEW) == NULL)
! 496: {
! 497: if (fputs(line, TMP) < 0)
! 498: bummer(TMP_str);
! 499: if (mode) c++; else c += i;
! 500: i = mpqs_append_file(pTMP, LPREL);
! 501: if (pCOMB) pari_fclose(pCOMB);
! 502: return (mode ? c + i : c);
! 503: }
! 504: q_new = atol(line_new);
! 505: if (mode) continue;
! 506: /* LP mode only: */
! 507: if (q_new_old != q_new)
! 508: { /* not combinable */
! 509: comb_in_progress = 0;
! 510: /* next loop iteration will deal with it, or the loop may end */
! 511: }
! 512: else
! 513: {
! 514: /* found combinables, check whether we're already busy on this
! 515: `large prime' */
! 516: if (!comb_in_progress)
! 517: {
! 518: if (!pCOMB)
! 519: {
! 520: pCOMB = pari_safefopen(COMB_str, WRITE);
! 521: COMB = pCOMB->file;
! 522: }
! 523: if (fputs(line_new_old, COMB) < 0)
! 524: bummer(COMB_str);
! 525: comb_in_progress = 1;
! 526: }
! 527: /* in any case, write the current line, and count it */
! 528: if (fputs(line_new, COMB) < 0)
! 529: bummer(COMB_str);
! 530: i++;
! 531: }
! 532: } /* while q > q_new */
! 533:
! 534: /* q <= q_new */
! 535:
! 536: if (!mode) c += i; /* accumulate count of combinables */
! 537: i = 0; /* and clear it */
! 538: comb_in_progress = 0; /* redundant */
! 539:
! 540: /* now let LPREL catch up with LPNEW, and possibly overtake it */
! 541:
! 542: while (q < q_new)
! 543: {
! 544: if (fputs(line, TMP) < 0)
! 545: bummer(TMP_str);
! 546: if (mode) c++;
! 547: if (fgets(line, MPQS_STRING_LENGTH, LPREL) == NULL)
! 548: {
! 549: if (fputs(line_new, TMP) < 0)
! 550: bummer(TMP_str);
! 551: i = mpqs_append_file(pTMP, LPNEW);
! 552: if (pCOMB) pari_fclose(pCOMB);
! 553: return (mode ? c + i + 1 : c);
! 554: }
! 555: else
! 556: q = atol(line);
! 557: }
! 558:
! 559: /* q >= q_new */
! 560:
! 561: /* Finally, it may happen that q == q_new, indicating combinables whose
! 562: `large prime' is already represented in LPREL, and appears now once
! 563: or more often in LPNEW. Thus in this sub-loop we advance LPNEW.
! 564: The `line' from LPREL is left alone, and will be written to TMP the
! 565: next time around the main for loop; we only write it to COMB here --
! 566: unless all we find is an exact duplicate of the line we already have,
! 567: that is. (There can be at most one such, and if so it will simply be
! 568: discarded, whether we are in LP or full relations mode.) */
! 569:
! 570: while (q == q_new)
! 571: {
! 572: if (strcmp(line_new, line) == 0)
! 573: {
! 574: /* duplicate -- move right ahead to the next LPNEW line */
! 575: ; /* do nothing here */
! 576: } /* end duplicate case */
! 577: else if (mode)
! 578: {
! 579: /* full relations mode: write line_new out first, keep line */
! 580: if (fputs(line_new, TMP) < 0)
! 581: bummer(TMP_str);
! 582: c++;
! 583: } /* end full relations case */
! 584: else
! 585: {
! 586: /* LP mode, and combinable relation */
! 587: if (!comb_in_progress)
! 588: {
! 589: if (!pCOMB)
! 590: {
! 591: pCOMB = pari_safefopen(COMB_str, WRITE);
! 592: COMB = pCOMB->file;
! 593: }
! 594: if (fputs(line, COMB) < 0)
! 595: bummer(COMB_str);
! 596: comb_in_progress = 1;
! 597: }
! 598: if (fputs(line_new, COMB) < 0)
! 599: bummer(COMB_str);
! 600: i++;
! 601: } /* end combinable LP case */
! 602: /* NB comb_in_progress is cleared by q_new becoming bigger than q,
! 603: and thus the current while loop terminating, the next time through
! 604: the main for loop */
! 605:
! 606: /* common ending: get another line_new, if any */
! 607: if (fgets(line_new, MPQS_STRING_LENGTH, LPNEW) == NULL)
! 608: {
! 609: if (fputs(line, TMP) < 0)
! 610: bummer(TMP_str);
! 611: if (mode) c++; else c += i;
! 612: i = mpqs_append_file(pTMP, LPREL);
! 613: if (pCOMB) pari_fclose(pCOMB);
! 614: return (mode ? c + i : c);
! 615: }
! 616: else
! 617: q_new = atol(line_new);
! 618: } /* while */
! 619:
! 620: if (!mode) c += i; /* accumulate count of combinables */
! 621: } /* for */
! 622: }
! 623:
! 624: static long
! 625: mpqs_mergesort_lp_file(char *REL_str, char *NEW_str, long mode)
! 626: {
! 627: pariFILE *pREL = pari_fopen(REL_str, READ);
! 628: pariFILE *pNEW = pari_fopen(NEW_str, READ);
! 629: long tp = mpqs_mergesort_lp_file0(pREL->file, pNEW->file, mode);
! 630:
! 631: pari_fclose(pREL);
! 632: pari_fclose(pNEW);
! 633: pari_unlink(REL_str);
! 634: if (rename(TMP_str,REL_str))
! 635: err(talker, "can\'t rename file %s to %s", TMP_str, REL_str);
! 636: if (
! 637: #ifdef MPQS_DEBUG
! 638: 1 ||
! 639: #endif
! 640: DEBUGLEVEL >= 6)
! 641: fprintferr("MPQS: renamed file %s to %s\n", TMP_str, REL_str);
! 642: return tp;
! 643: }
! 644:
! 645: /******************************/
! 646: /**
! 647: ** return next prime larger than p, using *primes_ptr on the
! 648: ** diffptr table first and pari's other wits after that
! 649: **/
! 650:
! 651: static byteptr
! 652: mpqs_iterate_primes(long *p, byteptr primes_ptr)
! 653: {
! 654: long prime = *p;
! 655: if (*primes_ptr)
! 656: prime += *primes_ptr++;
! 657: else
! 658: {
! 659: long av = avma;
! 660: prime = itos(nextprime(stoi(prime + 1)));
! 661: avma = av;
! 662: }
! 663: *p = prime;
! 664: return primes_ptr;
! 665: }
! 666:
! 667:
! 668: /**
! 669: ** return the multiplier k for N to use in MPQS
! 670: **/
! 671:
! 672: long
! 673: mpqs_find_k(GEN N, long tries)
! 674: {
! 675: static long cand_table[] = { 1,3,5,7,11,13,15,17,19,21,23,
! 676: 29,31,33,35,37,39,41,43,47,51,53,
! 677: 55,57,59,61,65,67,69,71,73,79,83,
! 678: 85,89,91,93,95,97,101,103,105,107,
! 679: 109,113,127,131,137,139};
! 680: long av = avma;
! 681: long best_k = 1, k, p, N_mod_4 = smodis(N, 4), x;
! 682: GEN kN;
! 683: double best_value = 1, value, dp;
! 684: long i, j;
! 685: byteptr primes_ptr;
! 686:
! 687: for (i = 0; i < MPQS_PRIMES_FOR_MULTIPLIER; i++)
! 688: {
! 689: k = cand_table[i];
! 690: x = (k * N_mod_4) % 4;
! 691: if (x == 1)
! 692: {
! 693: value = -0.7 * log2 ((double) k);
! 694: kN = mulis(N, k);
! 695: if (smodis(kN, 8) == 1)
! 696: value += 1.38629;
! 697:
! 698: j = 0; p = 0;
! 699: primes_ptr = diffptr;
! 700: while (j <= tries)
! 701: {
! 702: primes_ptr = mpqs_iterate_primes(&p, primes_ptr);
! 703: if (kross(smodis(kN, p), p) == 1)
! 704: {
! 705: j++;
! 706: dp = log2((double) p) / p;
! 707: value += (k % p == 0) ? dp : 2 * dp;
! 708: }
! 709: }
! 710:
! 711: if (value > best_value)
! 712: {
! 713: best_value = value;
! 714: best_k = k;
! 715: }
! 716: }
! 717: }
! 718: avma = av; return best_k;
! 719: }
! 720:
! 721: /******************************/
! 722: /**
! 723: ** guesstimate up to what size we're going to need precomputed
! 724: ** small primes
! 725: **/
! 726:
! 727: static long
! 728: mpqs_find_maxprime(long size)
! 729: {
! 730: double x;
! 731:
! 732: if (size < 16000)
! 733: return 176000;
! 734:
! 735: x = log((double)size);
! 736: x += log(x);
! 737: x -= 0.9427;
! 738: x *= size;
! 739:
! 740: return (long)x;
! 741: }
! 742:
! 743: /**
! 744: ** return the number of primes initialized in PARI
! 745: **/
! 746:
! 747: static long
! 748: mpqs_count_primes()
! 749: {
! 750: byteptr p = mpqs_diffptr;
! 751:
! 752: for ( ; *p; p++) /* empty */;
! 753: return (p - mpqs_diffptr);
! 754: }
! 755:
! 756: /**
! 757: ** create a factor base of size primes p_i with the
! 758: ** property that legendre(k*N, p_i) == 0, 1
! 759: ** FB[0] contains the size of the factor base; FB[FB[0]+1] is the
! 760: ** last prime p_i.
! 761: ** FB[1] contains -1 which allows to handle negative values of Q(x).
! 762: ** If a prime factor of N is found during the construction, it
! 763: ** is returned in f, otherwise f = 0 (such a factor will necessarily
! 764: ** fit into a C long).
! 765: **/
! 766:
! 767: static long*
! 768: mpqs_create_FB(long size, GEN kN, long k, long *f)
! 769: {
! 770: long i, kr, p = 0;
! 771: long *FB;
! 772: byteptr primes_ptr;
! 773:
! 774: FB = (long *) calloc(size + 3, sizeof(long));
! 775: if (!FB) err(memer);
! 776: FB[0] = size;
! 777: FB[1] = -1;
! 778: /* pick up PARI's current differences-of-small-primes array */
! 779: /* unless we already have our own. We must then reset it to NULL */
! 780: /* so we will not use a stale one the next time we are called */
! 781: if (!mpqs_diffptr) mpqs_diffptr = diffptr;
! 782:
! 783: if ((mpqs_prime_count ? mpqs_prime_count : mpqs_count_primes())
! 784: < 3 * size)
! 785: {
! 786: long newsize = 3 * mpqs_find_maxprime(size);
! 787: if (mpqs_diffptr != diffptr) free((void *) mpqs_diffptr);
! 788: if (DEBUGLEVEL >= 2)
! 789: {
! 790: fprintferr("MPQS: precomputing auxiliary primes up to %ld\n",
! 791: newsize);
! 792: }
! 793: mpqs_diffptr = initprimes(newsize);
! 794: /* count 'em once and remember the result */
! 795: mpqs_prime_count = mpqs_count_primes();
! 796: }
! 797:
! 798: if (
! 799: #ifdef MPQS_DEBUG
! 800: 1 ||
! 801: #endif
! 802: DEBUGLEVEL >= 7)
! 803: fprintferr("MPQS: FB [-1");
! 804: primes_ptr = mpqs_diffptr;
! 805: for (i = 2; i < size + 2; )
! 806: {
! 807: primes_ptr = mpqs_iterate_primes(&p, primes_ptr);
! 808:
! 809: /* testing p!=k was only correct because MPQS_PRIMES_FOR_MULTIPLIER
! 810: is so small that the composite values k > 1 will never be chosen.
! 811: Fixing this just in case someone increases that parameter one day...
! 812: --GN */
! 813: if (p > k || k%p)
! 814: {
! 815: kr = kross(smodis(kN, p), p);
! 816: if (kr != -1)
! 817: {
! 818: if (kr == 0)
! 819: {
! 820: if (
! 821: #ifdef MPQS_DEBUG
! 822: 1 ||
! 823: #endif
! 824: DEBUGLEVEL >= 7)
! 825: fprintferr(",%ld...] Wait a second --\n", p);
! 826: *f = p;
! 827: return FB;
! 828: }
! 829: if (
! 830: #ifdef MPQS_DEBUG
! 831: 1 ||
! 832: #endif
! 833: DEBUGLEVEL >= 7)
! 834: fprintferr(",%ld", p);
! 835: FB[i] = p, i++;
! 836: }
! 837: }
! 838: }
! 839:
! 840: if (
! 841: #ifdef MPQS_DEBUG
! 842: 1 ||
! 843: #endif
! 844: DEBUGLEVEL >= 7)
! 845: {
! 846: fprintferr("]\n");
! 847: flusherr();
! 848: }
! 849:
! 850: FB[i] = 0;
! 851: if (DEBUGLEVEL >= 6)
! 852: fprintferr("MPQS: last available index in FB is %ld\n", i - 1);
! 853:
! 854: *f = 0;
! 855: return FB;
! 856: }
! 857:
! 858: /******************************/
! 859:
! 860: /**
! 861: ** see below for the format of the parameter table.
! 862: ** These values are somewhat experimental and can be improved by
! 863: ** further extensive testing.
! 864: ** Tentative entries for 9...14 digits by GN, entry for 15 changed
! 865: ** Tentative entries for 81...100 digits by GN, entry for 74 changed
! 866: ** total_no_of_primes_for_A (penultimate entries in each row) increased
! 867: ** throughout, partly so as to offset the effect of changed bin_index
! 868: ** increment strategy --GN
! 869: ** Added entries to govern sort intervals, commented out unused numbers
! 870: ** of digits --GN
! 871: **/
! 872:
! 873: static double
! 874: mpqs_parameters[99][8] =
! 875: {
! 876: { /*9*/ 0.8, 900, 20, 3, 13, 2, 70, 8},
! 877: { /*10*/ 0.8, 900, 21, 3, 12, 2, 70, 8},
! 878: { /*11*/ 0.8, 920, 22, 3, 12, 2, 70, 6},
! 879: { /*12*/ 0.8, 960, 24, 3, 12, 2, 70, 6},
! 880: { /*13*/ 0.8, 1020, 26, 3, 12, 2, 70, 6},
! 881: { /*14*/ 0.8, 1100, 29, 3, 12, 2, 70, 6},
! 882: { /*15*/ 0.8, 1200, 32, 3, 12, 2, 60, 8},
! 883: { /*16*/ 0.8, 1400, 35, 3, 12, 2, 60, 8},
! 884: { /*17*/ 0.8, 3000, 40, 3, 12, 2, 60, 8},
! 885: { /*18*/ 0.8, 3000, 60, 3, 12, 2, 50, 10},
! 886: { /*19*/ 0.8, 3600, 80, 3, 13, 2, 50, 10},
! 887: { /*20*/ 0.8, 4000, 100, 3, 13, 2, 40, 10},
! 888: { /*21*/ 0.8, 4300, 100, 3, 13, 2, 40, 10},
! 889: { /*22*/ 0.8, 4500, 120, 3, 13, 3, 40, 10},
! 890: { /*23*/ 0.8, 4800, 140, 3, 14, 3, 30, 10},
! 891: { /*24*/ 0.8, 5000, 160, 3, 14, 4, 30, 10},
! 892: { /*25*/ 0.8, 5000, 180, 3, 14, 4, 30, 10},
! 893: { /*26*/ 0.9, 6000, 200, 5, 10, 4, 30, 10},
! 894: { /*27*/ 1.17, 6000, 220, 5, 10, 5, 30, 10},
! 895: { /*28*/ 1.17, 6500, 240, 5, 10, 5, 30, 10},
! 896: { /*29*/ 1.17, 6500, 260, 5, 10, 5, 30, 10},
! 897: { /*30*/ 1.36, 7000, 325, 5, 10, 5, 20, 10},
! 898: { /*31*/ 1.36, 7000, 355, 5, 10, 5, 20, 10},
! 899: { /*32*/ 1.36, 7500, 375, 5, 10, 5, 20, 10},
! 900: { /*33*/ 1.43, 7500, 400, 6, 11, 6, 20, 10},
! 901: { /*34*/ 1.43, 7500, 425, 6, 11, 6, 20, 10},
! 902: { /*35*/ 1.43, 7500, 550, 6, 11, 6, 20, 10},
! 903: { /*36*/ 1.43, 8000, 650, 6, 11, 6, 20, 10},
! 904: { /*37*/ 1.69, 9000, 750, 6, 11, 7, 20, 10},
! 905: { /*38*/ 1.69, 10000, 850, 6, 11, 7, 20, 10},
! 906: { /*39*/ 1.69, 11000, 950, 6, 11, 7, 20, 10},
! 907: { /*40*/ 1.69, 14000, 1000, 6, 11, 7, 20, 10},
! 908: { /*41*/ 1.69, 14000, 1150, 6, 11, 8, 10, 10},
! 909: { /*42*/ 1.69, 15000, 1300, 6, 11, 8, 10, 10},
! 910: { /*43*/ 1.69, 15000, 1600, 6, 11, 8, 10, 10},
! 911: { /*44*/ 1.69, 15000, 1900, 7, 12, 9, 10, 10},
! 912: { /*45*/ 1.69, 15000, 2200, 7, 12, 9, 10, 10},
! 913: { /*46*/ 1.69, 20000, 2500, 7, 12, 9, 10, 10},
! 914: { /*47*/ 1.69, 25000, 2500, 7, 12, 10, 10, 10},
! 915: { /*48*/ 1.69, 27500, 2700, 7, 12, 10, 10, 10},
! 916: { /*49*/ 1.69, 30000, 2800, 7, 12, 10, 10, 10},
! 917: { /*50*/ 1.75, 35000, 2900, 7, 12, 10, 10, 10},
! 918: { /*51*/ 1.75, 40000, 3000, 7, 12, 10, 10, 10},
! 919: { /*52*/ 1.85, 50000, 3200, 7, 12, 11, 10, 10},
! 920: { /*53*/ 1.85, 50000, 3500, 7, 12, 11, 10, 10},
! 921: { /*54*/ 1.95, 80000, 3800, 7, 13, 11, 10, 10},
! 922: { /*55*/ 1.95, 90000, 4100, 7, 13, 11, 10, 10},
! 923: { /*56*/ 1.95, 100000, 4400, 7, 13, 11, 10, 10},
! 924: { /*57*/ 1.95, 80000, 4700, 8, 14, 12, 10, 10},
! 925: { /*58*/ 1.95, 80000, 5000, 8, 14, 12, 10, 10},
! 926: { /*59*/ 2.15, 130000, 5500, 8, 14, 12, 10, 8},
! 927: { /*60*/ 2.15, 140000, 5800, 8, 14, 12, 10, 8},
! 928: { /*61*/ 2.15, 150000, 6100, 8, 14, 13, 10, 8},
! 929: { /*62*/ 2.15, 160000, 6400, 8, 14, 13, 10, 8},
! 930: { /*63*/ 2.35, 170000, 6700, 8, 14, 13, 10, 8},
! 931: { /*64*/ 2.35, 180000, 7000, 8, 14, 13, 10, 8},
! 932: { /*65*/ 2.35, 190000, 7300, 8, 14, 13, 10, 8},
! 933: { /*66*/ 2.35, 200000, 7600, 8, 14, 13, 10, 8},
! 934: { /*67*/ 2.4, 150000, 7900, 8, 14, 13, 10, 8},
! 935: { /*68*/ 2.4, 150000, 8200, 8, 15, 13, 10, 8},
! 936: { /*69*/ 2.4, 130000, 8600, 8, 15, 13, 8, 6},
! 937: { /*70*/ 2.45, 130000, 8800, 8, 15, 13, 8, 6},
! 938: { /*71*/ 2.45, 130000, 8800, 9, 16, 13, 8, 6},
! 939: { /*72*/ 2.4, 260000, 9400, 9, 16, 13, 5, 5},
! 940: { /*73*/ 2.4, 270000, 9700, 9, 16, 13, 5, 5},
! 941: { /*74*/ 2.4, 280000, 9800, 9, 16, 13, 5, 5},
! 942: { /*75*/ 2.6, 140000, 9000, 9, 17, 13, 5, 5},
! 943: { /*76*/ 2.6, 160000, 9400, 9, 17, 13, 5, 5},
! 944: { /*77*/ 2.6, 180000, 9600, 9, 17, 13, 5, 5},
! 945: { /*78*/ 2.6, 200000, 9800, 9, 17, 13, 5, 5},
! 946: { /*79*/ 2.65, 220000, 10000, 9, 18, 13, 5, 5},
! 947: { /*80*/ 2.65, 250000, 10500, 9, 18, 13, 5, 5},
! 948: /* entries below due to Thomas Denny */
! 949: { /*81*/ 3.1, 1500000, 16000, 9, 18, 15, 4, 4},
! 950: { /*82*/ 3.1, 1500000, 17000, 9, 18, 15, 4, 4},
! 951: { /*83*/ 3.1, 1500000, 18500, 9, 19, 16, 4, 4},
! 952: { /*84*/ 3.2, 1500000, 20000, 9, 19, 16, 4, 4},
! 953: { /*85*/ 3.2, 1500000, 21500, 9, 19, 16, 4, 4},
! 954: { /*86*/ 3.2, 1500000, 23000, 9, 19, 16, 4, 4},
! 955: { /*87*/ 3.2, 1500000, 25000, 9, 20, 17, 4, 4},
! 956: { /*88*/ 3.3, 1500000, 27000, 9, 20, 17, 4, 4},
! 957: { /*89*/ 3.3, 1500000, 28000, 9, 20, 17, 4, 4},
! 958: { /*90*/ 3.5, 2000000, 30500, 9, 20, 17, 2, 2},
! 959: { /*91*/ 3.6, 2000000, 32000, 9, 21, 18, 2, 2},
! 960: { /*92*/ 3.6, 2000000, 35000, 9, 21, 18, 2, 2},
! 961: { /*93*/ 3.7, 2000000, 37000, 9, 21, 18, 2, 2},
! 962: { /*94*/ 3.7, 2000000, 39500, 9, 22, 18, 2, 2},
! 963: { /*95*/ 3.7, 2500000, 41500, 9, 22, 18, 2, 2},
! 964: { /*96*/ 3.8, 2500000, 45000, 10, 23, 18, 2, 2},
! 965: { /*97*/ 3.8, 2500000, 47500, 10, 23, 18, 2, 2},
! 966: { /*98*/ 3.7, 3000000, 51000, 10, 24, 18, 2, 2},
! 967: { /*99*/ 3.8, 3000000, 53000, 10, 24, 18, 2, 2},
! 968: {/*100*/ 3.8, 3500000, 51000, 10, 25, 18, 2, 2},
! 969: {/*101*/ 3.8, 3500000, 54000, 10, 25, 18, 2, 2},
! 970: {/*102*/ 3.8, 3500000, 57000, 10, 26, 18, 2, 2},
! 971: {/*103*/ 3.9, 4000000, 61000, 10, 26, 18, 2, 2},
! 972: {/*104*/ 3.9, 4000000, 66000, 10, 27, 18, 2, 2},
! 973: {/*105*/ 3.9, 4000000, 70000, 10, 27, 18, 2, 2},
! 974: {/*106*/ 3.9, 4000000, 75000, 10, 28, 18, 2, 2},
! 975: {/*107*/ 3.9, 4000000, 80000, 10, 30, 18, 2, 2},
! 976: };
! 977:
! 978: /**
! 979: ** Return the appropriate parameters for the initialization of MPQS
! 980: **
! 981: ** the parameter table for mpqs has the following format:
! 982: **
! 983: ** [d -- decimal digits -- commented out]
! 984: ** e -- approximation accuracy
! 985: ** M -- size sieving interval
! 986: ** s -- size FB,
! 987: ** fA -- # prime factors in A
! 988: ** pA -- total # primes for determination of A,
! 989: ** [maxB -- how many Bs to use before choosing a new A -- determined by fA]
! 990: ** si -- initial sieving index
! 991: ** isoi -- initial sorting interval
! 992: ** fsoi -- followup sorting interval increment
! 993: **/
! 994:
! 995: static void
! 996: mpqs_read_parameters(ulong d, double *e, ulong *M, ulong *s, ulong *os,
! 997: ulong *fA, ulong *pA, long *maxB, ulong *si,
! 998: ulong *isoi, ulong *fsoi)
! 999: {
! 1000: long i = d;
! 1001: if (i < 9) i = 9;
! 1002: if (i > 107) i = 107;
! 1003: i -= 9;
! 1004:
! 1005: *e = mpqs_parameters[i][0];
! 1006: *M = (ulong)mpqs_parameters[i][1];
! 1007: *s = (ulong)mpqs_parameters[i][2];
! 1008: if (*s >= 200) *os = *s + 70;
! 1009: else *os = (ulong)(*s * 1.35);
! 1010: *fA = (ulong)mpqs_parameters[i][3];
! 1011: *pA = (ulong)mpqs_parameters[i][4];
! 1012: #if 0
! 1013: *maxB = (long) pow(2.0, mpqs_parameters[i][3] - 1.0);
! 1014: #else
! 1015: *maxB = 1l << (*fA - 1);
! 1016: #endif
! 1017: *si = (ulong)mpqs_parameters[i][5];
! 1018: *isoi = 10 * (ulong)mpqs_parameters[i][6]; /* percentages scaled by 10 */
! 1019: *fsoi = 10 * (ulong)mpqs_parameters[i][7];
! 1020: }
! 1021:
! 1022: /******************************/
! 1023:
! 1024: /**
! 1025: ** increment *x (!=0) to a larger value which has the same number of 1s
! 1026: ** in its binary representation. Cases which wrap around can be detected
! 1027: ** by the caller afterwards as long as we keep total_no_of_primes_for_A
! 1028: ** strictly less than BITS_IN_LONG.
! 1029: **
! 1030: ** Switch for the fast cases moved into here --GN
! 1031: **
! 1032: ** Changed switch to increment *x in all cases to the next larger number
! 1033: ** which (a) has the same count of 1 bits and (b) does not arise from the
! 1034: ** old value by moving a single 1 bit one position to the left (which was
! 1035: ** undesirable for the sieve). --GN based on discussion with TP
! 1036: **/
! 1037: static void
! 1038: mpqs_increment(ulong *x)
! 1039: {
! 1040: ulong r1_mask, r01_mask, slider=1;
! 1041:
! 1042: /* ultra-fast 32-way computed jump handles 22 out of 32 cases */
! 1043: switch (*x & 0x1f)
! 1044: {
! 1045: case 29:
! 1046: (*x)++; break; /* this does shift a single bit, but we'll
! 1047: postprocess this case */
! 1048: case 26:
! 1049: (*x) += 2; break; /* again */
! 1050: case 1: case 3: case 6: case 9: case 11:
! 1051: case 17: case 19: case 22: case 25: case 27:
! 1052: (*x) += 3; return;
! 1053: case 20:
! 1054: (*x) += 4; break; /* again */
! 1055: case 5: case 12: case 14: case 21:
! 1056: (*x) += 5; return;
! 1057: case 2: case 7: case 13: case 18: case 23:
! 1058: (*x) += 6; return;
! 1059: case 10:
! 1060: (*x) += 7; return;
! 1061: case 8:
! 1062: (*x) += 8; break; /* and again */
! 1063: case 4: case 15:
! 1064: (*x) += 12; return;
! 1065: default: /* 0, 16, 24, 28, 30, 31 */
! 1066: /* isolate rightmost 1 */
! 1067: r1_mask = ((*x ^ (*x - 1)) + 1) >> 1;
! 1068: /* isolate rightmost 1 which has a 0 to its left */
! 1069: r01_mask = ((*x ^ (*x + r1_mask)) + r1_mask) >> 2;
! 1070: /* simple cases. Both of these shift a single bit one position to the
! 1071: left, and will need postprocessing */
! 1072: if (r1_mask == r01_mask) { *x += r1_mask; break; }
! 1073: if (r1_mask == 1) { *x += r01_mask; break; }
! 1074: /* general case -- idea:
! 1075: add r01_mask, kill off as many 1 bits as possible to its right
! 1076: while at the same time filling in 1 bits from the LSB. */
! 1077: if (r1_mask == 2) { *x += (r01_mask>>1) + 1; return; }
! 1078: while (r01_mask > r1_mask && slider < r1_mask)
! 1079: {
! 1080: r01_mask >>= 1; slider <<= 1;
! 1081: }
! 1082: *x += r01_mask + slider - 1;
! 1083: return;
! 1084: }
! 1085: /* post-process all cases which couldn't be finalized above. If we get
! 1086: here, slider still has its original value. */
! 1087: r1_mask = ((*x ^ (*x - 1)) + 1) >> 1;
! 1088: r01_mask = ((*x ^ (*x + r1_mask)) + r1_mask) >> 2;
! 1089: if (r1_mask == r01_mask) { *x += r1_mask; return; }
! 1090: if (r1_mask == 1) { *x += r01_mask; return; }
! 1091: if (r1_mask == 2) { *x += (r01_mask>>1) + 1; return; }
! 1092: while (r01_mask > r1_mask && slider < r1_mask)
! 1093: {
! 1094: r01_mask >>= 1; slider <<= 1;
! 1095: }
! 1096: *x += r01_mask + slider - 1;
! 1097: return;
! 1098: }
! 1099:
! 1100: static long
! 1101: mpqs_invsmod(long b, long p)
! 1102: {
! 1103: long v1 = 0, v2 = 1, v3, r, oldp = p;
! 1104:
! 1105: while (b > 1)
! 1106: {
! 1107: v3 = v1 - (p / b) * v2; v1 = v2; v2 = v3;
! 1108: r = p % b; p = b; b = r;
! 1109: }
! 1110:
! 1111: if (v2 < 0) v2 += oldp;
! 1112: return v2;
! 1113: }
! 1114:
! 1115: /**
! 1116: ** compute coefficients of the sieving polynomial for self initializing
! 1117: ** variant. Coefficients A and B are returned and several tables are
! 1118: ** updated. See Thomas Sosnowski's diploma thesis.
! 1119: **/
! 1120:
! 1121: static void
! 1122: mpqs_self_init(GEN A, GEN B, GEN N, GEN kN, long *FB, long *sqrt_mod_p_kN,
! 1123: long *start_1, long *start_2, ulong no_of_primes_in_A,
! 1124: ulong total_no_of_primes_for_A, ulong M, long **inv_A_H_i,
! 1125: long *Q_prime, long *Q_prime_glob, GEN* H_i, long index_i,
! 1126: long start_index_FB_for_A, long *inv_A2, GEN inv_A4,
! 1127: ulong *bin_index, GEN *f)
! 1128: {
! 1129: long av;
! 1130: GEN p1, p2;
! 1131: ulong size_of_FB, nu_2;
! 1132: long i, j, p, M_mod_p, tmp, tmp1, tmp2;
! 1133:
! 1134: *f = NULL;
! 1135: if (index_i == 0)
! 1136: {
! 1137: /* compute first polynomial with new A */
! 1138: if (!*bin_index)
! 1139: {
! 1140: *bin_index = (1ul << no_of_primes_in_A) - 1;
! 1141: }
! 1142: else
! 1143: mpqs_increment(bin_index);
! 1144: if (*bin_index >= (1ul << total_no_of_primes_for_A)) /* wraparound */
! 1145: {
! 1146: if (DEBUGLEVEL >= 2)
! 1147: fprintferr("MPQS: bin_index wraparound\n");
! 1148: /* complain: caller should increase some parameters... */
! 1149: return;
! 1150: /* caller should repeat the above test; if we simply increase the
! 1151: total_no_of_primes_for_A, then bin_index now contains something
! 1152: suitable for carrying on -- we'll probably end up not using
! 1153: that particular index and skipping ahead to the next one, but
! 1154: this isn't a problem. OTOH total_no_of_primes_for_A should now
! 1155: be so large that this should never happen except for ridiculous
! 1156: input, like asking mpqs to factor 27, in which case it will act
! 1157: as a safeguard against an infinite loop --GN */
! 1158: }
! 1159:
! 1160: /* determine primes used for A in this iteration */
! 1161: for (i = 0, j = 0; (ulong)j < total_no_of_primes_for_A; j++)
! 1162: {
! 1163: if (*bin_index & (1 << j))
! 1164: {
! 1165: Q_prime[i] = Q_prime_glob[j];
! 1166: i++;
! 1167: }
! 1168: }
! 1169:
! 1170: /*
! 1171: * compute coefficient A using
! 1172: * A = prod (Q_prime[i], 0 < i < no_of_primes_in_A)
! 1173: */
! 1174:
! 1175: av = avma;
! 1176: p1 = stoi(Q_prime[0]);
! 1177: for (i = 1; (ulong)i < no_of_primes_in_A; i++)
! 1178: p1 = mulis(p1, Q_prime[i]);
! 1179: affii(p1, A);
! 1180: avma = av;
! 1181:
! 1182: /*
! 1183: * let bound := no_of_primes_in_A. Compute H_i, 0 <= i < bound.
! 1184: */
! 1185:
! 1186: for (i = 0; (ulong)i < no_of_primes_in_A; i++)
! 1187: {
! 1188: av = avma;
! 1189: p = Q_prime[i];
! 1190: p1 = divis(A, p);
! 1191: tmp = smodis(p1, p);
! 1192: p1 = mulis(p1, mpqs_invsmod(tmp, p));
! 1193: tmp = itos(mpsqrtmod(modis(kN, p), stoi(p)));
! 1194: p1 = mulis(p1, tmp);
! 1195: affii(modii(p1, A), H_i[i]);
! 1196: avma = av;
! 1197: }
! 1198:
! 1199: /*
! 1200: * Each B is of the form sum(v_i * H_i, 0 <= i < bound)
! 1201: * where each v_j is +1 or -1. This has to be done only once
! 1202: * (for index_i==0) for the coefficient A; if index_i > 0 then
! 1203: * there is a linear recursion for B
! 1204: */
! 1205:
! 1206: /* compute actual B coefficient, by taking all v_i == 1 */
! 1207: av = avma;
! 1208: p1 = H_i[0];
! 1209: for (i = 1; (ulong)i < no_of_primes_in_A; i++)
! 1210: p1 = addii(p1, H_i[i]);
! 1211: affii(p1, B);
! 1212: avma = av;
! 1213:
! 1214: /* ensure B = 1 mod 4 */
! 1215: if (mod2(B) == 0)
! 1216: {
! 1217: /* B += (A % 4) * A; */
! 1218: av = avma;
! 1219: p1 = addii(B, mulsi(mod4(A), A));
! 1220: affii(p1, B);
! 1221: avma = av;
! 1222: }
! 1223:
! 1224: /* compute inv_A2[i] = 1/(2*A) mod p_i */
! 1225: av = avma;
! 1226: p1 = shifti(A, 1);
! 1227: size_of_FB = FB[0] + 1;
! 1228: for (i = 2; (ulong)i <= size_of_FB; i++)
! 1229: inv_A2[i] = mpqs_invsmod(smodis(p1, FB[i]), FB[i]);
! 1230: avma = av;
! 1231:
! 1232: /* compute inv_A_H_i[i][j] = 1/A * H_i[i] mod p_j */
! 1233: for (i = 0; (ulong)i < no_of_primes_in_A; i++)
! 1234: {
! 1235: for (j = 2; (ulong)j <= size_of_FB; j++)
! 1236: {
! 1237: av = avma;
! 1238: p1 = mulis(H_i[i], inv_A2[j] << 1);
! 1239: inv_A_H_i[i][j] = smodis(p1, FB[j]);
! 1240: avma = av;
! 1241: }
! 1242: }
! 1243:
! 1244: /* compute the roots z1, z2, of the polynomial Q(x) mod p_j and
! 1245: * initialize start_1[i] with the first value p_i | Q(z1 + i p_j)
! 1246: * initialize start_2[i] with the first value p_i | Q(z2 + i p_j)
! 1247: */
! 1248: for (j = 2; (ulong)j <= size_of_FB; j++)
! 1249: {
! 1250: p = FB[j];
! 1251: M_mod_p = M % p;
! 1252:
! 1253: tmp = p - smodis(B, p); /* tmp = -B mod p */
! 1254:
! 1255: tmp1 = (tmp - sqrt_mod_p_kN[j]) % p;
! 1256: if (tmp1 < 0) tmp1 += p;
! 1257: tmp1 = mulssmod(tmp1, inv_A2[j], p);
! 1258: tmp1 = (tmp1 + M_mod_p) % p;
! 1259:
! 1260: tmp2 = (tmp + sqrt_mod_p_kN[j]) % p;
! 1261: if (tmp2 < 0) tmp2 += p;
! 1262: tmp2 = mulssmod(tmp2, inv_A2[j], p);
! 1263: tmp2 = (tmp2 + M_mod_p) % p;
! 1264:
! 1265: start_1[j] = (tmp1 < 0) ? tmp1 + p : tmp1;
! 1266: start_2[j] = (tmp2 < 0) ? tmp2 + p : tmp2;
! 1267: }
! 1268:
! 1269: /* determine 1/(4A) mod kN */
! 1270: av = avma;
! 1271: if (!invmod(shifti(A,2), kN, &p1)) /* --GN */
! 1272: {
! 1273: /* inv_A4 is a factor > 1 of kN. This cannot actually happen.
! 1274: Catch it anyway, it doesn't cost more than two comparisons
! 1275: against 0 / NULL */
! 1276: p1 = mppgcd(p1, N);
! 1277: *f = gerepileupto(av, p1);
! 1278: return; /* we certainly can't use the current poly */
! 1279: }
! 1280: affii(p1, inv_A4);
! 1281: avma = av;
! 1282: }
! 1283: else
! 1284: {
! 1285: /* no "real" computation -- use recursive formula
! 1286: * first: update of B, compute B[index_i], index_i > 0
! 1287: */
! 1288:
! 1289: /* compute nu_2 = nu_2(index_i) */
! 1290: nu_2 = 0;
! 1291: j = index_i;
! 1292: while ((j & 1) == 0)
! 1293: {
! 1294: nu_2++;
! 1295: j >>= 1;
! 1296: }
! 1297:
! 1298: av = avma;
! 1299: p1 = shifti(H_i[nu_2], 1);
! 1300:
! 1301: if ((((j+1)/2) & 1) == 1)
! 1302: {
! 1303: i = -1;
! 1304: p1 = subii(B, p1);
! 1305: }
! 1306: else
! 1307: {
! 1308: i = 1;
! 1309: p1 = addii(B, p1);
! 1310: }
! 1311: affii(p1, B);
! 1312: avma = av;
! 1313:
! 1314: /* determine new starting positions for sieving */
! 1315: size_of_FB = FB[0] + 1;
! 1316:
! 1317: if (i == -1)
! 1318: {
! 1319: for (j = 2; (ulong)j <= size_of_FB; j++)
! 1320: {
! 1321: p = FB[j];
! 1322: start_1[j] += inv_A_H_i[nu_2][j];
! 1323: if (start_1[j] >= p)
! 1324: start_1[j] -= p;
! 1325: start_2[j] += inv_A_H_i[nu_2][j];
! 1326: if (start_2[j] >= p)
! 1327: start_2[j] -= p;
! 1328: }
! 1329: }
! 1330: else
! 1331: {
! 1332: for (j = 2; (ulong)j <= size_of_FB; j++)
! 1333: {
! 1334: p = FB[j];
! 1335: start_1[j] -= inv_A_H_i[nu_2][j];
! 1336: if (start_1[j] < 0)
! 1337: start_1[j] += p;
! 1338: start_2[j] -= inv_A_H_i[nu_2][j];
! 1339: if (start_2[j] < 0)
! 1340: start_2[j] += p;
! 1341: }
! 1342: }
! 1343: }
! 1344:
! 1345: /* p=2 is a special case */
! 1346: if (FB[2] == 2)
! 1347: {
! 1348: start_1[2] = 0; start_2[2] = 1;
! 1349: }
! 1350:
! 1351:
! 1352: /* now compute zeros of polynomials that have only one zero mod p
! 1353: because p divides the coefficient A */
! 1354:
! 1355: /* compute coefficient -C */
! 1356: av = avma;
! 1357: p1 = subii(kN, sqri(B));
! 1358: p2 = divii(p1, shifti(A, 2));
! 1359:
! 1360: for (j = 1; (ulong)j <= total_no_of_primes_for_A; j++)
! 1361: if (*bin_index & (1 << (j-1)))
! 1362: {
! 1363: p = FB[start_index_FB_for_A + j];
! 1364: tmp = mpqs_invsmod(smodis(B, p), p);
! 1365: tmp2 = smodis (p2, p);
! 1366: tmp = mulssmod(tmp2, tmp, p);
! 1367: start_1[start_index_FB_for_A + j] =
! 1368: start_2[start_index_FB_for_A + j] = (tmp + M) % p;
! 1369: }
! 1370: avma = av;
! 1371:
! 1372: #ifdef MPQS_DEBUG
! 1373: {
! 1374: /*
! 1375: * check correctness of the roots z1, z2 mod p_i by evaluting
! 1376: * A * z1^2 + B * z1 + C mod p_i and checking against 0 mod p_i
! 1377: * C is written as (B*B-kN)/(4*A)
! 1378: */
! 1379: size_of_FB = FB[0] + 1;
! 1380: for (j = 3; j <= size_of_FB; j++)
! 1381: {
! 1382: av = avma;
! 1383: p = FB[j];
! 1384: M_mod_p = M % p;
! 1385:
! 1386: p1 = mulis(A, start_1[j] - M_mod_p);
! 1387: p1 = addii(p1, B);
! 1388: p1 = mulis(p1, start_1[j] - M_mod_p);
! 1389: p2 = divii(subii(sqri(B), kN), shifti(A, 2));
! 1390: p1 = addii(p1, p2);
! 1391: if (smodis(p1, p) != 0)
! 1392: {
! 1393: fprintferr("MPQS: (1) j = %ld p = %ld\n", j, p);
! 1394: fprintferr("MPQS: (1) index_i = %ld\n", index_i);
! 1395: fprintferr("MPQS: A = %Z\n", A);
! 1396: fprintferr("MPQS: B = %Z\n", B);
! 1397: fprintferr("MPQS: C = %Z\n", p1);
! 1398: fprintferr("MPQS: z1 = %ld\n", start_1[j] - M_mod_p);
! 1399: err(talker, "MPQS: self_init: found wrong polynomial in (1)");
! 1400: }
! 1401:
! 1402: p1 = mulis(A, start_2[j]-M_mod_p);
! 1403: p1 = addii(p1, B);
! 1404: p1 = mulis(p1, start_2[j]-M_mod_p);
! 1405: p2 = divii(subii(sqri(B), kN), shifti(A, 2));
! 1406: p1 = addii(p1, p2);
! 1407: if (smodis(p1, p) != 0)
! 1408: {
! 1409: fprintferr("MPQS: (2) j = %ld p = %ld\n", j, p);
! 1410: fprintferr("MPQS: (2) index_i = %ld\n", index_i);
! 1411: fprintferr("MPQS: A = %Z\n", A);
! 1412: fprintferr("MPQS: B = %Z\n", B);
! 1413: fprintferr("MPQS: C = %Z\n", p1);
! 1414: fprintferr("MPQS: z2 = %ld\n", start_2[j] - M_mod_p);
! 1415: err(talker, "MPQS: self_init: found wrong polynomial in (2)");
! 1416: }
! 1417: avma = av;
! 1418: }
! 1419: if (DEBUGLEVEL >= 4)
! 1420: fprintferr("MPQS: checking of roots of Q(x) was successful\n");
! 1421: }
! 1422: #endif
! 1423:
! 1424: }
! 1425:
! 1426: /******************************/
! 1427:
! 1428: /**
! 1429: ** Main sieving routine:
! 1430: **
! 1431: ** FB is a pointer to an array which holds the factor base
! 1432: ** log_FB is a pointer to an array which holds the approximations for
! 1433: ** the logarithms of the factor base elements
! 1434: ** start_1, start_2
! 1435: ** are arrays for starting points for different FB elements
! 1436: ** sieve_array
! 1437: ** points to a sieve array
! 1438: ** sieve_array_end
! 1439: ** points to the end of the sieve array
! 1440: ** M is the size of the sieving interval
! 1441: ** starting_sieving_index
! 1442: ** marks the first FB element which is used for sieving
! 1443: **
! 1444: **/
! 1445:
! 1446: #ifdef INLINE
! 1447: INLINE
! 1448: #endif
! 1449: void
! 1450: mpqs_sieve_p(unsigned char *begin, unsigned char *end,
! 1451: long p_times_4, long p, unsigned char log_p)
! 1452: {
! 1453: register unsigned char *e = end - p_times_4;
! 1454: while (e - begin >= 0) /* signed comparison --GN2000Jun02 */
! 1455: {
! 1456: (*begin) += log_p, begin += p;
! 1457: (*begin) += log_p, begin += p;
! 1458: (*begin) += log_p, begin += p;
! 1459: (*begin) += log_p, begin += p;
! 1460: }
! 1461: while (end - begin >= 0) /* again --GN2000Jun02 */
! 1462: (*begin) += log_p, begin += p;
! 1463: }
! 1464:
! 1465: static void
! 1466: mpqs_sieve(long *FB, unsigned char *log_FB, long *start_1, long *start_2,
! 1467: unsigned char *sieve_array, unsigned char *sieve_array_end,
! 1468: ulong M, ulong starting_sieving_index)
! 1469: {
! 1470: register long p_times_4, p, *ptr_FB, start1, start2, l;
! 1471: register unsigned char log_p;
! 1472:
! 1473: memset (sieve_array, 0, (M << 1) * sizeof (unsigned char));
! 1474:
! 1475: l = starting_sieving_index;
! 1476: ptr_FB = &FB[l];
! 1477:
! 1478: while ((p = *ptr_FB++) != 0)
! 1479: {
! 1480: p_times_4 = p * 4;
! 1481: log_p = log_FB[l];
! 1482: start1 = start_1[l];
! 1483: start2 = start_2[l];
! 1484:
! 1485: /* sieve with FB[l] from start_1[l] */
! 1486: /* if start1 != start2 sieve with FB[l] from start_2[l] */
! 1487: if (start1 == start2)
! 1488: mpqs_sieve_p(sieve_array + start1, sieve_array_end,
! 1489: p_times_4, p, log_p);
! 1490: else
! 1491: {
! 1492: mpqs_sieve_p(sieve_array + start1, sieve_array_end,
! 1493: p_times_4, p, log_p);
! 1494: mpqs_sieve_p(sieve_array + start2, sieve_array_end,
! 1495: p_times_4, p, log_p);
! 1496: }
! 1497:
! 1498: l++;
! 1499: }
! 1500: }
! 1501:
! 1502: /******************************/
! 1503:
! 1504: static long
! 1505: mpqs_eval_sieve(unsigned char *sieve_array, ulong M, long *candidates)
! 1506: {
! 1507: ulong M_2 = M << 1;
! 1508: int i = 0, count, q, r;
! 1509: unsigned char *ptr = sieve_array;
! 1510:
! 1511: r = M_2 % 4;
! 1512: q = M_2 - r;
! 1513: count = 0;
! 1514: for (i = 0; i < q; i += 4, ptr += 4)
! 1515: {
! 1516: if (*(ptr+0) > 128) { candidates[count] = i+0; count++; }
! 1517: if (*(ptr+1) > 128) { candidates[count] = i+1; count++; }
! 1518: if (*(ptr+2) > 128) { candidates[count] = i+2; count++; }
! 1519: if (*(ptr+3) > 128) { candidates[count] = i+3; count++; }
! 1520: }
! 1521: switch (r)
! 1522: {
! 1523: case 3:
! 1524: if (*(ptr+0) > 128) { candidates[count] = i+0; count++; }
! 1525: if (*(ptr+1) > 128) { candidates[count] = i+1; count++; }
! 1526: if (*(ptr+2) > 128) { candidates[count] = i+2; count++; }
! 1527: break;
! 1528: case 2:
! 1529: if (*(ptr+0) > 128) { candidates[count] = i+0; count++; }
! 1530: if (*(ptr+1) > 128) { candidates[count] = i+1; count++; }
! 1531: break;
! 1532: case 1:
! 1533: if (*(ptr+0) > 128) { candidates[count] = i+0; count++; }
! 1534: break;
! 1535: default:
! 1536: break;
! 1537: }
! 1538: candidates[count] = 0;
! 1539: return count;
! 1540: }
! 1541:
! 1542: /**
! 1543: ** Main relation routine:
! 1544: **
! 1545: ** FB is a pointer to an array which holds the factor base
! 1546: ** log_FB is a pointer to an array which holds the approximations for
! 1547: ** the logarithms of the factor base elements
! 1548: ** start_1, start_2
! 1549: ** are arrays for starting points for different FB elements
! 1550: ** M is the size of the sieving interval
! 1551: **
! 1552: **/
! 1553:
! 1554: #ifdef INLINE
! 1555: INLINE void
! 1556: mpqs_add_factor(char *s, ulong ei, ulong pi)
! 1557: {
! 1558: sprintf(s + strlen(s), " %lu %lu", ei, pi);
! 1559: }
! 1560: #else
! 1561: #define mpqs_add_factor(s,ei,pi) \
! 1562: sprintf(s + strlen(s), " %lu %lu", (ulong)ei, (ulong)pi)
! 1563: #endif
! 1564:
! 1565: /**
! 1566: ** divide and return the remainder. Leaves both the quotient and
! 1567: ** the remainder on the stack as GENs; the caller should clean up.
! 1568: **/
! 1569:
! 1570: #ifdef INLINE
! 1571: INLINE
! 1572: #else
! 1573: static
! 1574: #endif
! 1575: ulong
! 1576: mpqs_div_rem(GEN x, long y, GEN *q)
! 1577: {
! 1578: GEN r;
! 1579: *q = dvmdis(x, y, &r);
! 1580: if (signe(r)) return (ulong)(r[2]);
! 1581: return 0;
! 1582: }
! 1583:
! 1584: static long
! 1585: mpqs_eval_candidates(GEN A, GEN inv_A4, GEN B, GEN kN, long k,
! 1586: double sqrt_kN,
! 1587: long *FB, long *start_1, long *start_2,
! 1588: ulong M, long bin_index, long *candidates,
! 1589: long number_of_candidates, long lp_bound,
! 1590: long start_index_FB_for_A,
! 1591: FILE *FREL, FILE *LPREL)
! 1592: /* NB FREL, LPREL are actually FNEW, LPNEW when we get called */
! 1593: {
! 1594: GEN Qx, A_2x_plus_B, Y, Qx_div_p;
! 1595: double a, b, inv_2_a;
! 1596: long av, powers_of_2, p, tmp_p, remd_p, bi;
! 1597: long z1, z2, x, number_of_relations, x_minus_M;
! 1598: char *relations;
! 1599: ulong i, pi, ei, size_of_FB;
! 1600: int useless_cand;
! 1601: #ifdef MPQS_DEBUG_VERBOSE
! 1602: static char complaint[256], complaint0[256];
! 1603: #endif
! 1604:
! 1605: /* FIXME: this is probably right !!! */
! 1606:
! 1607: /*
! 1608: * compute the roots of Q(X); this will be used to find the sign of
! 1609: * Q(x) after reducing mod kN
! 1610: */
! 1611:
! 1612: a = gtodouble(A);
! 1613: inv_2_a = 1 / (2.0 * a);
! 1614: b = gtodouble(B);
! 1615: z1 = (long) ((-b - sqrt_kN) * inv_2_a);
! 1616: z2 = (long) ((-b + sqrt_kN) * inv_2_a);
! 1617:
! 1618: number_of_relations = 0;
! 1619: /* FIXME: this is definitely too loooooong ... */
! 1620: /* then take the size of the FB into account.
! 1621: We have in the worst case: a leading " 1 1", a trailing " 0\n" with
! 1622: the final NUL character, and in between up to size_of_FB pairs each
! 1623: consisting of an exponent, a subscript into FB, and two spaces.
! 1624: Moreover, subscripts into FB fit into 5 digits, and exponents fit
! 1625: into 3 digits with room to spare -- anything needing 3 or more digits
! 1626: for the subscript must come with an exponent of at most 2 digits.
! 1627: Moreover the product of the first 58 primes is larger than 10^110,
! 1628: so there cannot be more than 60 pairs in all, even if size_of_FB > 10^4.
! 1629: --GN */
! 1630: size_of_FB = FB[0]; /* one less than usually: don't count FB[1] */
! 1631: if (size_of_FB > 60) size_of_FB = 60;
! 1632: relations =
! 1633: (char *) gpmalloc((8 + size_of_FB * 9) * sizeof(char));
! 1634: #ifdef MPQS_DEBUG_VERBOSE
! 1635: complaint[0] = '\0';
! 1636: #endif
! 1637: #ifdef MPQS_DEBUG
! 1638: size_of_FB = FB[0] + 1; /* last useful subscript into FB */
! 1639: #endif
! 1640:
! 1641: i = 0;
! 1642: while (i < (ulong)number_of_candidates)
! 1643: {
! 1644: #ifdef MPQS_DEBUG_VERYVERBOSE /* this one really fills the screen... */
! 1645: fprintferr("%c", (char)('0' + i%10));
! 1646: #endif
! 1647: x = candidates[i++];
! 1648: relations[0] = '\0';
! 1649: av = avma;
! 1650:
! 1651: /* A_2x_plus_B = (A*(2x)+B), Qx = (A*(2x)+B)^2/(4*A) = Q(x) */
! 1652: x_minus_M = x - M;
! 1653: A_2x_plus_B = modii(addii(mulis(A, x_minus_M << 1), B), kN);
! 1654: Y = subii(kN, A_2x_plus_B);
! 1655: if (absi_cmp(A_2x_plus_B, Y) < 0) Y = A_2x_plus_B;
! 1656: /* absolute value of smallest absolute residue of A_2x_plus_B mod kN */
! 1657:
! 1658: Qx = modii(sqri(Y), kN);
! 1659:
! 1660: /* Most of the time, gcd(Qx, kN) will be either 1 or k. However,
! 1661: it may happen that Qx is a multiple of N, especially when N
! 1662: is small, and this will lead to havoc below -- so we have to be
! 1663: a little bit careful. Of course we cannot possibly afford to
! 1664: compute the gcd each time through this loop unless we are
! 1665: debugging... --GN */
! 1666: #ifdef MPQS_DEBUG
! 1667: {
! 1668: long av1 = avma, ks;
! 1669: GEN g = mppgcd(Qx, kN);
! 1670: /* if ((ks = kronecker(divii(Qx, g), divii(kN, g))) != 1) */
! 1671: if (is_pm1(g))
! 1672: {
! 1673: if ((ks = kronecker(Qx, kN)) != 1)
! 1674: {
! 1675: fprintferr("\nMPQS: 4*A*Q(x) = %Z\n", Qx);
! 1676: fprintferr("\tKronecker symbol %ld\n", ks);
! 1677: err(talker, "MPQS: 4*A*Q(x) is not a square (mod kN)");
! 1678: }
! 1679: }
! 1680: #ifdef MPQS_DEBUG_VERBOSE
! 1681: else if (cmpis(g,k) /* != 0 */ )
! 1682: {
! 1683: char *gs = GENtostr(g);
! 1684: sprintf(complaint, "\nMPQS: gcd(4*A*Q(x), kN) = %s\n", gs);
! 1685: free(gs);
! 1686: if (strcmp(complaint, complaint0) != 0)
! 1687: {
! 1688: fprintferr(complaint);
! 1689: strcpy(complaint0, complaint);
! 1690: }
! 1691: }
! 1692: #endif
! 1693: avma = av1;
! 1694: }
! 1695: #endif
! 1696:
! 1697: Qx = modii(mulii(Qx, inv_A4), kN);
! 1698:
! 1699: /* check the sign of Qx */
! 1700: if (z1 < x_minus_M && x_minus_M < z2)
! 1701: {
! 1702: Qx = subii(kN, Qx);
! 1703: /* i = 1, ei = 1, pi */
! 1704: mpqs_add_factor(relations, 1, 1);
! 1705: }
! 1706: if (!signe(Qx))
! 1707: {
! 1708: #ifdef MPQS_DEBUG_VERBOSE
! 1709: fprintferr("<+>");
! 1710: #endif
! 1711: avma = av;
! 1712: continue;
! 1713: }
! 1714:
! 1715: /* divide by powers of 2; note that we're really dealing with
! 1716: 4*A*Q(x), so we remember an extra factor 2^2 */
! 1717: powers_of_2 = vali(Qx);
! 1718: Qx = shifti(Qx, -powers_of_2);
! 1719: mpqs_add_factor(relations, powers_of_2 + 2, 2);
! 1720: if (!signe(Qx)) /* this shouldn't happen */
! 1721: {
! 1722: #ifdef MPQS_DEBUG_VERBOSE
! 1723: fprintferr("<*>");
! 1724: #endif
! 1725: avma = av;
! 1726: continue;
! 1727: }
! 1728:
! 1729: /* we handled the case p = 2 already */
! 1730: pi = 3;
! 1731: bi = bin_index;
! 1732: useless_cand = 0;
! 1733: #ifdef MPQS_DEBUG_VERBOSE
! 1734: fprintferr("a");
! 1735: #endif
! 1736:
! 1737: /* FB[3] .. FB[start_index_FB_for_A] do not divide A .
! 1738: * p = FB[start_index_FB_for_A+j+1] divides A (to the first power)
! 1739: * iff the 2^j bit in bin_index is set */
! 1740: while ((p = FB[pi]) != 0 && !useless_cand)
! 1741: {
! 1742: tmp_p = x % p;
! 1743:
! 1744: ei = 0;
! 1745: if (bi && pi > (ulong)start_index_FB_for_A)
! 1746: {
! 1747: ei = bi & 1; /* either 0 or 1 */
! 1748: bi >>= 1;
! 1749: }
! 1750:
! 1751: if (tmp_p == start_1[pi] || tmp_p == start_2[pi])
! 1752: {
! 1753: /* p divides Q(x) and possibly A */
! 1754: remd_p = mpqs_div_rem(Qx, p, &Qx_div_p);
! 1755: if (remd_p)
! 1756: {
! 1757: useless_cand = 1;
! 1758: break;
! 1759: }
! 1760: do
! 1761: {
! 1762: ei++;
! 1763: Qx = Qx_div_p;
! 1764: remd_p = mpqs_div_rem(Qx, p, &Qx_div_p);
! 1765: } while (remd_p == 0);
! 1766: }
! 1767: if (ei) /* p might divide A but not Q(x) */
! 1768: mpqs_add_factor(relations, ei, pi);
! 1769:
! 1770: pi++;
! 1771: }
! 1772:
! 1773: if (useless_cand)
! 1774: {
! 1775: #ifdef MPQS_DEBUG_VERBOSE
! 1776: fprintferr("\b<");
! 1777: #endif
! 1778: avma = av;
! 1779: continue;
! 1780: }
! 1781: #ifdef MPQS_DEBUG_VERBOSE
! 1782: fprintferr("\bb");
! 1783: #endif
! 1784:
! 1785: if (is_pm1(Qx))
! 1786: {
! 1787: char *Qxstring = GENtostr(Y);
! 1788: strcat(relations, " 0");
! 1789: fprintf(FREL, "%s :%s\n", Qxstring, relations);
! 1790: number_of_relations++;
! 1791:
! 1792: #ifdef MPQS_DEBUG
! 1793: {
! 1794: GEN Qx_2, prod_pi_ei, pi_ei;
! 1795: long lr = strlen(relations);
! 1796: char *s, *t = gpmalloc(lr+1);
! 1797: long pi, ei, av1 = avma;
! 1798:
! 1799: #ifdef MPQS_DEBUG_VERBOSE
! 1800: fprintferr("\b(");
! 1801: #endif
! 1802: Qx_2 = modii(sqri(Y), kN);
! 1803: prod_pi_ei = gun;
! 1804: strcpy(t, relations);
! 1805: s = strtok(relations, " \n");
! 1806: while (s != NULL)
! 1807: {
! 1808: ei = atol(s);
! 1809: if (ei == 0) break;
! 1810: s = strtok(NULL, " \n");
! 1811: pi = atol(s);
! 1812: pi_ei = powmodulo(stoi(FB[pi]), stoi(ei), kN);
! 1813: prod_pi_ei = modii(mulii(prod_pi_ei, pi_ei), kN);
! 1814: s = strtok(NULL, " \n");
! 1815: }
! 1816:
! 1817: if (!egalii(Qx_2, prod_pi_ei))
! 1818: {
! 1819: #ifdef MPQS_DEBUG_VERBOSE
! 1820: fprintferr("!)\n");
! 1821: #endif
! 1822: fprintferr("MPQS: %s :%s\n", Qxstring, t);
! 1823: fprintferr("\tQx_2 = %Z\n", Qx_2);
! 1824: fprintferr("\t rhs = %Z\n", prod_pi_ei);
! 1825: err(talker, "MPQS: wrong full relation found!!");
! 1826: }
! 1827: #ifdef MPQS_DEBUG_VERBOSE
! 1828: else
! 1829: fprintferr(":)");
! 1830: #endif
! 1831: avma = av1;
! 1832: free(t);
! 1833: }
! 1834: #endif
! 1835:
! 1836: free(Qxstring);
! 1837: }
! 1838: else if (cmpis(Qx, lp_bound) > 0)
! 1839: {
! 1840: /* TO BE DONE: check for double large prime */
! 1841: /* moved this else clause here where I think it belongs -- GN */
! 1842: #ifdef MPQS_DEBUG_VERBOSE
! 1843: fprintferr("\b.");
! 1844: #endif
! 1845: }
! 1846: else if (k==1 || cgcd(k, itos(Qx)) == 1)
! 1847: {
! 1848: /* if (mpqs_isprime(itos(Qx))) */
! 1849: char *Qxstring = GENtostr(Y);
! 1850: char *L1string = GENtostr(Qx);
! 1851: strcat(relations, " 0");
! 1852: fprintf(LPREL, "%s @ %s :%s\n", L1string, Qxstring, relations);
! 1853:
! 1854: #ifdef MPQS_DEBUG
! 1855: {
! 1856: GEN Qx_2, prod_pi_ei, pi_ei;
! 1857: long lr = strlen(relations);
! 1858: char *s, *t = gpmalloc(lr+1);
! 1859: long pi, ei, av1 = avma;
! 1860:
! 1861: #ifdef MPQS_DEBUG_VERBOSE
! 1862: fprintferr("\b(");
! 1863: #endif
! 1864: Qx_2 = modii(sqri(Y), kN);
! 1865: prod_pi_ei = gun;
! 1866: strcpy(t, relations);
! 1867: s = strtok(relations, " \n");
! 1868: while (s != NULL)
! 1869: {
! 1870: ei = atol(s);
! 1871: if (ei == 0) break;
! 1872: s = strtok(NULL, " \n");
! 1873: pi = atol(s);
! 1874: pi_ei = powmodulo(stoi(FB[pi]), stoi(ei), kN);
! 1875: prod_pi_ei = modii(mulii(prod_pi_ei, pi_ei), kN);
! 1876: s = strtok(NULL, " \n");
! 1877: }
! 1878: prod_pi_ei = modii(mulii(prod_pi_ei, Qx), kN);
! 1879:
! 1880: if (!egalii(Qx_2, prod_pi_ei))
! 1881: {
! 1882: #ifdef MPQS_DEBUG_VERBOSE
! 1883: fprintferr("!)\n");
! 1884: #endif
! 1885: fprintferr("MPQS: %s @ %s :%s\n",
! 1886: L1string, Qxstring, t);
! 1887: fprintferr("\tQx_2 = %Z\n", Qx_2);
! 1888: fprintferr("\t rhs = %Z\n", prod_pi_ei);
! 1889: err(talker, "MPQS: wrong large prime relation found!!");
! 1890: }
! 1891: #ifdef MPQS_DEBUG_VERBOSE
! 1892: else
! 1893: fprintferr(";)");
! 1894: #endif
! 1895: avma = av1;
! 1896: free(t);
! 1897: }
! 1898: #endif
! 1899:
! 1900: free(Qxstring);
! 1901: free(L1string);
! 1902: }
! 1903: #ifdef MPQS_DEBUG_VERBOSE
! 1904: else
! 1905: fprintferr("\b<k>");
! 1906: #endif
! 1907:
! 1908: avma = av;
! 1909: } /* while */
! 1910:
! 1911: #ifdef MPQS_DEBUG_VERBOSE
! 1912: fprintferr("\n");
! 1913: #endif
! 1914:
! 1915: free(relations);
! 1916: return number_of_relations;
! 1917: }
! 1918:
! 1919: /******************************/
! 1920:
! 1921: /**
! 1922: ** combines the large prime relations in COMB to full
! 1923: ** relations in FNEW. FNEW is assumed to be open for
! 1924: ** writing / appending.
! 1925: **/
! 1926:
! 1927: typedef struct
! 1928: {
! 1929: long q;
! 1930: char Y [MPQS_STRING_LENGTH];
! 1931: char ep [MPQS_STRING_LENGTH];
! 1932: } mpqs_lp_entry;
! 1933:
! 1934: static void
! 1935: mpqs_combine_exponents(long *ei, long ei_size, char *r1, char *r2)
! 1936: {
! 1937: char ej [MPQS_STRING_LENGTH], ek [MPQS_STRING_LENGTH];
! 1938: char *s;
! 1939: long e, p;
! 1940:
! 1941: memset(ei, 0, ei_size * sizeof(long));
! 1942: strcpy(ej, r1);
! 1943: strcpy(ek, r2);
! 1944:
! 1945: s = strtok(ej, " \n");
! 1946: while (s != NULL)
! 1947: {
! 1948: e = atol(s);
! 1949: if (e == 0)
! 1950: break;
! 1951: s = strtok(NULL, " \n");
! 1952: p = atol(s);
! 1953: ei[p] += e;
! 1954: s = strtok(NULL, " \n");
! 1955: }
! 1956:
! 1957: s = strtok(ek, " \n");
! 1958: while (s != NULL)
! 1959: {
! 1960: e = atol(s);
! 1961: if (e == 0)
! 1962: break;
! 1963: s = strtok(NULL, " \n");
! 1964: p = atol(s);
! 1965: ei[p] += e;
! 1966: s = strtok(NULL, " \n");
! 1967: }
! 1968:
! 1969: }
! 1970:
! 1971: static long
! 1972: mpqs_combine_large_primes(FILE *COMB, FILE *FNEW, long size_of_FB,
! 1973: GEN N, GEN kN, GEN *f
! 1974: #ifdef MPQS_DEBUG
! 1975: , long *FB
! 1976: #endif
! 1977: )
! 1978: {
! 1979: char buf [MPQS_STRING_LENGTH], *s1, *s2;
! 1980: char new_relation [MPQS_STRING_LENGTH];
! 1981: mpqs_lp_entry e[2]; /* we'll use the two alternatingly */
! 1982: long *ei, ei_size = size_of_FB + 2;
! 1983: long old_q;
! 1984: GEN inv_q, Y1, Y2, new_Y, new_Y1;
! 1985: long i, l, c = 0;
! 1986: long av = avma, av2;
! 1987:
! 1988: *f = NULL;
! 1989: if (fgets(buf, MPQS_STRING_LENGTH, COMB) == NULL)
! 1990: return 0; /* nothing there -- should not happen */
! 1991:
! 1992: /* put first lp relation in row 0 of e */
! 1993: s1 = buf; s2 = strchr(s1, ' '); *s2 = '\0';
! 1994: e[0].q = atol(s1);
! 1995: s1 = s2 + 3; s2 = strchr(s1, ' '); *s2 = '\0';
! 1996: strcpy(e[0].Y, s1);
! 1997: s1 = s2 + 3; s2 = strchr(s1, '\n'); *s2 = '\0';
! 1998: strcpy(e[0].ep, s1);
! 1999:
! 2000: i = 1; /* second relation will go into row 1 */
! 2001: old_q = e[0].q;
! 2002:
! 2003: while (!invmod(stoi(old_q), kN, &inv_q)) /* can happen --GN */
! 2004: {
! 2005: inv_q = mppgcd(inv_q, N);
! 2006: if (is_pm1(inv_q) || egalii(inv_q, N)) /* pity */
! 2007: {
! 2008: #ifdef MPQS_DEBUG
! 2009: fprintferr("MPQS: skipping relation with non-invertible q\n");
! 2010: #endif
! 2011: avma = av;
! 2012: if (fgets(buf, MPQS_STRING_LENGTH, COMB) == NULL)
! 2013: return 0;
! 2014: s1 = buf; s2 = strchr(s1, ' '); *s2 = '\0';
! 2015: e[0].q = atol(s1);
! 2016: s1 = s2 + 3; s2 = strchr(s1, ' '); *s2 = '\0';
! 2017: strcpy(e[0].Y, s1);
! 2018: s1 = s2 + 3; s2 = strchr(s1, '\n'); *s2 = '\0';
! 2019: strcpy(e[0].ep, s1);
! 2020: old_q = e[0].q;
! 2021: continue;
! 2022: }
! 2023: *f = gerepileupto(av, inv_q);
! 2024: return c;
! 2025: }
! 2026: Y1 = lisexpr(e[0].Y);
! 2027: av2 = avma; /* preserve inv_q and Y1 */
! 2028:
! 2029: ei = (long *) gpmalloc(ei_size * sizeof(long));
! 2030:
! 2031: while (fgets(buf, MPQS_STRING_LENGTH, COMB) != NULL)
! 2032: {
! 2033: s1 = buf; s2 = strchr(s1, ' '); *s2 = '\0';
! 2034: e[i].q = atol(s1);
! 2035: s1 = s2 + 3; s2 = strchr(s1, ' '); *s2 = '\0';
! 2036: strcpy(e[i].Y, s1);
! 2037: s1 = s2 + 3; s2 = strchr(s1, '\n'); *s2 = '\0';
! 2038: strcpy(e[i].ep, s1);
! 2039:
! 2040: if (e[i].q != old_q)
! 2041: {
! 2042: /* switch to combining a new bunch, swapping the rows */
! 2043: old_q = e[i].q;
! 2044: avma = av; /* discard old inv_q and Y1 */
! 2045: if (!invmod(stoi(old_q), kN, &inv_q)) /* can happen --GN */
! 2046: {
! 2047: inv_q = mppgcd(inv_q, N);
! 2048: if (is_pm1(inv_q) || egalii(inv_q, N)) /* pity */
! 2049: {
! 2050: #ifdef MPQS_DEBUG
! 2051: fprintferr("MPQS: skipping relation with non-invertible q\n");
! 2052: #endif
! 2053: avma = av;
! 2054: old_q = -1; /* sentinel */
! 2055: av2 = avma;
! 2056: continue; /* discard this combination */
! 2057: }
! 2058: *f = gerepileupto(av, inv_q);
! 2059: free (ei);
! 2060: return c;
! 2061: }
! 2062: Y1 = lisexpr(e[i].Y);
! 2063: i = 1 - i; /* subsequent relations go to other row */
! 2064: av2 = avma; /* preserve inv_q and Y1 */
! 2065: continue;
! 2066: }
! 2067: /* count and combine the two we've got, and continue in the same row */
! 2068: c++;
! 2069:
! 2070: mpqs_combine_exponents(ei, ei_size, e[1-i].ep, e[i].ep);
! 2071: if (DEBUGLEVEL >= 6)
! 2072: {
! 2073: fprintferr("MPQS: combining\n");
! 2074: fprintferr(" {%ld @ %s : %s}\n", old_q, e[1-i].Y, e[1-i].ep);
! 2075: fprintferr(" * {%ld @ %s : %s}\n", e[i].q, e[i].Y, e[i].ep);
! 2076: }
! 2077: Y2 = lisexpr(e[i].Y);
! 2078: new_Y = modii(mulii(mulii(Y1, Y2), inv_q), kN);
! 2079: new_Y1 = subii(kN, new_Y);
! 2080: if (absi_cmp(new_Y1, new_Y) < 0) new_Y = new_Y1;
! 2081: s1 = GENtostr(new_Y);
! 2082: strcpy(new_relation, s1);
! 2083: free(s1);
! 2084: strcat(new_relation, " :");
! 2085: if (ei[1] % 2)
! 2086: strcat(new_relation, " 1 1");
! 2087: for (l = 2; l < ei_size; l++)
! 2088: {
! 2089: if (ei[l])
! 2090: {
! 2091: sprintf(buf, " %ld %ld", ei[l], l);
! 2092: strcat(new_relation, buf);
! 2093: }
! 2094: }
! 2095: strcat(new_relation, " 0");
! 2096: if (DEBUGLEVEL >= 6) fprintferr(" == {%s}\n", new_relation);
! 2097: strcat(new_relation, "\n");
! 2098:
! 2099: #ifdef MPQS_DEBUG
! 2100: {
! 2101: char ejk [MPQS_STRING_LENGTH];
! 2102: GEN Qx_2, prod_pi_ei, pi_ei;
! 2103: char *s;
! 2104: long pi, exi, av1 = avma;
! 2105: Qx_2 = modii(sqri(new_Y), kN);
! 2106:
! 2107: strcpy(ejk, new_relation);
! 2108: s = strchr(ejk, ':') + 2;
! 2109: s = strtok(s, " \n");
! 2110:
! 2111: prod_pi_ei = gun;
! 2112: while (s != NULL)
! 2113: {
! 2114: exi = atol(s);
! 2115: if (exi == 0) break;
! 2116: s = strtok(NULL, " \n");
! 2117: pi = atol(s);
! 2118: pi_ei = powmodulo(stoi(FB[pi]), stoi(exi), kN);
! 2119: prod_pi_ei = modii(mulii(prod_pi_ei, pi_ei), kN);
! 2120: s = strtok(NULL, " \n");
! 2121: }
! 2122: avma = av1;
! 2123:
! 2124: if (!egalii(Qx_2, prod_pi_ei))
! 2125: {
! 2126: free(ei);
! 2127: err(talker,
! 2128: "MPQS: combined large prime relation is false");
! 2129: }
! 2130: }
! 2131: #endif
! 2132:
! 2133: if (fputs(new_relation, FNEW) < 0)
! 2134: {
! 2135: free(ei);
! 2136: bummer(FNEW_str);
! 2137: }
! 2138: avma = av2;
! 2139: } /* while */
! 2140:
! 2141: free(ei);
! 2142:
! 2143: if (DEBUGLEVEL >= 4)
! 2144: fprintferr("MPQS: combined %ld full relation%s\n",
! 2145: c, (c!=1 ? "s" : ""));
! 2146: return c;
! 2147: }
! 2148:
! 2149: /******************************/
! 2150:
! 2151: #ifdef LONG_IS_64BIT
! 2152:
! 2153: #define MPQS_GAUSS_BITS 64
! 2154: static unsigned long mpqs_mask_bit[] =
! 2155: {
! 2156: 0x8000000000000000UL, 0x4000000000000000UL,
! 2157: 0x2000000000000000UL, 0x1000000000000000UL,
! 2158: 0x0800000000000000UL, 0x0400000000000000UL,
! 2159: 0x0200000000000000UL, 0x0100000000000000UL,
! 2160: 0x0080000000000000UL, 0x0040000000000000UL,
! 2161: 0x0020000000000000UL, 0x0010000000000000UL,
! 2162: 0x0008000000000000UL, 0x0004000000000000UL,
! 2163: 0x0002000000000000UL, 0x0001000000000000UL,
! 2164: 0x0000800000000000UL, 0x0000400000000000UL,
! 2165: 0x0000200000000000UL, 0x0000100000000000UL,
! 2166: 0x0000080000000000UL, 0x0000040000000000UL,
! 2167: 0x0000020000000000UL, 0x0000010000000000UL,
! 2168: 0x0000008000000000UL, 0x0000004000000000UL,
! 2169: 0x0000002000000000UL, 0x0000001000000000UL,
! 2170: 0x0000000800000000UL, 0x0000000400000000UL,
! 2171: 0x0000000200000000UL, 0x0000000100000000UL,
! 2172: 0x0000000080000000UL, 0x0000000040000000UL,
! 2173: 0x0000000020000000UL, 0x0000000010000000UL,
! 2174: 0x0000000008000000UL, 0x0000000004000000UL,
! 2175: 0x0000000002000000UL, 0x0000000001000000UL,
! 2176: 0x0000000000800000UL, 0x0000000000400000UL,
! 2177: 0x0000000000200000UL, 0x0000000000100000UL,
! 2178: 0x0000000000080000UL, 0x0000000000040000UL,
! 2179: 0x0000000000020000UL, 0x0000000000010000UL,
! 2180: 0x0000000000008000UL, 0x0000000000004000UL,
! 2181: 0x0000000000002000UL, 0x0000000000001000UL,
! 2182: 0x0000000000000800UL, 0x0000000000000400UL,
! 2183: 0x0000000000000200UL, 0x0000000000000100UL,
! 2184: 0x0000000000000080UL, 0x0000000000000040UL,
! 2185: 0x0000000000000020UL, 0x0000000000000010UL,
! 2186: 0x0000000000000008UL, 0x0000000000000004UL,
! 2187: 0x0000000000000002UL, 0x0000000000000001UL
! 2188: };
! 2189:
! 2190: #else
! 2191:
! 2192: #define MPQS_GAUSS_BITS 32
! 2193: static unsigned long mpqs_mask_bit[] =
! 2194: {
! 2195: 0x80000000UL, 0x40000000UL, 0x20000000UL, 0x10000000UL,
! 2196: 0x08000000UL, 0x04000000UL, 0x02000000UL, 0x01000000UL,
! 2197: 0x00800000UL, 0x00400000UL, 0x00200000UL, 0x00100000UL,
! 2198: 0x00080000UL, 0x00040000UL, 0x00020000UL, 0x00010000UL,
! 2199: 0x00008000UL, 0x00004000UL, 0x00002000UL, 0x00001000UL,
! 2200: 0x00000800UL, 0x00000400UL, 0x00000200UL, 0x00000100UL,
! 2201: 0x00000080UL, 0x00000040UL, 0x00000020UL, 0x00000010UL,
! 2202: 0x00000008UL, 0x00000004UL, 0x00000002UL, 0x00000001UL
! 2203: };
! 2204:
! 2205: #endif
! 2206:
! 2207: static mpqs_gauss_matrix
! 2208: mpqs_gauss_create_matrix(long rows, long cols)
! 2209: {
! 2210: mpqs_gauss_matrix m;
! 2211: long i, j, words = cols / MPQS_GAUSS_BITS;
! 2212: if (cols % MPQS_GAUSS_BITS)
! 2213: words++;
! 2214: m = (mpqs_gauss_row *) gpmalloc(rows * sizeof(mpqs_gauss_row));
! 2215: for (i = 0; i < rows; i++)
! 2216: {
! 2217: m[i] = (ulong *) gpmalloc(words * sizeof(ulong));
! 2218: for (j = 0; j < words; j++)
! 2219: m[i][j] = 0UL;
! 2220: }
! 2221: return m;
! 2222: }
! 2223:
! 2224: static void
! 2225: mpqs_gauss_destroy_matrix(mpqs_gauss_matrix m, long rows, long cols)
! 2226: {
! 2227: long i;
! 2228: (void) cols;
! 2229: for (i = 0; i < rows; i++)
! 2230: free(m[i]);
! 2231: free(m);
! 2232: }
! 2233:
! 2234: static ulong
! 2235: mpqs_gauss_get_bit(mpqs_gauss_matrix m, long i, long j)
! 2236: {
! 2237: return m[i][j / MPQS_GAUSS_BITS] & mpqs_mask_bit[j % MPQS_GAUSS_BITS];
! 2238: }
! 2239:
! 2240: static void
! 2241: mpqs_gauss_set_bit(mpqs_gauss_matrix m, long i, long j)
! 2242: {
! 2243: m[i][j / MPQS_GAUSS_BITS] |= mpqs_mask_bit[j % MPQS_GAUSS_BITS];
! 2244: }
! 2245:
! 2246: static void
! 2247: mpqs_gauss_clear_bit(mpqs_gauss_matrix m, long i, long j)
! 2248: {
! 2249: m[i][j / MPQS_GAUSS_BITS] &= ~mpqs_mask_bit[j % MPQS_GAUSS_BITS];
! 2250: }
! 2251:
! 2252: /* output an mpqs_gauss_matrix in PARI format */
! 2253: /* TODO -- this should do a little intelligent wrapping... GN */
! 2254: static void
! 2255: mpqs_gauss_print_matrix(mpqs_gauss_matrix m, long rows, long cols)
! 2256: {
! 2257: long i, j;
! 2258: fprintferr("\n[");
! 2259: for (i = 0; i < rows; i++)
! 2260: {
! 2261: for (j = 0; j < cols - 1; j++)
! 2262: {
! 2263: if (mpqs_gauss_get_bit(m, i, j))
! 2264: fprintferr("1, ");
! 2265: else
! 2266: fprintferr("0, ");
! 2267: }
! 2268:
! 2269: if (mpqs_gauss_get_bit(m, i, j))
! 2270: fprintferr("1");
! 2271: else
! 2272: fprintferr("0");
! 2273: if (i != rows - 1)
! 2274: fprintferr("; ");
! 2275: }
! 2276: fprintferr("]\n");
! 2277: }
! 2278:
! 2279: /* x ^= y : row addition over F_2 */
! 2280: static void
! 2281: mpqs_gauss_add_rows(mpqs_gauss_row y, mpqs_gauss_row x, long k, long n)
! 2282: {
! 2283: long i, q, r;
! 2284: n = n - k;
! 2285: r = n % 8; q = n - r + k; i = 0 + k;
! 2286: for (; i < q; i += 8)
! 2287: {
! 2288: x[0+i] ^= y[0+i]; x[1+i] ^= y[1+i];
! 2289: x[2+i] ^= y[2+i]; x[3+i] ^= y[3+i];
! 2290: x[4+i] ^= y[4+i]; x[5+i] ^= y[5+i];
! 2291: x[6+i] ^= y[6+i]; x[7+i] ^= y[7+i];
! 2292: }
! 2293: switch (r)
! 2294: {
! 2295: case 7: x[i] ^= y[i], i++;
! 2296: case 6: x[i] ^= y[i], i++;
! 2297: case 5: x[i] ^= y[i], i++;
! 2298: case 4: x[i] ^= y[i], i++;
! 2299: case 3: x[i] ^= y[i], i++;
! 2300: case 2: x[i] ^= y[i], i++;
! 2301: case 1: x[i] ^= y[i], i++;
! 2302: default: ;
! 2303: }
! 2304: }
! 2305:
! 2306: /* create and read an mpqs_gauss_matrix from a relation file FREL (opened
! 2307: by caller). Also record the position of each relation in the file for
! 2308: later use
! 2309: rows = size_of_FB+1, cols = rel */
! 2310: static mpqs_gauss_matrix
! 2311: mpqs_gauss_read_matrix(FILE *FREL, long rows, long cols, long *fpos)
! 2312: {
! 2313: mpqs_gauss_matrix m;
! 2314: long i = 0, e, p;
! 2315: char buf[MPQS_STRING_LENGTH], *s;
! 2316:
! 2317: m = mpqs_gauss_create_matrix(rows, cols);
! 2318: if ((fpos[0] = ftell(FREL)) < 0)
! 2319: err(talker, "ftell error on full relations file");
! 2320: while (fgets(buf, MPQS_STRING_LENGTH, FREL) != NULL)
! 2321: {
! 2322: s = strchr(buf, ':') + 2;
! 2323: s = strtok(s, " \n");
! 2324: while (s != NULL)
! 2325: {
! 2326: e = atol(s);
! 2327: if (e == 0)
! 2328: break;
! 2329: s = strtok(NULL, " \n");
! 2330: p = atol(s);
! 2331: if (e & 1)
! 2332: mpqs_gauss_set_bit(m, p - 1, i);
! 2333: s = strtok(NULL, " \n");
! 2334: }
! 2335: i++;
! 2336: if (i < cols && (fpos[i] = ftell(FREL)) < 0)
! 2337: err(talker, "ftell error on full relations file");
! 2338: }
! 2339: if (i != cols)
! 2340: {
! 2341: fprintferr("MPQS: full relations file %s than expected",
! 2342: i > cols ? "longer" : "shorter");
! 2343: err(talker, "MPQS panicking");
! 2344: }
! 2345: return m;
! 2346: }
! 2347:
! 2348: /* compute the kernel of an mpqs_gauss_matrix over F_2
! 2349: uses the algorithm described by Knuth, Vol. 2 as modified by Henri Cohen
! 2350: and optimized by Christian Batut, Thomas Papanikolaou and Xavier Roblot.
! 2351: m = rows, n = cols */
! 2352: static mpqs_gauss_matrix
! 2353: mpqs_kernel(mpqs_gauss_matrix x, long m, long n, long *rank)
! 2354: {
! 2355: long k, i, j, t, r;
! 2356: mpqs_gauss_matrix ker_x;
! 2357: mpqs_gauss_indices c, d;
! 2358: long words = n / MPQS_GAUSS_BITS;
! 2359: if (n % MPQS_GAUSS_BITS)
! 2360: words++;
! 2361:
! 2362: c = (long *) gpmalloc(m * sizeof(long));
! 2363: for (k = 0; k < m; k++) c[k] = -1;
! 2364:
! 2365: d = (long *) gpmalloc(n * sizeof(long));
! 2366: r = 0;
! 2367:
! 2368: for (k = 0; k < n; k++)
! 2369: {
! 2370: j = 0;
! 2371: while (j < m && (c[j] >= 0 || mpqs_gauss_get_bit(x, j, k) == 0))
! 2372: j++;
! 2373:
! 2374: if (j == m)
! 2375: {
! 2376: d[k] = -1; /* no pivot found in column k */
! 2377: r++; /* column k is a vector of the kernel */
! 2378: }
! 2379: else
! 2380: {
! 2381: d[k] = j; /* the pivot in column k is at row j */
! 2382: c[j] = k; /* a pivot at position j was found in column k */
! 2383: for (t = 0; t < m; t++)
! 2384: {
! 2385: if (t != j)
! 2386: {
! 2387: if (mpqs_gauss_get_bit(x, t, k))
! 2388: mpqs_gauss_add_rows(x[j], x[t], k / MPQS_GAUSS_BITS, words);
! 2389: }
! 2390: }
! 2391: }
! 2392: }
! 2393:
! 2394: ker_x = mpqs_gauss_create_matrix(n, r);
! 2395:
! 2396: for (j = k = 0; j < r; j++, k++)
! 2397: {
! 2398: while (d[k] != -1) k++;
! 2399: for (i = 0; i < k; i++)
! 2400: {
! 2401: if (d[i] != -1)
! 2402: {
! 2403: if (mpqs_gauss_get_bit(x, d[i], k))
! 2404: mpqs_gauss_set_bit(ker_x, i, j);
! 2405: else
! 2406: mpqs_gauss_clear_bit(ker_x, i, j);
! 2407: }
! 2408: else
! 2409: mpqs_gauss_clear_bit(ker_x, i, j);
! 2410: }
! 2411: mpqs_gauss_set_bit(ker_x, k, j);
! 2412: }
! 2413:
! 2414: free(c);
! 2415: free(d);
! 2416:
! 2417: *rank = r;
! 2418: return ker_x;
! 2419: }
! 2420:
! 2421: /******************************/
! 2422:
! 2423: static GEN
! 2424: mpqs_add_relation(GEN Y_prod, GEN N_or_kN, long *ei, char *r1)
! 2425: {
! 2426: GEN Y, res;
! 2427: char relation [MPQS_STRING_LENGTH];
! 2428: char *s;
! 2429: long av = avma, e, p;
! 2430:
! 2431: strcpy(relation, r1);
! 2432: s = strchr(relation, ':') - 1;
! 2433: *s = '\0';
! 2434: Y = lisexpr(relation);
! 2435: res = modii(mulii(Y_prod, Y), N_or_kN);
! 2436:
! 2437: s = s + 3;
! 2438: s = strtok(s, " \n");
! 2439: while (s != NULL)
! 2440: {
! 2441: e = atol(s);
! 2442: if (e == 0)
! 2443: break;
! 2444: s = strtok(NULL, " \n");
! 2445: p = atol(s);
! 2446: ei[p] += e;
! 2447: s = strtok(NULL, " \n");
! 2448: }
! 2449: return gerepileupto(av,res);
! 2450: }
! 2451:
! 2452: static char*
! 2453: mpqs_get_relation(long pos, FILE *FREL)
! 2454: {
! 2455: static char buf [MPQS_STRING_LENGTH];
! 2456: if (fseek(FREL, pos, SEEK_SET))
! 2457: err(talker, "can\'t seek full relations file");
! 2458: if (fgets(buf, MPQS_STRING_LENGTH, FREL) == NULL)
! 2459: err(talker, "full relations file truncated?!");
! 2460: return buf;
! 2461: }
! 2462:
! 2463: /* the following two reside in src/basemath/ifactor1.c */
! 2464: long is_odd_power(GEN x, GEN *pt, long *mask);
! 2465: int miller(GEN n, long k);
! 2466:
! 2467: #define isprobableprime(n) (miller((n),17))
! 2468:
! 2469: static GEN
! 2470: mpqs_solve_linear_system(GEN kN, GEN N, long rel, long *FB, long size_of_FB)
! 2471: {
! 2472: pariFILE *pFREL;
! 2473: FILE *FREL;
! 2474: GEN X, Y_prod, N_or_kN, D1, base, res, new_res;
! 2475: long av=avma, av2, av3, lim, lim3, tetpil;
! 2476: long *fpos, *ei;
! 2477: long i, j, H_cols, H_rows;
! 2478: long res_last, res_next, res_size, res_max;
! 2479: mpqs_gauss_matrix m, ker_m;
! 2480: long done, flag, mask, rank;
! 2481:
! 2482: #ifdef MPQS_DEBUG
! 2483: N_or_kN = kN;
! 2484: #else
! 2485: N_or_kN = (DEBUGLEVEL >= 4 ? kN : N);
! 2486: #endif /* --GN */
! 2487: pFREL = pari_fopen(FREL_str, READ);
! 2488: FREL = pFREL->file;
! 2489: fpos = (long *) gpmalloc(rel * sizeof(long));
! 2490:
! 2491: m = mpqs_gauss_read_matrix(FREL, size_of_FB+1, rel, fpos);
! 2492: if (DEBUGLEVEL >= 7)
! 2493: {
! 2494: fprintferr("\\\\ MATRIX READ BY MPQS\nFREL=");
! 2495: mpqs_gauss_print_matrix(m, size_of_FB+1, rel);
! 2496: fprintferr("\n");
! 2497: }
! 2498:
! 2499: ker_m = mpqs_kernel(m, size_of_FB+1, rel, &rank);
! 2500: if (DEBUGLEVEL >= 4)
! 2501: {
! 2502: if (DEBUGLEVEL >= 7)
! 2503: {
! 2504: fprintferr("\\\\ KERNEL COMPUTED BY MPQS\nKERNEL=");
! 2505: mpqs_gauss_print_matrix(ker_m, rel, rank);
! 2506: fprintferr("\n");
! 2507: }
! 2508: /* put this here where the poor user has a chance of seeing it: */
! 2509: fprintferr("MPQS: Gauss done: kernel has rank %ld, taking gcds...\n",
! 2510: rank);
! 2511: }
! 2512:
! 2513: H_rows = rel;
! 2514: H_cols = rank;
! 2515:
! 2516: /* If the computed kernel turns out to be trivial, fail gracefully;
! 2517: main loop may try to find some more relations --GN */
! 2518: if (H_cols == 0)
! 2519: {
! 2520: if (DEBUGLEVEL >= 3)
! 2521: err(warner, "MPQS: no solutions found from linear system solver");
! 2522: /* ei has not yet been allocated */
! 2523: mpqs_gauss_destroy_matrix(m, size_of_FB+1, rel);
! 2524: mpqs_gauss_destroy_matrix(ker_m, rel, rank);
! 2525: free(fpos);
! 2526: pari_fclose(pFREL);
! 2527: avma = av;
! 2528: return NULL; /* no factors found */
! 2529: }
! 2530:
! 2531: /* If the rank is r, we can expect up to 2^r pairwise coprime factors,
! 2532: but it may well happen that a kernel basis vector contributes nothing
! 2533: new to the decomposition. We will allocate room for up to eight factors
! 2534: initially (certainly adequate when one or two basis vectors work),
! 2535: adjusting this down at the end to what we actually found, or up if
! 2536: we are very lucky and find more factors. In the upper half of our
! 2537: vector, we store information about which factors we know to be composite
! 2538: (zero) or believe to be composite ((long)NULL which is just 0) or suspect
! 2539: to be prime (un), or an exponent (deux or some t_INT) if it is a proper
! 2540: power */
! 2541: av2 = avma; lim = stack_lim(av2,1);
! 2542: if (rank > BITS_IN_LONG - 2)
! 2543: res_max = VERYBIGINT; /* this, unfortunately, is the common case */
! 2544: else
! 2545: res_max = 1L<<rank; /* max number of factors we can hope for */
! 2546: res_size = 8; /* no. of factors we can store in this res */
! 2547: res = cgetg(2*res_size+1, t_VEC);
! 2548: for (i=2*res_size; i; i--) res[i] = 0;
! 2549: res_next = res_last = 1;
! 2550:
! 2551: ei = (long *) gpmalloc((size_of_FB + 2) * sizeof(long));
! 2552:
! 2553: for (i = 0; i < H_cols; i++) /* loop over basis of kernel */
! 2554: {
! 2555: X = Y_prod = gun;
! 2556: memset(ei, 0, (size_of_FB + 2) * sizeof(long));
! 2557:
! 2558: av3 = avma; lim3 = stack_lim(av3,1);
! 2559: for (j = 0; j < H_rows; j++)
! 2560: {
! 2561: if (mpqs_gauss_get_bit(ker_m, j, i))
! 2562: Y_prod = mpqs_add_relation(Y_prod, N_or_kN, ei,
! 2563: mpqs_get_relation(fpos[j], FREL));
! 2564: if (low_stack(lim3, stack_lim(av3,1)))
! 2565: {
! 2566: if(DEBUGMEM>1) err(warnmem,"[1]: mpqs_solve_linear_system");
! 2567: Y_prod = gerepileupto(av3, Y_prod);
! 2568: }
! 2569: }
! 2570: Y_prod = gerepileupto(av3, Y_prod); /* unconditionally */
! 2571:
! 2572: av3 = avma; lim3 = stack_lim(av3,1);
! 2573: for (j = 2; j <= (size_of_FB + 1); j++)
! 2574: {
! 2575: if (ei[j] & 1)
! 2576: { /* this cannot happen --GN */
! 2577: mpqs_gauss_destroy_matrix(m, size_of_FB+1, rel);
! 2578: mpqs_gauss_destroy_matrix(ker_m, rel, rank);
! 2579: free(ei); free(fpos);
! 2580: fprintferr("MPQS: the combination of the relations is a nonsquare\n");
! 2581: err(bugparier, "factoring (MPQS)");
! 2582: }
! 2583: if (ei[j])
! 2584: {
! 2585: X = modii(mulii(X, powmodulo(stoi(FB[j]), stoi(ei[j]>>1), N_or_kN)),
! 2586: N_or_kN);
! 2587: if (low_stack(lim3, stack_lim(av3,1)))
! 2588: {
! 2589: if(DEBUGMEM>1) err(warnmem,"[2]: mpqs_solve_linear_system");
! 2590: X = gerepileupto(av3, X);
! 2591: }
! 2592: }
! 2593: }
! 2594: X = gerepileupto(av3, X); /* unconditionally */
! 2595: if (
! 2596: #ifdef MPQS_DEBUG
! 2597: 1 ||
! 2598: #endif
! 2599: DEBUGLEVEL >= 1)
! 2600: { /* this shouldn't happen either --GN */
! 2601: if (signe(modii(subii(sqri(X), sqri(Y_prod)), N_or_kN)))
! 2602: {
! 2603: fprintferr("MPQS: X^2 - Y^2 != 0 mod %s\n",
! 2604: (N_or_kN == kN ? "kN" : "N"));
! 2605: fprintferr("\tindex i = %ld\n", i);
! 2606: err(warner, "MPQS: wrong relation found after Gauss");
! 2607: }
! 2608: }
! 2609: /* if res_next < 3, we still haven't decomposed the original N, and
! 2610: will want both a gcd and its cofactor, overwriting N. Note that
! 2611: gcd(X+Y_prod,N)==1 forces gcd(X-Y_prod,N)==N, so we can skip X-Y_prod
! 2612: in such cases */
! 2613: done = 0; /* (re-)counts probably-prime factors
! 2614: (or powers whose bases we don't want to
! 2615: handle any further) */
! 2616: if (res_next < 3)
! 2617: {
! 2618: D1 = mppgcd(addii(X,Y_prod),N);
! 2619: if (!is_pm1(D1))
! 2620: {
! 2621: if ((flag = egalii(D1, N))) /* assignment */
! 2622: /* this one's useless, try the other one */
! 2623: D1 = mppgcd(subii(X,Y_prod),N);
! 2624: if (!flag || (!is_pm1(D1) && !egalii(D1,N)))
! 2625: { /* got something that works */
! 2626: if (DEBUGLEVEL >= 5)
! 2627: fprintferr("MPQS: splitting N after %ld kernel vector%s\n",
! 2628: i+1, (i? "s" : ""));
! 2629: (void)mpdivis(N, D1, N); /* divide N in place */
! 2630: res[1] = (long)N; /* we'll gcopy this anyway before exiting */
! 2631: res[2] = (long)D1;
! 2632: res_last = res_next = 3;
! 2633: if (res_max == 2) break; /* two out of two possible factors seen */
! 2634: mask = 7;
! 2635: /* (actually, 5th/7th powers aren't really worth the trouble. OTOH
! 2636: once we have the hooks for dealing with cubes, higher powers can
! 2637: be handled essentially for free) */
! 2638: if (isprobableprime(N)) { done++; res[res_size+1] = un; }
! 2639: else if (carrecomplet(N, &base))
! 2640: { /* squares could cost us a lot of time */
! 2641: affii(base, N); done++; res[res_size+1] = deux;
! 2642: if (DEBUGLEVEL >= 5)
! 2643: fprintferr("MPQS: decomposed a square\n");
! 2644: }
! 2645: else if ((flag = is_odd_power(N, &base, &mask))) /* assignment */
! 2646: {
! 2647: affii(base, N); done++; res[res_size+1] = (long)(stoi(flag));
! 2648: if (DEBUGLEVEL >= 5)
! 2649: fprintferr("MPQS: decomposed a %s\n",
! 2650: (flag == 3 ? "cube" :
! 2651: (flag == 5 ? "5th power" : "7th power")));
! 2652: }
! 2653: else res[res_size+1] = zero; /* known composite */
! 2654: mask = 7;
! 2655: if (isprobableprime(D1)) { done++; res[res_size+2] = un; }
! 2656: else if (carrecomplet(D1, &base))
! 2657: {
! 2658: res[2] = (long)base;
! 2659: done++; res[res_size+2] = deux;
! 2660: if (DEBUGLEVEL >= 5)
! 2661: fprintferr("MPQS: decomposed a square\n");
! 2662: }
! 2663: else if ((flag = is_odd_power(D1, &base, &mask))) /* assignment */
! 2664: {
! 2665: res[2] = (long)base;
! 2666: done++; res[res_size+2] = (long)(stoi(flag));
! 2667: if (DEBUGLEVEL >= 5)
! 2668: fprintferr("MPQS: decomposed a %s\n",
! 2669: (flag == 3 ? "cube" :
! 2670: (flag == 5 ? "5th power" : "7th power")));
! 2671: }
! 2672: else res[res_size+2] = zero; /* known composite */
! 2673: if (done == 2) break; /* both factors look prime or were powers */
! 2674: if (DEBUGLEVEL >= 5)
! 2675: fprintferr("MPQS: got two factors, looking for more...\n");
! 2676: /* and loop (after collecting garbage if necessary) */
! 2677: } /* else loop to next kernel basis vector */
! 2678: } /* D1!=1, nothing to be done when ==1 */
! 2679: }
! 2680: else /* we already have factors */
! 2681: {
! 2682: GEN X_plus_Y = addii(X, Y_prod);
! 2683: GEN X_minus_Y = NULL; /* will only be computed when needed */
! 2684: for (j=1; j < res_next; j++)
! 2685: { /* loop over known-composite factors */
! 2686: if (res[res_size+j] && res[res_size+j] != zero)
! 2687: {
! 2688: done++; continue; /* skip probable primes etc */
! 2689: }
! 2690: /* (actually, also skip square roots of squares etc. They are
! 2691: necessarily a lot smaller than the original N, and should
! 2692: be easy to deal with later) */
! 2693: av3 = avma;
! 2694: D1 = mppgcd(X_plus_Y, (GEN)(res[j]));
! 2695: if (is_pm1(D1)) continue; /* this one doesn't help us */
! 2696: if ((flag = egalii(D1, (GEN)(res[j]))))
! 2697: { /* bad one, try the other */
! 2698: avma = av3;
! 2699: if (!X_minus_Y) X_minus_Y = subii(X, Y_prod);
! 2700: av3 = avma;
! 2701: D1 = mppgcd(X_minus_Y, (GEN)(res[j]));
! 2702: }
! 2703: if (!flag || (!is_pm1(D1) && !egalii(D1, (GEN)(res[j]))))
! 2704: { /* got one which splits this factor */
! 2705: if (DEBUGLEVEL >= 5)
! 2706: fprintferr("MPQS: resplitting a factor after %ld kernel vectors\n",
! 2707: i+1); /* always plural */
! 2708: /* first make sure there's room for another factor */
! 2709: if (res_next > res_size)
! 2710: { /* need to reallocate (_very_ rare case) */
! 2711: long i1, new_size = 2*res_size;
! 2712: GEN new_res;
! 2713: if (new_size > res_max) new_size = res_max;
! 2714: new_res = cgetg(2*new_size+1, t_VEC);
! 2715: for (i1=2*new_size; i1>=res_next; i1--) new_res[i1] = 0;
! 2716: for (i1=1; i1<res_next; i1++)
! 2717: {
! 2718: new_res[i1] = res[i1]; /* factors */
! 2719: new_res[new_size+i1] = res[res_size+i1]; /* primality tags */
! 2720: }
! 2721: res = new_res; res_size = new_size; /* res_next unchanged */
! 2722: }
! 2723: /* now there is room; divide into existing factor and store the
! 2724: new gcd. Remove the known-composite flag from the old entry */
! 2725: (void)mpdivis((GEN)(res[j]), D1, (GEN)(res[j]));
! 2726: res[res_next] = (long)D1; res[res_size+j] = 0;
! 2727: if (++res_next > res_max) break; /* all possible factors seen */
! 2728: mask = 7; /* check for 3rd and 5th powers */
! 2729: if (isprobableprime((GEN)(res[j])))
! 2730: {
! 2731: done++; res[res_size+j] = un;
! 2732: }
! 2733: else if (carrecomplet((GEN)(res[j]), &base))
! 2734: {
! 2735: /* we no longer bother preserving the cloned N or what is left
! 2736: of it when we hit it here */
! 2737: res[j] = (long)base;
! 2738: done++; res[res_size+j] = deux;
! 2739: if (DEBUGLEVEL >= 5)
! 2740: fprintferr("MPQS: decomposed a square\n");
! 2741: }
! 2742: else if ((flag = is_odd_power((GEN)(res[j]), &base, &mask))) /* = */
! 2743: {
! 2744: res[j] = (long)base;
! 2745: done++; res[res_size+j] = (long)stoi(flag);
! 2746: if (DEBUGLEVEL >= 5)
! 2747: fprintferr("MPQS: decomposed a %s\n",
! 2748: (flag == 3 ? "cube" :
! 2749: (flag == 5 ? "5th power" : "7th power")));
! 2750: }
! 2751: else res[res_size+j] = zero; /* known composite */
! 2752: mask = 7;
! 2753: if (isprobableprime(D1))
! 2754: {
! 2755: done++; res[res_size+res_last] = un;
! 2756: }
! 2757: else if (carrecomplet(D1, &base))
! 2758: {
! 2759: res[res_last] = (long)base;
! 2760: done++; res[res_size+res_last] = deux;
! 2761: if (DEBUGLEVEL >= 5)
! 2762: fprintferr("MPQS: decomposed a square\n");
! 2763: }
! 2764: else if ((flag = is_odd_power(D1, &base, &mask))) /* assignment */
! 2765: {
! 2766: res[res_last] = (long)base;
! 2767: done++; res[res_size+res_last] = (long)stoi(flag);
! 2768: if (DEBUGLEVEL >= 5)
! 2769: fprintferr("MPQS: decomposed a %s\n",
! 2770: (flag == 3 ? "cube" :
! 2771: (flag == 5 ? "5th power" : "7th power")));
! 2772: }
! 2773: else res[res_size+res_last] = zero; /* known composite */
! 2774: } /* else it didn't help on this factor, try the next one... */
! 2775: else avma = av3; /* ...after destroying the gcds */
! 2776: } /* loop over known composite factors */
! 2777: if (res_next > res_last)
! 2778: {
! 2779: if (DEBUGLEVEL >= 5 && done < res_last)
! 2780: fprintferr("MPQS: got %ld factors%s\n",
! 2781: res_last,
! 2782: (done < res_last ? ", looking for more..." : ""));
! 2783: res_last = res_next;
! 2784: }
! 2785: /* we should break out of the outer loop when we have seen res_max
! 2786: factors, and also when all current factors are probable primes */
! 2787: if (res_next > res_max || done == res_next - 1) break;
! 2788: /* else continue loop over kernel basis */
! 2789: } /* end case of further splitting of existing factors */
! 2790: /* garbage collection */
! 2791: if (low_stack(lim, stack_lim(av2,1)))
! 2792: {
! 2793: long i1;
! 2794: if(DEBUGMEM>1) err(warnmem,"[3]: mpqs_solve_linear_system");
! 2795: tetpil=avma;
! 2796: /* gcopy would have a problem with our NULL pointers... */
! 2797: new_res = cgetg(lg(res), t_VEC);
! 2798: for (i1=2*res_size; i1>=res_next; i1--) new_res[i1] = 0;
! 2799: for (i1=1; i1<res_next; i1++)
! 2800: {
! 2801: new_res[i1] =
! 2802: (isonstack((GEN)(res[i1])) ? licopy((GEN)(res[i1])) : res[i1]);
! 2803: new_res[res_size+i1] = res[res_size+i1];
! 2804: }
! 2805: res = gerepile(av2, tetpil, new_res);
! 2806: /* discard X and Y_prod */
! 2807: }
! 2808: } /* for (loop over kernel basis) */
! 2809:
! 2810: if (res_next < 3) /* still no factors seen */
! 2811: {
! 2812: pari_fclose(pFREL);
! 2813: mpqs_gauss_destroy_matrix(m, size_of_FB+1, rel);
! 2814: mpqs_gauss_destroy_matrix(ker_m, rel, rank);
! 2815: free(ei); free(fpos);
! 2816: avma = av;
! 2817: return NULL; /* no factors found */
! 2818: }
! 2819: /* normal case: convert internal format to ifac format as described in
! 2820: src/basemath/ifactor1.c (triples of components: value, exponent, class
! 2821: [unknown, known composite, known prime]), clean up and return result */
! 2822: pari_fclose(pFREL);
! 2823: mpqs_gauss_destroy_matrix(m, size_of_FB+1, rel);
! 2824: mpqs_gauss_destroy_matrix(ker_m, rel, rank);
! 2825: free(ei); free(fpos);
! 2826: res_last = res_next - 1; /* number of distinct factors found */
! 2827: new_res = cgetg(3*res_last + 1, t_VEC);
! 2828: if (DEBUGLEVEL >= 6)
! 2829: fprintferr("MPQS: wrapping up vector of %ld factors\n", res_last);
! 2830: for (i=1,j=1; i <= res_last; i++)
! 2831: {
! 2832: new_res[j++] = /* value of factor */
! 2833: isonstack((GEN)(res[i])) ? licopy((GEN)(res[i])) : res[i];
! 2834: flag = res[res_size+i];
! 2835: new_res[j++] = /* exponent */
! 2836: flag ? /* flag was zero or un or ... */
! 2837: (flag == zero ? un :
! 2838: (isonstack((GEN)flag) ? licopy((GEN)flag) : flag)
! 2839: ) :
! 2840: un; /* flag was (long)NULL */
! 2841: new_res[j++] = /* class */
! 2842: flag == zero ? zero : /* known composite */
! 2843: (long)NULL; /* base of power or suspected prime --
! 2844: mark as `unknown' */
! 2845: if (DEBUGLEVEL >= 6)
! 2846: fprintferr("\tpackaging %ld: %Z ^%ld (%s)\n", i, res[i],
! 2847: itos((GEN)(new_res[j-2])),
! 2848: (flag == zero ? "comp." : "unknown"));
! 2849: }
! 2850: return gerepileupto(av, new_res);
! 2851: }
! 2852:
! 2853: /******************************/
! 2854:
! 2855: /* All percentages below are actually fixed-point quantities scaled by 10
! 2856: (value of 1 means 0.1%, 1000 means 100%). --GN */
! 2857:
! 2858: #define max_percentage 1500 /* give up when nothing found after ~1.5
! 2859: times the required number of relations has
! 2860: been computed (n might be a prime power
! 2861: or the parameters might be exceptionally
! 2862: unfortunate for it) --GN */
! 2863:
! 2864: /**
! 2865: ** Factors N using the self-initializing multipolynomial quadratic sieve
! 2866: ** (SIMPQS). Returns one of the two factors, or (usually) a vector of
! 2867: ** factors and exponents and information about which ones are definitely
! 2868: ** still composite, or NULL when something goes wrong or when we can't
! 2869: ** seem to make any headway.
! 2870: **/
! 2871:
! 2872: /* TODO: this function to be renamed mpqs_main() with several extra para-
! 2873: meters, with mpqs() as a wrapper for the standard case, so we can do
! 2874: partial runs distributed across several machines etc. (not necessarily
! 2875: from gp, but certainly from a small dedicated C program). --GN */
! 2876:
! 2877: GEN
! 2878: mpqs(GEN N)
! 2879: {
! 2880: GEN fact; /* will in the end hold our factor(s) */
! 2881: ulong decimal_digits; /* number of decimals of N */
! 2882: long tc; /* number of candidates found in one
! 2883: iteration */
! 2884: long t; /* number of full relations found in one
! 2885: iteration */
! 2886: long tp; /* number of full relations found in one
! 2887: iteration after combining large prime
! 2888: relations */
! 2889: long k; /* the multiplier */
! 2890: GEN kN; /* k * N */
! 2891: double sqrt_kN; /* double approximation of sqrt(k*N) */
! 2892: long *FB; /* the factor base */
! 2893: ulong size_of_FB; /* the size of the factor base */
! 2894: ulong FB_overshoot; /* the number of relations aimed for */
! 2895: double log_multiplier; /* maps logarithms of FB elements to
! 2896: unsigned chars */
! 2897: double tolerance; /* used in sieving with logarithms */
! 2898: unsigned char *log_FB; /* logarithms of FB elements mapped to
! 2899: unsigned chars */
! 2900: unsigned char *sieve_array; /* the sieve array */
! 2901: unsigned char *sieve_array_end; /* the end of the sieve array */
! 2902: ulong M; /* the sieve interval size [-M, M] */
! 2903: ulong starting_sieving_index; /* the first element in the FB used for
! 2904: sieving */
! 2905: long last_prime_in_FB; /* the biggest prime in FB */
! 2906: long *sqrt_mod_p_kN; /* array containing sqrt(K*N) mod p_i,
! 2907: where p_i are FB elements */
! 2908: GEN A, B, inv_A4; /* coefficients of polynomials in (SI) */
! 2909: long *Q_prime_glob, *Q_prime; /* used for self initialization (SI) */
! 2910: GEN *H_i; /* will be used to compute the consecutive
! 2911: B during (SI) */
! 2912: long start_index_FB_for_A; /* the first index in the FB used for
! 2913: computing A during (SI), minus 1 */
! 2914: ulong no_of_primes_in_A; /* number of primes dividing A
! 2915: during (SI) */
! 2916: ulong total_no_of_primes_for_A; /* number of primes used for finding A
! 2917: during (SI) */
! 2918: long max_no_of_B; /* how many B's to use before choosing
! 2919: a new A during (SI) */
! 2920: long index_i; /* denotes the current pair of coeffs
! 2921: (A, B_i). If i == 0, a new A is
! 2922: generated */
! 2923: ulong bin_index; /* used for choosing the prime factors for
! 2924: for the A coeffs in mpqs_self_init() */
! 2925: long i, p; /* counters */
! 2926:
! 2927: /* Let (z0, z1) be the roots of Q(x) = A x^2 + Bx +C mod p_i;
! 2928: then we know that
! 2929: Q(z1 + i k) == 0 mod p_i and Q(z2 + i k) == 0 mod p_i */
! 2930:
! 2931: long *start_1; /* stores the position where p_i
! 2932: divides Q(x) for the first time,
! 2933: using z1 */
! 2934: long *start_2; /* same, but using z2 */
! 2935: long *inv_A2; /* inv_A2[i] = 1/(2*A) mod p_i */
! 2936: long **inv_A_H_i; /* inv_A_H_i[i][j] = 1/A H_i[i] mod p_j */
! 2937: long *candidates; /* positions in the sieve_array which
! 2938: probably factor over the FB */
! 2939: long lp_bound; /* size limit for large primes */
! 2940: ulong sort_interval; /* these determine when to sort and merge */
! 2941: ulong followup_sort_interval; /* the temporary files (scaled percentages) */
! 2942: long total_full_relations = 0;
! 2943: long total_partial_relations = 0;
! 2944: pariFILE *pFREL;
! 2945: pariFILE *pFNEW;
! 2946: pariFILE *pLPREL;
! 2947: pariFILE *pLPNEW;
! 2948: pariFILE *pCOMB;
! 2949: FILE *FNEW;
! 2950: FILE *LPNEW;
! 2951: long percentage = 0; /* scaled by 10, see comment above */
! 2952: long total_candidates_number = 0;
! 2953: long useless_candidates = 0; /* another scaled percentage */
! 2954: long vain_iterations = 0;
! 2955: long good_iterations = 0;
! 2956: long iterations = 0;
! 2957: long av = avma;
! 2958:
! 2959: /* state flags for cleanup if we get interrupted --GN */
! 2960: static char all_clean = 1; /* set to 0 while mpqs() is busy */
! 2961:
! 2962: if (DEBUGLEVEL >= 4)
! 2963: {
! 2964: if (!all_clean) { /* TODO: clean up... */ }
! 2965: (void) timer2(); /* clear timer */
! 2966: fprintferr("MPQS: number to factor N = %Z\n", N);
! 2967: }
! 2968:
! 2969: all_clean = 0; /* activate clean-up trap */
! 2970: {
! 2971: char *s = GENtostr(N);
! 2972: decimal_digits = strlen(s);
! 2973: free(s);
! 2974: }
! 2975:
! 2976: if (decimal_digits >= 108) /* changed to match Denny's parameters */
! 2977: {
! 2978: err(warner, "MPQS: number too big to be factored with MPQS, giving up");
! 2979: avma = av;
! 2980: all_clean = 1;
! 2981: return NULL;
! 2982: }
! 2983:
! 2984: if (DEBUGLEVEL >= 4)
! 2985: fprintferr("MPQS: factoring number of %ld decimal digits\n",
! 2986: decimal_digits);
! 2987:
! 2988: if (decimal_digits >= 70)
! 2989: err(warner,
! 2990: "MPQS: the factorization of this number will take %s hours",
! 2991: decimal_digits >= 84 ? "many" : "several");
! 2992:
! 2993: k = mpqs_find_k(N, 5);
! 2994: if (DEBUGLEVEL >= 5)
! 2995: fprintferr("MPQS: found multiplier %ld for N\n", k);
! 2996:
! 2997: kN = mulis(N, k);
! 2998: {
! 2999: char *s = GENtostr(kN);
! 3000: decimal_digits = strlen(s);
! 3001: free(s);
! 3002: }
! 3003:
! 3004: if (DEBUGLEVEL >= 5)
! 3005: {
! 3006: fprintferr("MPQS: kN = %Z\n", kN);
! 3007: fprintferr("MPQS: kN has %ld decimal digits\n",
! 3008: decimal_digits);
! 3009: }
! 3010:
! 3011: mpqs_read_parameters(decimal_digits, &tolerance, &M, &size_of_FB,
! 3012: &FB_overshoot,
! 3013: &no_of_primes_in_A, &total_no_of_primes_for_A,
! 3014: &max_no_of_B, &starting_sieving_index,
! 3015: &sort_interval, &followup_sort_interval);
! 3016: {
! 3017: double bytesize = (size_of_FB + 1)/(8.*1048576.);
! 3018: bytesize *= FB_overshoot;
! 3019: if (bytesize > 32.)
! 3020: {
! 3021: err(warner,
! 3022: "MPQS: Gauss elimination will require more than 32MBy of memory");
! 3023: if (DEBUGLEVEL >= 1)
! 3024: fprintferr("\t(estimated memory needed: %4.1fMBy)\n", bytesize);
! 3025: }
! 3026: }
! 3027:
! 3028: if (DEBUGLEVEL >= 4)
! 3029: {
! 3030: fprintferr("MPQS: sieving interval = [%ld, %ld]\n",
! 3031: -(long)M, M);
! 3032: fprintferr("MPQS: size of factor base = %ld\n",
! 3033: size_of_FB);
! 3034: fprintferr("MPQS: striving for %ld relations\n",
! 3035: FB_overshoot);
! 3036: fprintferr("MPQS: first sorting at %ld%%, then every %3.1f%% / %3.1f%%\n",
! 3037: sort_interval/10, followup_sort_interval/10.,
! 3038: followup_sort_interval/20.);
! 3039: fprintferr("MPQS: initial sieving index = %ld\n",
! 3040: starting_sieving_index);
! 3041: }
! 3042: sieve_array =
! 3043: (unsigned char *) gpmalloc((M << 1) * sizeof(unsigned char));
! 3044: sieve_array_end = sieve_array + (M << 1) - 1;
! 3045:
! 3046: if (DEBUGLEVEL >= 5)
! 3047: fprintferr("MPQS: creating factor base FB of size = %ld\n",
! 3048: size_of_FB);
! 3049:
! 3050: FB = mpqs_create_FB(size_of_FB, kN, k, &p);
! 3051:
! 3052: /* the following this way round to avoid overflow: --GN */
! 3053: lp_bound = FB[FB[0]+1];
! 3054: if (DEBUGLEVEL >= 4)
! 3055: fprintferr("MPQS: largest prime in FB = %ld\n",
! 3056: lp_bound);
! 3057: if (lp_bound > MPQS_LP_BOUND)
! 3058: lp_bound = MPQS_LP_BOUND;
! 3059: lp_bound *= MPQS_LP_FACTOR;
! 3060: if (DEBUGLEVEL >= 4)
! 3061: fprintferr("MPQS: bound for `large primes\' = %ld\n",
! 3062: lp_bound);
! 3063:
! 3064: if (p != 0)
! 3065: {
! 3066: free(FB);
! 3067: free(sieve_array);
! 3068: if (DEBUGLEVEL >= 4)
! 3069: fprintferr("\nMPQS: found factor = %ld whilst creating factor base\n",
! 3070: p);
! 3071: if (mpqs_diffptr == diffptr) mpqs_diffptr = NULL;
! 3072: avma = av;
! 3073: /* TODO: free the FB etc!!! */
! 3074: all_clean = 1;
! 3075: return stoi(p);
! 3076: }
! 3077:
! 3078: if (DEBUGLEVEL >= 5)
! 3079: {
! 3080: fprintferr("MPQS: computing logarithm approximations for p_i in FB\n");
! 3081: fprintferr("MPQS: computing sqrt(k*N) mod p_i\n");
! 3082: }
! 3083: last_prime_in_FB = FB[FB[0] + 1];
! 3084: log_multiplier = (2 * (unsigned char) (0.5 * log2 (gtodouble(kN)) +
! 3085: log2 ((double) M) - tolerance *
! 3086: log2 ((double) last_prime_in_FB)));
! 3087: log_multiplier = 127.0 / log_multiplier;
! 3088:
! 3089: log_FB =
! 3090: (unsigned char *) gpmalloc((size_of_FB + 2) * sizeof(unsigned char));
! 3091: sqrt_mod_p_kN =
! 3092: (long *) gpmalloc((size_of_FB + 2) * sizeof(long));
! 3093:
! 3094: for (i = 2; (ulong)i < size_of_FB + 2; i++)
! 3095: {
! 3096: long av1 = avma;
! 3097: p = FB[i];
! 3098:
! 3099: /* compute the approximations of the logarithms of p_i */
! 3100: log_FB[i] =
! 3101: (unsigned char) (log_multiplier * log2 ((double) p) * 2);
! 3102:
! 3103: /* compute the x_i such that x_i^2 = (kN % p_i) mod p_i */
! 3104: sqrt_mod_p_kN[i] = itos(mpsqrtmod(modis(kN, p), stoi(p)));
! 3105: avma = av1;
! 3106: }
! 3107:
! 3108: if (DEBUGLEVEL >= 5)
! 3109: fprintferr("MPQS: allocating arrays for self-initialization\n");
! 3110:
! 3111: /* the size of coefficient A should be approximately */
! 3112: /* sqrt(kN)/M, so the size of the primes p dividing */
! 3113: /* A should be approximately (sqrt(kN/M))^(1/no_of_primes_in_A) */
! 3114:
! 3115: /* compute expected size of coefficients, which also defines the tolerance
! 3116: for the logarithmic sieve */
! 3117: sqrt_kN = sqrt(gtodouble(kN));
! 3118: tolerance = sqrt_kN / M;
! 3119: tolerance = pow(2.0, log2(tolerance) / no_of_primes_in_A);
! 3120: if (tolerance > FB[size_of_FB - 1]) /* ??? */
! 3121: err(talker, "MPQS: number of prime factors in A is too small");
! 3122:
! 3123: /* choose primes in FB to use for building the A coefficient */
! 3124: start_index_FB_for_A = 2;
! 3125: while (FB[start_index_FB_for_A] < tolerance)
! 3126: start_index_FB_for_A++;
! 3127:
! 3128: if (start_index_FB_for_A > 7)
! 3129: start_index_FB_for_A -= (no_of_primes_in_A >> 1);
! 3130:
! 3131: /* ensure that the primes to be used for A do occur in the FB */
! 3132: if (start_index_FB_for_A + total_no_of_primes_for_A >= size_of_FB)
! 3133: start_index_FB_for_A = size_of_FB - total_no_of_primes_for_A - 1;
! 3134:
! 3135: /* ensure that the multiplier k is smaller than the prime divisors of A */
! 3136: if (k >= FB[start_index_FB_for_A])
! 3137: {
! 3138: do
! 3139: start_index_FB_for_A++;
! 3140: while (k >= FB[start_index_FB_for_A]);
! 3141: if (start_index_FB_for_A + total_no_of_primes_for_A >= size_of_FB)
! 3142: err(talker,
! 3143: "MPQS: number of primes for A is too large, or FB too small");
! 3144: /* this shouldn't happen */
! 3145: }
! 3146:
! 3147: /* now a selection of total_no_of_primes_for_A consecutive primes
! 3148: * p = FB[start_index_FB_for_A+1], ... is chosen from the factor base */
! 3149:
! 3150: /* (no need to copy them around as long as they are consecutive entries
! 3151: in FB --GN) */
! 3152: Q_prime =
! 3153: (long *) gpmalloc(no_of_primes_in_A * sizeof(long));
! 3154: #if 1
! 3155: Q_prime_glob = &(FB[start_index_FB_for_A + 1]);
! 3156: #else
! 3157: Q_prime_glob =
! 3158: (long *) gpmalloc(total_no_of_primes_for_A * sizeof(long));
! 3159: for (i = 0; i < total_no_of_primes_for_A; i++)
! 3160: Q_prime_glob[i] = FB[start_index_FB_for_A + i + 1];
! 3161: #endif
! 3162:
! 3163: /* used for choosing the correct A coeffs in mpqs_self_init() */
! 3164: bin_index = 0;
! 3165:
! 3166: /* will be used to compute the consecutive B during
! 3167: self-initialization */
! 3168: H_i = (GEN *) gpmalloc(no_of_primes_in_A * sizeof(GEN));
! 3169: for (i = 0; (ulong)i < no_of_primes_in_A; i++)
! 3170: H_i[i] = cgeti(2 * total_no_of_primes_for_A);
! 3171:
! 3172: inv_A_H_i =
! 3173: (long **) gpmalloc(total_no_of_primes_for_A * sizeof(long *));
! 3174: for (i = 0; (ulong)i < total_no_of_primes_for_A; i++)
! 3175: inv_A_H_i[i] = (long *) gpmalloc((size_of_FB + 2) * sizeof(long));
! 3176:
! 3177: start_1 = (long *) gpmalloc((size_of_FB + 2) * sizeof(long));
! 3178: start_2 = (long *) gpmalloc((size_of_FB + 2) * sizeof(long));
! 3179:
! 3180: /* the next will hold 1/(2*A) mod p_i, p_i in FB */
! 3181: inv_A2 = (long *) gpmalloc((size_of_FB + 2) * sizeof(long));
! 3182:
! 3183: candidates = (long *) gpmalloc(MPQS_CANDIDATE_ARRAY_SIZE * sizeof(long));
! 3184:
! 3185: if (DEBUGLEVEL >= 5)
! 3186: {
! 3187: fprintferr("MPQS: index range of primes for A: [%ld, %ld]\n",
! 3188: start_index_FB_for_A + 1,
! 3189: start_index_FB_for_A + total_no_of_primes_for_A);
! 3190: fprintferr("MPQS: coefficients A will be built from %ld primes each\n",
! 3191: no_of_primes_in_A);
! 3192: }
! 3193:
! 3194: /* CLEAN UP define */
! 3195:
! 3196: #define CLEANUP() \
! 3197: free(FB); \
! 3198: free(sieve_array); \
! 3199: free(log_FB); \
! 3200: free(sqrt_mod_p_kN); \
! 3201: free(Q_prime); \
! 3202: /* free(Q_prime_glob); */ \
! 3203: free(H_i); \
! 3204: for (i = 0; (ulong)i < total_no_of_primes_for_A; i++) \
! 3205: free(inv_A_H_i[i]); \
! 3206: free(inv_A_H_i); \
! 3207: free(start_1); \
! 3208: free(start_2); \
! 3209: free(inv_A2); \
! 3210: free(candidates);
! 3211:
! 3212: /*
! 3213: * main loop which
! 3214: * - computes polynomials and their zeros (self initialization)
! 3215: * - does the sieving
! 3216: * - tests candidates of the sieve array
! 3217: */
! 3218:
! 3219: /* denotes the current pair of coeffs (A, B_i). If i == 0 a new A is
! 3220: generated */
! 3221: index_i = -1;
! 3222:
! 3223: /* the coefficients of the polynomial currently used for sieving */
! 3224: /* A will be at most as long as the product of
! 3225: no_of_primes_in_A word-sized primes (was total_..., GN) */
! 3226: /* B needs at most total_no_of_primes_for_A + 1 words [CHECK] --GN */
! 3227: /* Take the double is just for safety ... */
! 3228: A = cgeti(2 * no_of_primes_in_A);
! 3229: B = cgeti(2 * total_no_of_primes_for_A + 1);
! 3230:
! 3231: /* 1/4A mod kN */
! 3232: inv_A4 = cgeti(lg(kN));
! 3233:
! 3234: if (DEBUGLEVEL >= 5)
! 3235: fprintferr("MPQS: starting main loop\n");
! 3236: /* compute names for the temp files we'll need */
! 3237: FREL_str = mpqs_get_filename("FREL");
! 3238: FNEW_str = mpqs_get_filename("FNEW");
! 3239: LPREL_str = mpqs_get_filename("LPREL");
! 3240: LPNEW_str = mpqs_get_filename("LPNEW");
! 3241: COMB_str = mpqs_get_filename("COMB");
! 3242: TMP_str = mpqs_get_filename("LPTMP");
! 3243:
! 3244: /* just to create the temp files */
! 3245: pFREL = pari_safefopen(FREL_str, WRITE); pari_fclose(pFREL);
! 3246: pLPREL = pari_safefopen(LPREL_str, WRITE); pari_fclose(pLPREL);
! 3247:
! 3248: pFNEW = pari_safefopen(FNEW_str, WRITE); FNEW = pFNEW->file;
! 3249: pLPNEW= pari_safefopen(LPNEW_str, WRITE); LPNEW = pLPNEW->file;
! 3250: for(;;)
! 3251: {
! 3252: /* at start of loop, FNEW and LPNEW are open for writing */
! 3253: iterations++;
! 3254: /* when all of the B's have already been used, choose new A ;
! 3255: this is indicated by setting index_i to 0 */
! 3256: if (index_i == (max_no_of_B - 1))
! 3257: index_i = 0;
! 3258: else
! 3259: index_i++;
! 3260:
! 3261: /* self initialization: compute polynomial and its zeros */
! 3262:
! 3263: mpqs_self_init(A, B, N, kN, FB, sqrt_mod_p_kN, start_1, start_2,
! 3264: no_of_primes_in_A, total_no_of_primes_for_A,
! 3265: M, inv_A_H_i, Q_prime, Q_prime_glob, H_i,
! 3266: index_i, start_index_FB_for_A, inv_A2, inv_A4,
! 3267: &bin_index, &fact);
! 3268: if (bin_index >= (1ul << total_no_of_primes_for_A)) /* wraparound */
! 3269: {
! 3270: /* TODO: increase some parameters. For the moment, simply give up */
! 3271: CLEANUP();
! 3272: pari_fclose(pFNEW);
! 3273: pari_fclose(pLPNEW);
! 3274: /* FREL, LPREL are closed at this point */
! 3275: pari_unlink(FREL_str);
! 3276: pari_unlink(FNEW_str);
! 3277: pari_unlink(LPREL_str);
! 3278: pari_unlink(LPNEW_str);
! 3279: if (mpqs_diffptr == diffptr) mpqs_diffptr = NULL;
! 3280: all_clean = 1;
! 3281: avma=av; return NULL;
! 3282: }
! 3283: if (fact) /* A4 not coprime to kN, fact divides N */
! 3284: { /* (cannot actually happen) */
! 3285: if (is_pm1(fact) || egalii(fact,N))
! 3286: continue; /* cannot use the current polynomial */
! 3287: CLEANUP();
! 3288: pari_fclose(pFNEW);
! 3289: pari_fclose(pLPNEW);
! 3290: pari_unlink(FREL_str);
! 3291: pari_unlink(FNEW_str);
! 3292: pari_unlink(LPREL_str);
! 3293: pari_unlink(LPNEW_str);
! 3294: if (mpqs_diffptr == diffptr) mpqs_diffptr = NULL;
! 3295: all_clean = 1;
! 3296: if (DEBUGLEVEL >= 4)
! 3297: {
! 3298: fprintferr("MPQS: whilst trying to invert A4 mod kN,\n");
! 3299: fprintferr("\tfound factor = %Z\n", fact);
! 3300: flusherr();
! 3301: }
! 3302: return gerepileupto(av, fact);
! 3303: }
! 3304:
! 3305: if (DEBUGLEVEL >= 6)
! 3306: {
! 3307: if (!index_i)
! 3308: fprintferr("MPQS: chose prime pattern 0x%lX for A\n",
! 3309: bin_index);
! 3310: if (signe(B) < 0)
! 3311: {
! 3312: setsigne(B,1);
! 3313: fprintferr("MPQS: chose Q_%ld(x) = %Z x^2 - %Z x + C\n",
! 3314: index_i, A, B);
! 3315: setsigne(B,-1);
! 3316: }
! 3317: else
! 3318: {
! 3319: fprintferr("MPQS: chose Q_%ld(x) = %Z x^2 + %Z x + C\n",
! 3320: index_i, A, B);
! 3321: }
! 3322: }
! 3323:
! 3324: mpqs_sieve(FB, log_FB, start_1, start_2, sieve_array,
! 3325: sieve_array_end, M, starting_sieving_index);
! 3326:
! 3327: tc = mpqs_eval_sieve(sieve_array, M, candidates);
! 3328: total_candidates_number += tc;
! 3329: if (DEBUGLEVEL >= 6)
! 3330: fprintferr("MPQS: found %lu candidate%s\n",
! 3331: tc, (tc==1? "" : "s"));
! 3332:
! 3333: if (tc)
! 3334: {
! 3335: good_iterations++;
! 3336: t = mpqs_eval_candidates(A, inv_A4, B, kN, k, sqrt_kN, FB,
! 3337: start_1, start_2,
! 3338: M, bin_index, candidates, tc, lp_bound,
! 3339: start_index_FB_for_A, FNEW, LPNEW);
! 3340: }
! 3341: else
! 3342: t = 0;
! 3343:
! 3344: total_full_relations += t;
! 3345: percentage =
! 3346: (long)((1000.0 * total_full_relations) / FB_overshoot);
! 3347: useless_candidates =
! 3348: (long)((1000.0 * (total_candidates_number - total_full_relations))
! 3349: / (total_candidates_number ? total_candidates_number : 1));
! 3350:
! 3351: if ((ulong)percentage < sort_interval)
! 3352: continue; /* most main loops end here... */
! 3353:
! 3354: /* Extra processing when we have completed a sort interval: */
! 3355: if (DEBUGLEVEL >= 3)
! 3356: {
! 3357: if (DEBUGLEVEL >= 4)
! 3358: fprintferr("\nMPQS: passing the %3.1f%% checkpoint, time = %ld ms\n",
! 3359: sort_interval/10., timer2());
! 3360: else
! 3361: fprintferr("\nMPQS: passing the %3.1f%% checkpoint\n",
! 3362: sort_interval/10.);
! 3363: flusherr();
! 3364: }
! 3365: /* sort LPNEW and merge it into LPREL, diverting combinables into COMB */
! 3366: pari_fclose(pLPNEW);
! 3367: mpqs_sort_lp_file(LPNEW_str);
! 3368: tp = mpqs_mergesort_lp_file(LPREL_str, LPNEW_str, 0);
! 3369: pLPNEW = pari_fopen(LPNEW_str, WRITE); /* NOT safefopen */
! 3370: LPNEW = pLPNEW->file;
! 3371:
! 3372: /* combine whatever there is to be combined */
! 3373: if (tp > 0)
! 3374: {
! 3375: /* build full relations out of large prime relations */
! 3376: pCOMB = pari_fopen(COMB_str, READ);
! 3377: tp = mpqs_combine_large_primes(pCOMB->file, FNEW, size_of_FB, N, kN, &fact
! 3378: #ifdef MPQS_DEBUG
! 3379: , FB
! 3380: #endif
! 3381: );
! 3382: pari_fclose(pCOMB);
! 3383: pari_unlink(COMB_str);
! 3384: /* now FREL, LPREL are closed and FNEW, LPNEW are still open */
! 3385: if (fact) /* factor found during combining */
! 3386: {
! 3387: /* clean up */
! 3388: CLEANUP();
! 3389: pari_fclose(pLPNEW);
! 3390: pari_fclose(pFNEW);
! 3391: pari_unlink(FREL_str);
! 3392: pari_unlink(FNEW_str);
! 3393: pari_unlink(LPREL_str);
! 3394: pari_unlink(LPNEW_str);
! 3395: if (DEBUGLEVEL >= 4)
! 3396: {
! 3397: fprintferr("\nMPQS: split N whilst combining, time = %ld ms\n",
! 3398: timer2());
! 3399: fprintferr("MPQS: found factor = %Z\n", fact);
! 3400: }
! 3401: if (mpqs_diffptr == diffptr) mpqs_diffptr = NULL;
! 3402: all_clean = 1;
! 3403: return gerepileupto(av, fact);
! 3404: }
! 3405: }
! 3406:
! 3407: /* sort FNEW and merge it into FREL */
! 3408: pari_fclose(pFNEW);
! 3409: mpqs_sort_lp_file(FNEW_str);
! 3410: total_full_relations = mpqs_mergesort_lp_file(FREL_str, FNEW_str, 1);
! 3411: /* this being the definitive count (combinables combined, and
! 3412: duplicates removed) */
! 3413: /* FNEW stays closed until we know whether we need to reopen it for
! 3414: another iteration */
! 3415:
! 3416: total_partial_relations += tp;
! 3417:
! 3418: /* note that due to the removal of duplicates, percentage may actually
! 3419: decrease at this point. This may look funny in the diagnostics but
! 3420: is nothing to worry about, since we _are_ making progress neverthe-
! 3421: less. --GN */
! 3422: percentage =
! 3423: (long)((1000.0 * total_full_relations) / FB_overshoot);
! 3424: vain_iterations =
! 3425: (long)((1000.0 * (iterations - good_iterations))
! 3426: / iterations);
! 3427:
! 3428: /* TODO: the following could be improved (extrapolate from past
! 3429: experience how many combined full relations we can expect in
! 3430: addition to those we're finding directly) --GN */
! 3431: if (percentage >= 840)
! 3432: {
! 3433: if (percentage >= 980)
! 3434: sort_interval = percentage + 10;
! 3435: else
! 3436: sort_interval = percentage + (followup_sort_interval >> 1);
! 3437: if (sort_interval >= 1000 && percentage < 1000)
! 3438: sort_interval = 1000;
! 3439: }
! 3440: else
! 3441: {
! 3442: sort_interval = percentage + followup_sort_interval;
! 3443: }
! 3444:
! 3445: if (DEBUGLEVEL >= 4)
! 3446: {
! 3447: fprintferr("MPQS: done sorting%s, time = %ld ms\n",
! 3448: tp > 0 ? " and combining" : "",
! 3449: timer2());
! 3450: fprintferr("MPQS: found %3.1f%% of the required relations\n",
! 3451: percentage/10.);
! 3452: if (DEBUGLEVEL >= 5)
! 3453: {
! 3454: /* total_full_relations are always plural */
! 3455: fprintferr("MPQS: found %ld full relations\n",
! 3456: total_full_relations);
! 3457: fprintferr("MPQS: (%ld of these from partial relations)\n",
! 3458: total_partial_relations);
! 3459: fprintferr("MPQS: %4.1f%% useless candidates\n",
! 3460: useless_candidates/10.);
! 3461: fprintferr("MPQS: %4.1f%% of the iterations yielded no candidates\n",
! 3462: vain_iterations/10.);
! 3463: fprintferr("MPQS: next checkpoint at %3.1f%%\n",
! 3464: sort_interval/10.);
! 3465: }
! 3466: }
! 3467:
! 3468: if (percentage < 1000)
! 3469: {
! 3470: pFNEW = pari_fopen(FNEW_str, WRITE); /* NOT safefopen */
! 3471: FNEW = pFNEW->file;
! 3472: /* at this point, LPNEW and FNEW are again open for writing */
! 3473: continue; /* main loop */
! 3474: }
! 3475:
! 3476: /* percentage >= 1000, which implies total_full_relations > size_of_FB:
! 3477: try finishing it off */
! 3478:
! 3479: /* solve the system over F_2 */
! 3480: if (DEBUGLEVEL >= 4)
! 3481: fprintferr("\nMPQS: starting Gauss over F_2 on %ld distinct relations\n",
! 3482: total_full_relations);
! 3483: fact = mpqs_solve_linear_system(kN, N,
! 3484: total_full_relations,
! 3485: FB, size_of_FB);
! 3486:
! 3487: /* if solution found, clean up and return */
! 3488: if (fact)
! 3489: {
! 3490: /* clean up */
! 3491: CLEANUP();
! 3492: pari_fclose(pLPNEW);
! 3493: pari_unlink(FREL_str);
! 3494: pari_unlink(FNEW_str);
! 3495: pari_unlink(LPREL_str);
! 3496: pari_unlink(LPNEW_str);
! 3497: if (DEBUGLEVEL >= 4)
! 3498: {
! 3499: fprintferr("\nMPQS: time in Gauss and gcds = %ld ms\n",
! 3500: timer2());
! 3501: if (typ(fact) == t_INT)
! 3502: fprintferr("MPQS: found factor = %Z\n", fact);
! 3503: else
! 3504: {
! 3505: long j, nf=(lg(fact)-1)/3;
! 3506: if (nf==2)
! 3507: fprintferr("MPQS: found factors = %Z\n\tand %Z\n",
! 3508: fact[4], fact[1]);
! 3509: else
! 3510: {
! 3511: fprintferr("MPQS: found %ld factors =\n", nf);
! 3512: for (j=nf; j; j--)
! 3513: fprintferr("\t%Z%s\n", fact[3*j-2], (j>1? "," : ""));
! 3514: }
! 3515: }
! 3516: }
! 3517: if (mpqs_diffptr == diffptr) mpqs_diffptr = NULL;
! 3518: all_clean = 1;
! 3519: /* nuisance: fact may not be safe for a gcopy(), and thus
! 3520: gerepilecopy(av, fact) will usually segfault on
! 3521: one of the NULL markers. However, it is already a nice
! 3522: connected object, and it resides already the top of the
! 3523: stack, so... :^) --GN */
! 3524: return gerepileupto(av, fact);
! 3525: }
! 3526: else
! 3527: {
! 3528: if (DEBUGLEVEL >= 4)
! 3529: {
! 3530: fprintferr("\nMPQS: time in Gauss and gcds = %ld ms\n",
! 3531: timer2());
! 3532: fprintferr("MPQS: no factors found.\n");
! 3533: if (percentage <= max_percentage)
! 3534: fprintferr("\nMPQS: restarting sieving ...\n");
! 3535: else
! 3536: fprintferr("\nMPQS: giving up.\n");
! 3537: }
! 3538: if (percentage > max_percentage)
! 3539: {
! 3540: /* clean up */
! 3541: CLEANUP();
! 3542: pari_fclose(pLPNEW);
! 3543: pari_unlink(FREL_str);
! 3544: pari_unlink(FNEW_str);
! 3545: pari_unlink(LPREL_str);
! 3546: pari_unlink(LPNEW_str);
! 3547: if (mpqs_diffptr == diffptr) mpqs_diffptr = NULL;
! 3548: all_clean = 1;
! 3549: avma=av; return NULL;
! 3550: }
! 3551: pFNEW = pari_fopen(FNEW_str, WRITE); /* NOT safefopen */
! 3552: FNEW = pFNEW->file;
! 3553: }
! 3554: } /* main loop */
! 3555: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>