/*
Copyright (C) 2010 Fredrik Johansson
This file is part of FLINT.
FLINT 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 .
*/
#include
#include "flint.h"
#include "fmpz.h"
#include "fmpz_vec.h"
#include "mpn_extras.h"
#include "ulong_extras.h"
static slong trial_cutoff[15] = {4, 4, 4, 6, 11, 18, 31, 54, 97, 172, 309, 564, 1028, 1900, 3512};
/*
Tuning values to give a roughly 1/3 chance of finding a factor of the given
number of bits. Parameters are {bits, B1, curves}. B2 should be taken to be
100*B1. Tuning values are a bit rough from 62 bits on.
*/
static slong ecm_tuning[][3] =
{
{0, 0, 0}, {2, 1, 1}, {4, 3, 1}, {6, 5, 1}, {8, 7, 1},
{10, 9, 2}, {12, 11, 2}, {14, 13, 2}, {16, 15, 2}, {18, 17, 2},
{20, 19, 5}, {22, 25, 8}, {24, 32, 10}, {26, 47, 11}, {28, 67, 13},
{30, 102, 13}, {32, 126, 13}, {34, 207, 15}, {36, 293, 16}, {38, 415, 17},
{40, 610, 18}, {42, 920, 18}, {44, 1270, 20}, {46, 1800, 20}, {48, 2650, 20},
{50, 3850, 21}, {52, 5300, 22}, {54, 8500, 22}, {56, 10000, 26}, {58, 12000, 33},
{60, 14000, 42}, {62, 15000, 57}, {64, 16500, 72}, {66, 18000, 87}, {68, 22000, 102},
{70, 26000, 117}, {72, 30000, 131}, {74, 40000, 146}, {76, 50000, 161}, {78, 60000, 175},
{80, 70000, 190}, {82, 80000, 205}, {84, 100000, 220}, {86, 140000, 240}, {88, 190000, 255},
{90, 240000, 291}, {92, 280000, 318}, {94, 320000, 345}, {96, 370000, 372}, {98, 420000, 400},
{100, 470000, 430}
};
int _is_prime(const fmpz_t n, int proved)
{
if (proved)
return fmpz_is_prime(n);
else
return fmpz_is_probabprime(n);
}
void remove_found_factors(fmpz_factor_t factor, fmpz_t n, fmpz_t f)
{
slong i;
fmpz_factor_t fac;
fmpz_tdiv_q(n, n, f);
fmpz_factor_init(fac);
fmpz_factor_no_trial(fac, f);
for (i = 0; i < fac->num; i++)
fac->exp[i] += fmpz_remove(n, n, fac->p + i);
_fmpz_factor_concat(factor, fac, 1);
fmpz_factor_clear(fac);
}
int fmpz_factor_smooth(fmpz_factor_t factor, const fmpz_t n,
slong bits, int proved)
{
ulong exp;
mp_limb_t p;
__mpz_struct * xsrc;
mp_ptr xd;
mp_size_t xsize;
slong found;
slong trial_stop;
slong * idx;
slong i, b, bits2, istride;
const mp_limb_t * primes;
int ret = 0;
TMP_INIT;
if (!COEFF_IS_MPZ(*n))
{
fmpz_factor_si(factor, *n);
return 1;
}
_fmpz_factor_set_length(factor, 0);
/* Get sign and size */
xsrc = COEFF_TO_PTR(*n);
if (xsrc->_mp_size < 0)
{
xsize = -(xsrc->_mp_size);
factor->sign = -1;
}
else
{
xsize = xsrc->_mp_size;
factor->sign = 1;
}
/* Just a single limb */
if (xsize == 1)
{
_fmpz_factor_extend_factor_ui(factor, xsrc->_mp_d[0]);
return 1;
}
/* Create a temporary copy to be mutated */
TMP_START;
xd = TMP_ALLOC(xsize * sizeof(mp_limb_t));
flint_mpn_copyi(xd, xsrc->_mp_d, xsize);
/* Factor out powers of two */
xsize = flint_mpn_remove_2exp(xd, xsize, &exp);
if (exp != 0)
_fmpz_factor_append_ui(factor, UWORD(2), exp);
if (bits <= 0)
{
flint_printf("(fmpz_factor_smooth) Number of bits must be at least 1\n");
flint_abort();
}
if (bits <= 15)
trial_stop = trial_cutoff[bits - 1];
else
trial_stop = 3512;
b = fmpz_sizeinbase(n, 2) - exp;
idx = (slong *) flint_malloc((5 + b/4)*sizeof(slong));
found = flint_mpn_factor_trial_tree(idx, xd, xsize, trial_stop);
if (found)
{
primes = n_primes_arr_readonly(trial_stop);
for (i = 0; i < found; i++)
{
p = primes[idx[i]];
exp = 1;
xsize = flint_mpn_divexact_1(xd, xsize, p);
/* Check if p^2 divides n */
if (flint_mpn_divisible_1_p(xd, xsize, p))
{
xsize = flint_mpn_divexact_1(xd, xsize, p);
exp = 2;
}
/* If we're up to cubes, then maybe there are higher powers */
if (exp == 2 && flint_mpn_divisible_1_p(xd, xsize, p))
{
xsize = flint_mpn_divexact_1(xd, xsize, p);
xsize = flint_mpn_remove_power_ascending(xd, xsize, &p, 1, &exp);
exp += 3;
}
_fmpz_factor_append_ui(factor, p, exp);
}
}
if (xsize == 1)
{
/* Any single-limb factor left? */
if (xd[0] != 1)
_fmpz_factor_extend_factor_ui(factor, xd[0]);
ret = 1;
}
else
{
fmpz_t n2, f;
__mpz_struct * data;
fmpz_init2(n2, xsize);
data = _fmpz_promote(n2);
flint_mpn_copyi(data->_mp_d, xd, xsize);
data->_mp_size = xsize;
if (proved != -1 && _is_prime(n2, proved))
{
_fmpz_factor_append(factor, n2, 1);
ret = 1;
}
else
{
fmpz_t root;
fmpz_init(root);
exp = fmpz_is_perfect_power(root, n2);
if (exp != 0)
{
fmpz_factor_t fac;
fmpz_factor_init(fac);
ret = fmpz_factor_smooth(fac, root, bits, proved);
fmpz_set_ui(n2, 1);
_fmpz_factor_concat(factor, fac, exp);
fmpz_factor_clear(fac);
}
else if (bits >= 16) /* trial factored already up to 15 bits */
{
int found;
flint_rand_t state;
fmpz_init(f);
flint_randinit(state);
/* currently only tuning values up to factors of 100 bits */
bits = FLINT_MIN(bits, 100);
bits2 = (bits + 1)/2;
/* tuning is in increments of 2 bits */
istride = 3;
/* start with 18-22 bits, advance by 6 bits at a time */
for (i = 9 + (bits2 % 3); i <= bits2; i += istride)
{
found = fmpz_factor_ecm(f, ecm_tuning[i][2],
ecm_tuning[i][1], ecm_tuning[i][1]*100, state, n2);
if (found != 0)
{
/* make sure all prime divisors in factor are removed from n2 */
remove_found_factors(factor, n2, f);
if (fmpz_is_one(n2))
{
ret = 1;
break;
}
/* if what remains is below the bound, just factor it */
if (fmpz_sizeinbase(n2, 2) < bits)
{
fmpz_factor_no_trial(factor, n2);
ret = 1;
break;
}
if (_is_prime(n2, proved))
{
_fmpz_factor_append(factor, n2, 1);
ret = 1;
break;
}
i -= istride; /* redo with the same parameters if factor found */
}
}
flint_randclear(state);
fmpz_clear(f);
}
}
if (ret != 1 && !fmpz_is_one(n2))
_fmpz_factor_append(factor, n2, 1); /* place cofactor in factor struct */
else
ret = 1;
fmpz_clear(n2);
}
flint_free(idx);
TMP_END;
return ret;
}