/* Copyright (C) 2015 Kushagra Singh 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 . */ /* This is an implementation of the pollard rho algorithm, with a more efficient cycle finding algorithm, as proposed by Richard Brent. Details can be found in the paper https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf, pseudocode is available on page 182 of the same paper */ #include #include "flint.h" #include "fmpz.h" #include "ulong_extras.h" #include "mpn_extras.h" int fmpz_factor_pollard_brent(fmpz_t p_factor, flint_rand_t state, fmpz_t n_in, mp_limb_t max_tries, mp_limb_t max_iters) { fmpz_t fa, fy, maxa, maxy; mp_ptr a, y, n, ninv, temp; mp_limb_t n_size, normbits, ans, val, size, cy; __mpz_struct *fac, *mpz_ptr; int ret; TMP_INIT; if (fmpz_is_even(n_in)) { fmpz_set_ui(p_factor, 2); return 1; } n_size = fmpz_size(n_in); if (n_size == 1) { val = fmpz_get_ui(n_in); ret = n_factor_pollard_brent(&ans, state, val, max_tries, max_iters); fmpz_set_ui(p_factor, ans); return ret; } fmpz_init2(fa, n_size); fmpz_init2(fy, n_size); fmpz_init2(maxa, n_size); fmpz_init2(maxy, n_size); fmpz_sub_ui(maxa, n_in, 3); /* 1 <= a <= n - 3 */ fmpz_sub_ui(maxy, n_in, 1); /* 1 <= y <= n - 1 */ TMP_START; a = TMP_ALLOC(n_size * sizeof(mp_limb_t)); y = TMP_ALLOC(n_size * sizeof(mp_limb_t)); n = TMP_ALLOC(n_size * sizeof(mp_limb_t)); ninv = TMP_ALLOC(n_size * sizeof(mp_limb_t)); /* copying n_in onto n, and normalizing */ temp = COEFF_TO_PTR(*n_in)->_mp_d; count_leading_zeros(normbits, temp[n_size - 1]); if (normbits) mpn_lshift(n, temp, n_size, normbits); else flint_mpn_copyi(n, temp, n_size); flint_mpn_preinvn(ninv, n, n_size); fac = _fmpz_promote(p_factor); mpz_realloc2(fac, n_size * FLINT_BITS); fac->_mp_size = n_size; while (max_tries--) { fmpz_randm(fa, state, maxa); fmpz_add_ui(fa, fa, 1); fmpz_randm(fy, state, maxy); fmpz_add_ui(fy, fy, 1); mpn_zero(a, n_size); mpn_zero(y, n_size); if (normbits) { if ((!COEFF_IS_MPZ(*fy))) { y[0] = fmpz_get_ui(fy); cy = mpn_lshift(y, y, 1, normbits); if (cy) y[1] = cy; } else { mpz_ptr = COEFF_TO_PTR(*fy); temp = mpz_ptr->_mp_d; size = mpz_ptr->_mp_size; cy = mpn_lshift(y, temp, size, normbits); if (cy) y[size] = cy; } if ((!COEFF_IS_MPZ(*fa))) { a[0] = fmpz_get_ui(fa); cy = mpn_lshift(a, a, 1, normbits); if (cy) a[1] = cy; } else { mpz_ptr = COEFF_TO_PTR(*fa); temp = mpz_ptr->_mp_d; size = mpz_ptr->_mp_size; cy = mpn_lshift(a, temp, size, normbits); if (cy) a[size] = cy; } } else { temp = COEFF_TO_PTR(*fy)->_mp_d; flint_mpn_copyi(y, temp, n_size); temp = COEFF_TO_PTR(*fa)->_mp_d; flint_mpn_copyi(a, temp, n_size); } ret = flint_mpn_factor_pollard_brent_single(fac->_mp_d, n, ninv, a, y, n_size, normbits, max_iters); if (ret) { fac->_mp_size = ret; /* ret is number of limbs of factor found */ _fmpz_demote_val(p_factor); break; } } fmpz_clear(fa); fmpz_clear(fy); fmpz_clear(maxa); fmpz_clear(maxy); TMP_END; return ret; }