/*============================================================================= This file is part of Antic. Antic is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . =============================================================================*/ /****************************************************************************** Copyright 2012 William Hart ******************************************************************************/ #include #include #include "profiler.h" #include "flint.h" #include "fmpz.h" #include "qfb.h" int main(void) { fmpz_t g, n, n0, p, L; slong iters, i, j, depth, jmax = 10; qfb_t pow, twopow; ulong pr, nmodpr, mult, n0mod4; qfb_hash_t * qhash; int done; fmpz_init(g); fmpz_init(n); fmpz_init(n0); fmpz_init(p); fmpz_init(L); qfb_init(pow); qfb_init(twopow); printf("Enter number to be factored: "); fflush(stdout); if (!fmpz_read(n0)) { printf("Read failed\n"); abort(); } fmpz_neg(n0, n0); iters = 10; /* find prime such that n is a square mod p (or p divides n) */ if (fmpz_is_even(n0)) { printf("Factor: 2\n"); return 0; } mult = 1; while (1) /* keep increasing iterations for each multiplier until done */ { printf("iters = %ld, multipliers = %ld\n", iters, jmax); for (j = 0; j < jmax; j++) /* loop over jmax different multipliers */ { done = 1; if (mult != 1 && fmpz_fdiv_ui(n0, mult) == 0) { printf("Factor: %ld\n", mult); return 0; } fmpz_mul_ui(n, n0, mult); if (fmpz_fdiv_ui(n, 4) == 3) fmpz_mul_2exp(n, n, 2); pr = 2; fmpz_abs(L, n); fmpz_root(L, L, 4); do { pr = n_nextprime(pr, 0); while (mult % pr == 0) pr = n_nextprime(pr, 0); nmodpr = fmpz_fdiv_ui(n, pr); if (nmodpr == 0) /* pr is a factor */ { printf("Factor: %lu\n", pr); return 0; } } while (n_jacobi(nmodpr, pr) < 0); fmpz_set_ui(p, pr); /* find prime form of discriminant n */ qfb_prime_form(pow, n, p); /* raise to various powers of small primes */ qfb_pow_ui(pow, pow, n, 59049); /* 3^10 */ qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) goto done; qfb_pow_ui(pow, pow, n, 390625); /* 5^8 */ qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) goto done; qfb_pow_ui(pow, pow, n, 117649); /* 7^6 */ qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) goto done; qfb_pow_ui(pow, pow, n, 14641); /* 11^4 */ qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) goto done; qfb_pow_ui(pow, pow, n, 169); /* 13^2 */ qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) goto done; depth = FLINT_BIT_COUNT(iters) + 1; qhash = qfb_hash_init(depth); pr = 13; for (i = 0; i < iters; i++) { pr = n_nextprime(pr, 0); qfb_pow_ui(pow, pow, n, pr*pr); qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) /* found factor */ break; qfb_hash_insert(qhash, twopow, pow, i, depth); } if (i == iters) /* stage 2 */ { ulong jump = iters*iters; slong iters2; for (i = 0; i < iters; i++) { qfb_pow_ui(pow, pow, n, jump); qfb_pow_ui(twopow, pow, n, 4096); if (qfb_is_principal_form(twopow, n)) /* found factor */ break; iters2 = qfb_hash_find(qhash, twopow, depth); if (iters2 != -1) /* found factor */ { if (fmpz_sgn(qhash[iters2].q->b) == fmpz_sgn(twopow->b)) qfb_inverse(qhash[iters2].q2, qhash[iters2].q2); qfb_nucomp(pow, pow, qhash[iters2].q2, n, L); qfb_reduce(pow, pow, n); break; } } if (i == iters) done = 0; } done: if (done) { for (i = 0; i < 12; i++) { qfb_pow_ui(twopow, pow, n, 2); if (qfb_is_principal_form(twopow, n)) { if (fmpz_cmpabs(pow->a, pow->b) != 0) { fmpz_abs(pow->b, pow->b); fmpz_sub(g, pow->b, pow->a); fmpz_sub(pow->a, g, pow->a); } fmpz_gcd(g, pow->a, n0); if (!fmpz_is_one(g)) /* Success! */ { printf("Factor: "); fmpz_print(g); printf("\n"); return 0; } done = 0; break; } qfb_set(pow, twopow); } } mult += 2; qfb_hash_clear(qhash, depth); } iters *= 2; jmax = (slong) (jmax * 1.15); mult = iters/10; mult |= 1; } qfb_clear(pow); qfb_clear(twopow); fmpz_clear(g); fmpz_clear(n); fmpz_clear(n0); fmpz_clear(p); fmpz_clear(L); return 0; }