/*------------------------------------------------------------------*/ uint32 add_free_relations(msieve_obj *obj, factor_base_t *fb, uint8 *free_bits) { uint32 i, j; uint32 num_relations = 0; uint32 alg_degree = fb->afb.poly.degree; uint32 rat_degree = fb->rfb.poly.degree; uint32 free_bytes = (FREE_RELATION_LIMIT / 2 + 7) / 8; savefile_open(&obj->savefile, SAVEFILE_APPEND); for (i = 0; i < free_bytes; i++) { if (free_bits[i] == 0) continue; for (j = 0; j < 8; j++) { char buf[LINE_BUF_SIZE]; uint32 dummy_roots[MAX_POLY_DEGREE]; uint32 high_coeff; uint32 num_roots; uint32 p; if (!(free_bits[i] & (1 << j))) continue; /* bit 8*i+j could be a new free relation */ p = 2 * (8 * i + j) + 1; num_roots = poly_get_zeros(dummy_roots, &fb->afb.poly, p, &high_coeff, 1); if (num_roots == alg_degree && high_coeff != 0) { num_roots = poly_get_zeros(dummy_roots, &fb->rfb.poly, p, &high_coeff, 1); if (num_roots == rat_degree && high_coeff != 0) { sprintf(buf, "%u,0:\n", p); savefile_write_line(&obj->savefile, buf); num_relations++; } } } } if (num_relations) logprintf(obj, "added %u free relations\n", num_relations); savefile_flush(&obj->savefile); savefile_close(&obj->savefile); return num_relations; }
// SGL : セーブイメージを読み込む (T.Yui) int isfcmd_6f(SCR_OPE *op) { SINT32 savenum; SINT32 num; POINT_T pt; VRAMHDL dst; SAVEHDL sh; _SAVEINF inf; BOOL r; if ((scr_getval(op, &savenum) != SUCCESS) || (scr_getval(op, &num) != SUCCESS) || (scr_getpt(op, &pt) != SUCCESS)) { return(GAMEEV_WRONGLENG); } if ((num < 0) || (num >= GAMECORE_MAXVRAM)) { goto cmd6f_exit; } dst = gamecore.vram[num]; if (dst == NULL) { goto cmd6f_exit; } sh = savefile_open(FALSE); r = sh->readinf(sh, savenum, &inf, -1, -1); sh->close(sh); if (r == SUCCESS) { #ifdef SIZE_QVGA vramdraw_halfpoint(&pt); #endif vramcpy_cpy(dst, (VRAMHDL)inf.preview, &pt, NULL); vram_destroy((VRAMHDL)inf.preview); } cmd6f_exit: return(GAMEEV_SUCCESS); }
/*------------------------------------------------------------------*/ static uint32 nfs_init_savefile(msieve_obj *obj, mp_t *n) { char buf[LINE_BUF_SIZE]; uint32 relations_found = 0; savefile_t *savefile = &obj->savefile; uint32 update = 1; /* open the savefile; if the file already exists and the first line contains n, then we are restarting from a previous factorization */ if (savefile_exists(savefile)) { savefile_open(savefile, SAVEFILE_READ); buf[0] = 0; savefile_read_line(buf, sizeof(buf), savefile); if (buf[0] == 'N') { mp_t read_n; mp_str2mp(buf + 2, &read_n, 10); if (mp_cmp(n, &read_n) == 0) update = 0; } savefile_close(savefile); } if (update && (obj->flags & MSIEVE_FLAG_NFS_SIEVE)) { /* If sieving is about to add new relations, truncate the file and write the present n. I hope you backed up savefiles you wanted! */ savefile_open(savefile, SAVEFILE_WRITE); sprintf(buf, "N %s\n", mp_sprintf(n, 10, obj->mp_sprintf_buf)); savefile_write_line(savefile, buf); savefile_flush(savefile); savefile_close(savefile); } else { /* we don't care how many relations are present, so don't waste time counting them */ return 0; } /* count the number of relations in the savefile; do not verify any of them */ savefile_open(savefile, SAVEFILE_READ); while (!savefile_eof(savefile)) { /* count relations; No checking of relations happens here */ savefile_read_line(buf, sizeof(buf), savefile); while (!savefile_eof(savefile)) { if (isdigit(buf[0]) || buf[0] == '-') relations_found++; savefile_read_line(buf, sizeof(buf), savefile); } if (relations_found) logprintf(obj, "restarting with %u relations\n", relations_found); } savefile_close(savefile); return relations_found; }
/*--------------------------------------------------------------------*/ uint32 factor_gnfs(msieve_obj *obj, mp_t *n, factor_list_t *factor_list) { int32 status; uint32 bits; sieve_param_t params; mp_poly_t rat_poly; mp_poly_t alg_poly; uint32 relations_found = 0; uint32 max_relations = 0; uint32 factor_found = 0; /* Calculate the factor base bound */ bits = mp_bits(n); get_sieve_params(bits, ¶ms); logprintf(obj, "commencing number field sieve (%d-digit input)\n", strlen(mp_sprintf(n, 10, obj->mp_sprintf_buf))); /* generate or read in the NFS polynomials */ memset(&rat_poly, 0, sizeof(rat_poly)); memset(&alg_poly, 0, sizeof(alg_poly)); status = read_poly(obj, n, &rat_poly, &alg_poly, ¶ms.skewness); if (status != 0 && (obj->flags & (MSIEVE_FLAG_NFS_POLY1 | MSIEVE_FLAG_NFS_POLY2))) { status = find_poly(obj, n); status = read_poly(obj, n, &rat_poly, &alg_poly, ¶ms.skewness); } if (status != 0) { printf("error generating or reading NFS polynomials\n"); return 0; } analyze_one_poly(obj, &rat_poly, &alg_poly, params.skewness); if ((obj->flags & MSIEVE_FLAG_STOP_SIEVING) || !(obj->flags & (MSIEVE_FLAG_NFS_SIEVE | MSIEVE_FLAG_NFS_FILTER | MSIEVE_FLAG_NFS_LA | MSIEVE_FLAG_NFS_SQRT))) { return 0; } /* if we're supposed to be sieving, initialize the savefile */ if (obj->flags & (MSIEVE_FLAG_NFS_SIEVE | MSIEVE_FLAG_NFS_FILTER)) { /* figure out how many relations to look for, and quit early if that many have already been found */ relations_found = nfs_init_savefile(obj, n); if (obj->max_relations > 0) { max_relations = relations_found + obj->max_relations; } else { /* if no guidance on this is available, make a wild guess: a fixed fraction of the total number of large primes possible */ max_relations = 0.8 * (params.rfb_lp_size / (log((double)params.rfb_lp_size) - 1) + params.afb_lp_size / (log((double)params.afb_lp_size) - 1)); } } /* this is a little tricky: perform only sieving (and quit when enough relations are found), only filtering (and quit if it fails, or continue the postprocessing if it succeeds), or alternate between sieving and filtering until the filtering succeeds */ while (1) { if (!(obj->flags & (MSIEVE_FLAG_NFS_SIEVE | MSIEVE_FLAG_NFS_FILTER))) { break; } if (obj->flags & MSIEVE_FLAG_NFS_SIEVE) { savefile_open(&obj->savefile, SAVEFILE_APPEND); relations_found = do_line_sieving(obj, ¶ms, n, relations_found, max_relations); savefile_close(&obj->savefile); if (relations_found == 0) break; if (!(obj->flags & MSIEVE_FLAG_NFS_FILTER)) return 0; } if (obj->flags & MSIEVE_FLAG_STOP_SIEVING) return 0; if (obj->flags & MSIEVE_FLAG_NFS_FILTER) { max_relations = nfs_filter_relations(obj, n); if (max_relations == 0) break; logprintf(obj, "filtering wants %u more relations\n", max_relations); if (!(obj->flags & MSIEVE_FLAG_NFS_SIEVE)) return 0; max_relations += relations_found; } } if (obj->flags & MSIEVE_FLAG_NFS_LA) nfs_solve_linear_system(obj, n); if (obj->flags & MSIEVE_FLAG_NFS_SQRT) factor_found = nfs_find_factors(obj, n, factor_list); return factor_found; }
void qs_filter_relations(sieve_conf_t *conf) { /* Perform all of the postprocessing on the list of relations from the sieving phase. There are two main jobs, reading in all the relations that will be used and then determining the list of cycles in which partial relations appear. Care should be taken to avoid wasting huge amounts of memory */ msieve_obj *obj = conf->obj; uint32 *hashtable = conf->cycle_hashtable; cycle_t *table = conf->cycle_table; uint32 num_poly_factors = conf->num_poly_factors; uint32 num_derived_poly = 1 << (num_poly_factors - 1); uint32 *final_poly_index; uint32 num_relations, num_cycles, num_poly; la_col_t *cycle_list; relation_t *relation_list; uint32 i, passes, start; uint32 curr_a_idx, curr_poly_idx, curr_rel; uint32 curr_expected, curr_saved, curr_cycle; uint32 total_poly_a; uint32 poly_saved; uint32 cycle_bins[NUM_CYCLE_BINS+1] = {0}; char buf[LINE_BUF_SIZE]; /* Rather than reading all the relations in and then removing singletons, read only the large primes of each relation into an initial list, remove the singletons, and then only read in the relations that survive. This avoids reading in useless relations (and usually the polynomials they would need) */ savefile_open(&obj->savefile, SAVEFILE_READ); relation_list = (relation_t *)xmalloc(10000 * sizeof(relation_t)); curr_rel = 10000; i = 0; total_poly_a = 0; /* skip over the first line */ savefile_read_line(buf, sizeof(buf), &obj->savefile); while (!savefile_eof(&obj->savefile)) { char *start; switch (buf[0]) { case 'A': total_poly_a++; break; case 'R': start = strchr(buf, 'L'); if (start != NULL) { uint32 prime1, prime2; read_large_primes(start, &prime1, &prime2); if (i == curr_rel) { curr_rel = 3 * curr_rel / 2; relation_list = (relation_t *)xrealloc( relation_list, curr_rel * sizeof(relation_t)); } relation_list[i].poly_idx = i; relation_list[i].large_prime[0] = prime1; relation_list[i].large_prime[1] = prime2; i++; } break; } savefile_read_line(buf, sizeof(buf), &obj->savefile); } num_relations = i; num_relations = purge_singletons(obj, relation_list, num_relations, table, hashtable); relation_list = (relation_t *)xrealloc(relation_list, num_relations * sizeof(relation_t)); /* Now we know how many relations to expect. Also initialize the lists of polynomial 'a' and 'b' values */ num_poly = 10000; conf->poly_list = (poly_t *)xmalloc(num_poly * sizeof(poly_t)); conf->poly_a_list = (mp_t *)xmalloc(total_poly_a * sizeof(mp_t)); final_poly_index = (uint32 *)xmalloc(num_derived_poly * sizeof(uint32)); /* initialize the running counts of relations and polynomials */ i = 0; curr_expected = 0; curr_saved = 0; curr_rel = (uint32)(-1); curr_poly_idx = (uint32)(-1); curr_a_idx = (uint32)(-1); poly_saved = 0; logprintf(obj, "attempting to read %u relations\n", num_relations); /* Read in the relations and the polynomials they use at the same time. */ savefile_rewind(&obj->savefile); while (curr_expected < num_relations) { char *tmp; relation_t *r; /* read in the next entity */ if (savefile_eof(&obj->savefile)) break; savefile_read_line(buf, sizeof(buf), &obj->savefile); switch (buf[0]) { case 'A': /* Read in a new 'a' value */ curr_a_idx++; read_poly_a(conf, buf); mp_copy(&conf->curr_a, conf->poly_a_list+curr_a_idx); /* build all of the 'b' values associated with it */ build_derived_poly(conf); /* all 'b' values start off unused */ memset(final_poly_index, -1, num_derived_poly * sizeof(uint32)); break; case 'R': /* handle a new relation. First find the large primes; these will determine if a relation is full or partial */ tmp = strchr(buf, 'L'); if (tmp == NULL) break; /* Check if this relation is needed. If it survived singleton removal then its ordinal ID will be in the next entry of relation_list. First move up the index of relation_list until the relation index to check is >= the one we have (it may have gotten behind because relations were corrupted) */ curr_rel++; while (curr_expected < num_relations && relation_list[curr_expected].poly_idx < curr_rel) { curr_expected++; } /* now check if the relation should be saved */ if (curr_expected >= num_relations || relation_list[curr_expected].poly_idx != curr_rel) break; curr_expected++; /* convert the ASCII text of the relation to a relation_t, verifying correctness in the process */ r = relation_list + curr_saved; if (read_relation(conf, buf, r) != 0) { logprintf(obj, "failed to read relation %d\n", curr_expected - 1); break; } curr_saved++; /* if necessary, save the b value corresponding to this relation */ if (final_poly_index[r->poly_idx] == (uint32)(-1)) { if (i == num_poly) { num_poly *= 2; conf->poly_list = (poly_t *)xrealloc( conf->poly_list, num_poly * sizeof(poly_t)); } conf->poly_list[i].a_idx = curr_a_idx; signed_mp_copy(&(conf->curr_b[r->poly_idx]), &(conf->poly_list[i].b)); final_poly_index[r->poly_idx] = i; r->poly_idx = i++; } else { r->poly_idx = final_poly_index[r->poly_idx]; } break; /* done with this relation */ } } /* update the structures with the counts of relations and polynomials actually recovered */ num_relations = curr_saved; logprintf(obj, "recovered %u relations\n", num_relations); logprintf(obj, "recovered %u polynomials\n", i); savefile_close(&obj->savefile); free(final_poly_index); conf->poly_list = (poly_t *)xrealloc(conf->poly_list, i * sizeof(poly_t)); /* begin the cycle generation process by purging duplicate relations. For the sake of consistency, always rebuild the graph afterwards */ num_relations = purge_duplicate_relations(obj, relation_list, num_relations); memset(hashtable, 0, sizeof(uint32) << LOG2_CYCLE_HASH); conf->vertices = 0; conf->components = 0; conf->cycle_table_size = 1; for (i = 0; i < num_relations; i++) { relation_t *r = relation_list + i; if (r->large_prime[0] != r->large_prime[1]) { add_to_cycles(conf, r->large_prime[0], r->large_prime[1]); } } /* compute the number of cycles to expect. Note that this number includes cycles from both full and partial relations (the cycle for a full relation is trivial) */ num_cycles = num_relations + conf->components - conf->vertices; /* The idea behind the cycle-finding code is this: the graph is composed of a bunch of connected components, and each component contains one or more cycles. To find the cycles, you build the 'spanning tree' for each component. Think of the spanning tree as a binary tree; there are no cycles in it because leaves are only connected to a common root and not to each other. Any time you connect together two leaves of the tree, though, a cycle is formed. So, for a spanning tree like this: 1 o / \ 2 o o 3 / \ \ o o o 4 5 6 if you connect leaves 4 and 5 you get a cycle (4-2-5). If you connect leaves 4 and 6 you get another cycle (4-2-1-3-6) that will reuse two of the nodes in the first cycle. It's this reuse that makes double large primes so powerful. For our purposes, every edge in the tree above represents a partial relation. Every edge that would create a cycle comes from another partial relation. So to find all the cycles, you begin with the roots of all of the connected components, and then iterate through the list of partial relations until all have been 'processed'. A partial relation is considered processed when one or both of its primes is in the tree. If one prime is present then the relation gets added to the tree; if both primes are present then the relation creates one cycle but is *not* added to the tree. It's really great to see such simple ideas do something so complicated as finding cycles (and doing it very quickly) */ /* First traverse the entire graph and remove any vertices that are not the roots of connected components (i.e. remove any primes whose cycle_t entry does not point to itself */ for (i = 0; i < (1 << LOG2_CYCLE_HASH); i++) { uint32 offset = hashtable[i]; while (offset != 0) { cycle_t *entry = table + offset; if (offset != entry->data) entry->data = 0; offset = entry->next; } } logprintf(obj, "attempting to build %u cycles\n", num_cycles); cycle_list = (la_col_t *)xmalloc(num_cycles * sizeof(la_col_t)); /* keep going until either all cycles are found, all relations are processed, or cycles stop arriving. Normally these conditions all occur at the same time */ for (start = passes = curr_cycle = 0; start < num_relations && curr_cycle < num_cycles; passes++) { /* The list of relations up to index 'start' is con- sidered processed. For all relations past that... */ uint32 start_cycles = curr_cycle; for (i = start; i < num_relations && curr_cycle < num_cycles; i++) { cycle_t *entry1, *entry2; relation_t rtmp = relation_list[i]; if (rtmp.large_prime[0] == rtmp.large_prime[1]) { /* this is a full relation, and forms a cycle just by itself. Move it to position 'start' of the relation list and increment 'start'. The relation is now frozen at that position */ la_col_t *c = cycle_list + curr_cycle++; relation_list[i] = relation_list[start]; relation_list[start] = rtmp; /* build a trivial cycle for the relation */ c->cycle.num_relations = 1; c->cycle.list = (uint32 *) xmalloc(sizeof(uint32)); c->cycle.list[0] = start++; continue; } /* retrieve the cycle_t entries associated with the large primes in relation r. */ entry1 = get_table_entry(table, hashtable, rtmp.large_prime[0], 0); entry2 = get_table_entry(table, hashtable, rtmp.large_prime[1], 0); /* if both vertices do not point to other vertices, then neither prime has been added to the graph yet, and r must remain unprocessed */ if (entry1->data == 0 && entry2->data == 0) continue; /* if one or the other prime is part of the graph, add r to the graph. The vertex not in the graph points to the vertex that is, and this entry also points to the relation that is associated with rtmp. If both primes are in the graph, recover the cycle this generates */ if (entry1->data == 0) { entry1->data = entry2 - table; entry1->count = start; } else if (entry2->data == 0) { entry2->data = entry1 - table; entry2->count = start; } else { la_col_t *c = cycle_list + curr_cycle; c->cycle.list = NULL; enumerate_cycle(obj, c, table, entry1, entry2, start); if (c->cycle.list) curr_cycle++; } /* whatever happened above, the relation is processed now; move it to position 'start' of the relation list and increment 'start'. The relation is now frozen at that position */ relation_list[i] = relation_list[start]; relation_list[start++] = rtmp; } /* If this pass did not find any new cycles, then we've reached steady state and are finished */ if (curr_cycle == start_cycles) break; } num_cycles = curr_cycle; logprintf(obj, "found %u cycles in %u passes\n", num_cycles, passes); /* sort the list of cycles so that the cycles with the largest number of relations will come last. If the linear algebra code skips any cycles it can easily skip the most dense cycles */ qsort(cycle_list, (size_t)num_cycles, sizeof(la_col_t), sort_cycles); conf->relation_list = relation_list; conf->num_relations = num_relations; conf->cycle_list = cycle_list; conf->num_cycles = num_cycles; /* print out a histogram of cycle lengths for infor- mational purposes */ for (i = 0; i < num_cycles; i++) { num_relations = cycle_list[i].cycle.num_relations; if (num_relations >= NUM_CYCLE_BINS) cycle_bins[NUM_CYCLE_BINS]++; else cycle_bins[num_relations - 1]++; } logprintf(obj, "distribution of cycle lengths:\n"); for (i = 0; i < NUM_CYCLE_BINS; i++) { if (cycle_bins[i]) { logprintf(obj, " length %d : %d\n", i + 1, cycle_bins[i]); } } if (cycle_bins[i]) logprintf(obj, " length %u+: %u\n", i + 1, cycle_bins[i]); logprintf(obj, "largest cycle: %u relations\n", cycle_list[num_cycles-1].cycle.num_relations); }