Revision 4c128d6c42aca5969a590ccac33d60147de0ffc5 authored by Paul Zimmermann on 09 December 2010, 15:02:37 UTC, committed by Paul Zimmermann on 09 December 2010, 15:02:37 UTC
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/cado-nfs/branches/1.0@615 3eaf19af-ecc0-40f6-b43f-672aa0c71c71
1 parent 76b8f2b
rootsieve.c
/* Rootsieve algorithm.
Copyright 2010 Paul Zimmermann (using notes from Emmanuel Thome)
This file is part of CADO-NFS.
CADO-NFS is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option)
any later version.
CADO-NFS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with CADO-NFS; see the file COPYING. If not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "cado.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h> /* for log */
#include "utils.h"
#include "modul_poly.h"
#include "auxiliary.h"
// #define KK -16346
// #define PP 7
/* if gpn and pn are not coprime, let g = gcd(gpn, pn):
we must have g*g'*v = r + j*g*p' with g' = gpn/g and p'=pn/g:
(a) if g does not divide r, there is no solution
(b) if g divides r, then we must have:
g'*v = r' + j*p' with r'=r/g, let v0 = r'/g' mod p',
then v0, v0+p', ..., v0+(g-1)*p' are the g solutions. */
static void
special_update (double *A, long K0, long K1, const residueul_t gpn,
modulusul_t Pn, residueul_t r, double alpha_p)
{
modulusul_t Pp;
residueul_t rp, gp;
int ret;
long k0, k;
modintul_t gg;
unsigned long g, rr, pp, pn;
pn = modul_getmod_ul (Pn);
modul_gcd (gg, gpn, Pn);
g = gg[0];
rr = modul_get_ul (r, Pn);
if (rr % g == 0)
{
pp = pn / g;
modul_initmod_ul (Pp, pp);
modul_init (gp, Pp);
modul_init (rp, Pp);
modul_set_ul (gp, modul_get_ul (gpn, Pn) / g, Pp);
modul_set_ul (rp, rr / g, Pp);
ret = modul_inv (gp, gp, Pp);
ASSERT_ALWAYS (ret != 0);
modul_mul (rp, rp, gp, Pp);
k0 = modul_get_ul (rp, Pp);
for (k = k0; k <= K1; k += pp)
{
A[k - K0] -= alpha_p;
#if (defined(KK) && defined(PP))
if (k == KK && (pn % PP) == 0)
fprintf (stderr, "subtract %f to AA[%d] for pp=%lu, now %f\n",
alpha_p, KK, pp, A[k - K0]);
#endif
}
for (k = k0 - pp; k >= K0; k -= pp)
{
A[k - K0] -= alpha_p;
#if (defined(KK) && defined(PP))
if (k == KK && (pn % PP) == 0)
fprintf (stderr, "subtract %f to AA[%d] for pp=%lu, now %f\n",
alpha_p, KK, pp, A[k - K0]);
#endif
}
modul_clear (gp, Pp);
modul_clear (rp, Pp);
modul_clearmod (Pp);
}
}
/* f(x) of degree d is the polynomial f0(x) + j*x*g(x)
where g(x) = b*x-m.
A is a table of K1-K0+1 entries, where A[k-K0] corresponds to the alpha
contribution for f(x) + k*g(x)
p is the current prime, we consider pn = p^n here */
void
update_table (mpz_t *f, int d, mpz_t m, mpz_t b, double *A, long K0, long K1,
unsigned long pn, double alpha_p)
{
long k, k0;
modul_poly_t fpn; /* f mod p^n */
modulusul_t Pn;
residueul_t l, gpn, bpn, r, v;
int ret;
modul_initmod_ul (Pn, pn);
modul_init (gpn, Pn);
modul_init (bpn, Pn);
modul_init (r, Pn);
modul_init (l, Pn);
modul_init (v, Pn);
modul_poly_init (fpn, d);
/* first reduce f(x) and g(x) mod p^n */
modul_poly_set_mod_raw (fpn, f, d, Pn);
modul_set_ul (gpn, mpz_fdiv_ui (m, pn), Pn);
/* invariant: gpn = -g(l) */
modul_set_ul (bpn, mpz_fdiv_ui (b, pn), Pn);
modul_set_ul (l, 0, Pn);
for (;;)
{
modul_poly_eval (r, fpn, l, Pn);
/* invariant: gpn = -g(l) */
/* we want r = v*gpn, i.e., v = r/gpn; r is never 0 otherwise f(x) would
be divisible by p^n, but gpn = g(l) can be 0 */
ret = modul_intcmp_ul (gpn, 0);
if (ret != 0)
{
ret = modul_inv (v, gpn, Pn); /* FIXME: use batch inversion */
if (ret == 0) /* gpn and pn are not coprime */
special_update (A, K0, K1, gpn, Pn, r, alpha_p);
else
{
modul_mul (v, v, r, Pn);
k0 = modul_get_ul (v, Pn);
for (k = k0; k <= K1; k += pn)
{
A[k - K0] -= alpha_p;
#if (defined(KK) && defined(PP))
if (k == KK && (pn % PP) == 0)
fprintf (stderr, "subtract %f to AA[%d] for l=%lu, pn=%lu, now %f\n",
alpha_p, KK, modul_get_ul (l, Pn), pn, A[k - K0]);
#endif
}
for (k = k0 - (long) pn; k >= K0; k -= (long) pn)
{
A[k - K0] -= alpha_p;
#if (defined(KK) && defined(PP))
if (k == KK && (pn % PP) == 0)
fprintf (stderr, "subtract %f to AA[%d] for l=%lu, pn=%lu, now %f\n",
alpha_p, KK, modul_get_ul (l, Pn), pn, A[k - K0]);
#endif
}
}
}
/* since g(x) = b*x-m, -g(l) = m-b*l */
modul_sub (gpn, gpn, bpn, Pn);
modul_add_ul (l, l, 1, Pn);
if (modul_intcmp_ul (l, 0) == 0)
break;
}
modul_clear (gpn, Pn);
modul_clear (bpn, Pn);
modul_clear (r, Pn);
modul_clear (l, Pn);
modul_clear (v, Pn);
modul_clearmod (Pn);
modul_poly_clear (fpn);
}
#define average_valuation_affine special_val0
/* Computes the contribution at p of the alpha value of f (projective part
only). The return value is always <= 0. */
double
alpha_p_projective (mpz_t *f, int d, mpz_t disc, unsigned long p)
{
double e;
int i;
if (mpz_divisible_ui_p (disc, p))
{
mpz_array_t *q;
mpz_t c;
/* compute q = reverse(f)(px): q[0] = f[d], q[1] = f[d-1]*p, ...,
q[d] = f[0]*p^d */
q = alloc_mpz_array (d + 1);
mpz_init_set_ui (c, 1);
for (i = 0; i <= d; i++)
{
mpz_mul ((q->data)[i], f[d-i], c);
mpz_mul_ui (c, c, p);
}
e = average_valuation_affine (q->data, d, p) / (double) (p + 1);
mpz_clear (c);
clear_mpz_array (q);
return -e * log ((double) p);
}
else
{
for (i = d; i >= 0 && mpz_divisible_ui_p (f[i], p); i--);
ASSERT_ALWAYS (i >= 0);
ASSERT_ALWAYS (d - i <= 1);
return - (double) (d - i) * (double) p / (double) (p + 1)
* log ((double) p) / (double) (p - 1);
}
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...